Tokenisering och NLP-grunder: BPE, SentencePiece och WordPiece
Tokenisering är processen att dela upp text i underenheter (tokens) som kan bearbetas av en modell. Denna process, som utgör grunden för moderna LLM:er, påverkar modellens prestanda direkt.
Vad är tokenisering?
Tokenisering är det första steget i att omvandla råtext till numeriska representationer:
"Hello world!" → ["Hello", "world", "!"] → [1234, 5678, 99]
Tokeniseringsnivåer
- Teckennivå: Varje tecken är en token.
- Ordnivå: Varje ord är en token.
- Delordsnivå: Ord delas upp i mindre underenheter (det moderna tillvägagångssättet).
Tokenisering på ordnivå
Enkel metod
1def word_tokenize(text): 2 return text.split() 3 4# Example 5text = "Artificial intelligence is shaping the future" 6tokens = word_tokenize(text) 7# ['Artificial', 'intelligence', 'is', 'shaping', 'the', 'future']
Problem
- OOV (Out of Vocabulary): Att stöta på ord som inte förekom under träningen.
- Stor vokabulär: Att hantera hundratusentals ord är ineffektivt.
- Morfologisk rikedom: I språk som Turkish är antalet ordvariationer på grund av suffix enormt.
- Sammansatta ord: Svårt att avgöra om "Artificial intelligence" ska ses som ett eller två begrepp.
Tokenisering på teckennivå
1def char_tokenize(text): 2 return list(text) 3 4# Example 5text = "Hello" 6tokens = char_tokenize(text) 7# ['H', 'e', 'l', 'l', 'o']
Fördelar
- Inget OOV-problem.
- Liten vokabulärstorlek (~100 tecken).
Nackdelar
- Resulterande sekvenser blir mycket långa.
- Förlust av kontextuell betydelse på token-nivå.
- Högre beräkningskostnad för modellen.
Subword-tokenisering
Det moderna LLM-valet: en balans mellan ord- och teckennivå.
"tokenization" → ["token", "ization"] "unhappiness" → ["un", "happiness"] eller ["un", "happy", "ness"]
BPE (Byte Pair Encoding)
Den mest använda subword-tokeniseringsalgoritmen.
BPE-algoritm
- Dela text i individuella tecken.
- Hitta det mest frekventa paret av intilliggande tecken.
- Slå samman detta par till en ny enskild token.
- Upprepa processen tills önskad vokabulärstorlek uppnåtts.
BPE-exempel
1Starting vocabulary: ['l', 'o', 'w', 'e', 'r', 'n', 's', 't', 'i', 'd'] 2Corpus: "low lower newest lowest widest" 3 4Step 1: Most frequent pair 'e' + 's' → 'es' 5Step 2: Most frequent pair 'es' + 't' → 'est' 6Step 3: Most frequent pair 'l' + 'o' → 'lo' 7Step 4: Most frequent pair 'lo' + 'w' → 'low' 8... 9 10Final Result: ['low', 'est', 'er', 'new', 'wid', ...]
BPE-implementation
1def get_stats(vocab): 2 pairs = {} 3 for word, freq in vocab.items(): 4 symbols = word.split() 5 for i in range(len(symbols) - 1): 6 pair = (symbols[i], symbols[i + 1]) 7 pairs[pair] = pairs.get(pair, 0) + freq 8 return pairs 9 10def merge_vocab(pair, vocab): 11 new_vocab = {} 12 bigram = ' '.join(pair) 13 replacement = ''.join(pair) 14 for word in vocab: 15 new_word = word.replace(bigram, replacement) 16 new_vocab[new_word] = vocab[word] 17 return new_vocab 18 19def train_bpe(corpus, num_merges): 20 vocab = get_initial_vocab(corpus) 21 22 for i in range(num_merges): 23 pairs = get_stats(vocab) 24 if not pairs: 25 break 26 best_pair = max(pairs, key=pairs.get) 27 vocab = merge_vocab(best_pair, vocab) 28 29 return vocab
WordPiece
En algoritm utvecklad av Google och använd i modeller som BERT.
BPE vs WordPiece
| Feature | BPE | WordPiece |
|---|---|---|
| Merge Criterion | Frequency | Likelihood |
| Prefix | None | ## (for mid-word tokens) |
| Used In | GPT, LLaMA | BERT, DistilBERT |
WordPiece-exempel
1"tokenization" → ["token", "##ization"] 2"playing" → ["play", "##ing"] 3## SentencePiece 4 5En språkagnostisk tokenizer som också utvecklats av Google. 6 7### Features 8 9- **Språkoberoende:** Antar inte att blanksteg är ordavgränsare. 10- **Byte-nivå:** Arbetar direkt på råtext. 11- **BPE + Unigram:** Stöder flera algoritmer. 12- **Reversibel:** Perfekt detokenisering är möjlig. 13 14### SentencePiece Usage 15 16```python 17import sentencepiece as spm 18 19# Training the model 20spm.SentencePieceTrainer.train( 21 input='corpus.txt', 22 model_prefix='tokenizer', 23 vocab_size=32000, 24 model_type='bpe' # or 'unigram' 25) 26 27# Loading and using the model 28sp = spm.SentencePieceProcessor() 29sp.load('tokenizer.model') 30 31# Encode 32tokens = sp.encode('Hello world', out_type=str) 33# ['▁Hello', '▁world'] 34 35ids = sp.encode('Hello world', out_type=int) 36# [1234, 5678, 9012] 37 38# Decode 39text = sp.decode(ids) 40# 'Hello world'
▁ (Underscore) Symbol
SentencePiece markerar början av ord med ▁:
"Hello world" → ["▁Hello", "▁world"] "New York" → ["▁New", "▁York"]
Tiktoken (OpenAI)
Den specialiserade BPE-implementation som används av OpenAI.
1import tiktoken 2 3# Loading the encoder 4enc = tiktoken.encoding_for_model("gpt-4") 5 6# Encode 7tokens = enc.encode("Hello world!") 8# [12345, 67890, 999] 9 10# Decode 11text = enc.decode(tokens) 12# "Hello world!" 13 14# Check token count 15print(len(tokens)) # 3
Model-Encoder Mappings
| Model | Encoder | Vocab Size |
|---|---|---|
| GPT-4 | cl100k_base | 100,277 |
| GPT-3.5 | cl100k_base | 100,277 |
| GPT-3 | p50k_base | 50,281 |
| Codex | p50k_edit | 50,281 |
Hugging Face Tokenizers
1from transformers import AutoTokenizer 2 3# Loading the tokenizer 4tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased") 5 6# Encode 7encoded = tokenizer("Hello, world!", return_tensors="pt") 8# { 9# 'input_ids': tensor([[101, 7592, 1010, 2088, 999, 102]]), 10# 'attention_mask': tensor([[1, 1, 1, 1, 1, 1]]) 11# } 12 13# Decode 14text = tokenizer.decode(encoded['input_ids'][0]) 15# "[CLS] hello, world! [SEP]" 16 17# Token List 18tokens = tokenizer.tokenize("Hello, world!") 19# ['hello', ',', 'world', '!']
Fast Tokenizers
1from tokenizers import Tokenizer, models, trainers, pre_tokenizers 2 3# Creating a new tokenizer 4tokenizer = Tokenizer(models.BPE()) 5tokenizer.pre_tokenizer = pre_tokenizers.Whitespace() 6 7trainer = trainers.BpeTrainer( 8 vocab_size=30000, 9 special_tokens=["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"] 10) 11 12tokenizer.train(files=["corpus.txt"], trainer=trainer) 13tokenizer.save("my_tokenizer.json")
Special Tokens
Common Special Tokens
| Token | Description | Use Case |
|---|---|---|
| [CLS] | Start of sequence | BERT-klassificeringsuppgifter |
| [SEP] | Segment separator | Separera meningpar |
| [PAD] | Padding | Justering vid batch-bearbetning |
| [UNK] | Unknown token | Hantering av ord utanför ordförrådet |
| [MASK] | Mask | Masked Language Modeling (MLM) |
| <|endoftext|> | End of sequence | GPT-generativa uppgifter |
Chat Tokens
1<|system|>You are a helpful assistant<|end|> 2<|user|>Hello!<|end|> 3<|assistant|>Hello! How can I help you today?<|end|>
Tokenization Challenges in Turkish
Morphological Richness
1"gelebileceklermiş" (they were said to be able to come) → A single word but complex structure 2gel (come) + ebil (can) + ecek (will) + ler (they) + miş (reportedly) 3 4Tokenization: 5- Poor: ["gelebileceklermiş"] (Single token, very rare) 6- Good: ["gel", "ebil", "ecek", "ler", "miş"]
Solutions
- Turkish-optimized tokenizer training.
- Integration of morphological analysis.
- Suffix-aware BPE application.
Tokenbegränsningar och hantering
Kontextfönster
| Modell | Kontextlängd (Token) | ~Antal ord |
|---|---|---|
| GPT-3.5 | 16K | ~12 000 |
| GPT-4 | 128K | ~96 000 |
| Claude 3 | 200K | ~150 000 |
Tokenberäkning
1def estimate_tokens(text): 2 # Rough estimate: 1 token ≈ 4 characters (English) 3 # For Turkish: 1 token ≈ 3 characters 4 return len(text) // 3 5 6# More accurate calculation 7def count_tokens(text, model="gpt-4"): 8 enc = tiktoken.encoding_for_model(model) 9 return len(enc.encode(text))
Slutsats
Tokenisering är den grundläggande byggstenen för NLP och LLMs. Subword‑metoder som BPE, WordPiece och SentencePiece spelar en avgörande roll för moderna språkmodellers framgång. Att välja och konfigurera rätt tokeniserare påverkar modellens slutliga prestanda direkt.
På Veni AI tillhandahåller vi tokeniseringsstrategier specialiserade för turkiska NLP‑lösningar.
