Byte-Pair Encoding (BPE)
What Problem Does BPE Solve?
Three tokenization approaches and their problems:
- Word-level: Vocabulary explodes (millions of words), can't handle typos/"unknownwords" →
<UNK>tokens everywhere - Character-level: Small vocab (26-100 chars), but sequences become VERY long, model must learn spelling from scratch
- BPE (subword-level): Fixed vocab size (10k-50k), handles rare words by decomposition, captures morphology
The 80/20: BPE gets you 80% of word-level efficiency with 20% of the vocabulary size, plus zero <UNK> tokens.

The BPE Algorithm: From First Principles
Why This Design?
- Greedy frequency-based merging: Optimizes for compression (store common patterns once)
- Bottom-up construction: Starts from characters (handles any input) and builds up (captures frequent patterns)
- Deterministic: Same corpus + same → same vocabulary (reproducible)
BPE Training: Worked Example
Let's train BPE on a tiny corpus with target vocab size = 11. To make counting easy, assume the corpus has these word frequencies: low (×5), lower (×2), newest (×6), widest (×3).
Corpus (with counts): 5× "low" 2× "lower" 6× "newest" 3× "widest"
Step 0: Initialize with Characters
Split each word into characters with a word boundary </w>:
5×: l o w </w>
2×: l o w e r </w>
6×: n e w e s t </w>
3×: w i d e s t </w>
Base vocabulary → size = 11
Frequencies of pairs (multiply pair occurrences by word count):
(l, o): appears inlow(×5) +lower(×2) = 7(o, w):low(×5) +lower(×2) = 7(w, </w>):low(×5) = 5(w, e):lower(×2) +newest(×6) = 8 ← highest(e, s):newest(×6) +widest(×3) = 9 ← actually highest(s, t):newest(×6) +widest(×3) = 9(e, r):lower(×2) = 2
Step 1: Merge Most Frequent Pair
Top pairs tie at 9: (e, s) and (s, t). Break tie alphabetically → merge (e, s).
New token: es
Updated corpus:
5×: l o w </w>
2×: l o w e r </w>
6×: n e w es t </w>
3×: w i d es t </w>
→ size = 12
Why this step? es is shared by newest and widest (9 times) → maximum compression this round.
Step 2: Next Merge
Recount pairs:
(es, t):newest(×6) +widest(×3) = 9 ← most frequent(w, e):lower(×2) +newest(×6) = 8(l, o): 7,(o, w): 7
Merge (es, t) → new token est
Updated corpus:
5×: l o w </w>
2×: l o w e r </w>
6×: n e w est </w>
3×: w i d est </w>
→ size = 13
Continue Until Target Vocab Size...
The algorithm would continue, next merging (w, e) (=8), then (l, o) (=7), then (lo, w), eventually forming subwords like low, est</w>, newest</w>, etc.
Final learned merges (the "BPE merge rules", in order):
1. e s → es
2. es t → est
3. w e → we
4. l o → lo
5. lo w → low
...
Encoding Example: "lowest"
Merge rules learned (simplified, in order):
e s → eses t → estl o → lolo w → low
Step-by-step (apply rules by priority, lowest index first):
Input: l o w e s t </w>
Apply rule 1 (e s→es): l o w es t </w>
Apply rule 2 (es t→est): l o w est </w>
Apply rule 3 (l o→lo): lo w est </w>
Apply rule 4 (lo w→low): low est </w>
Output tokens: [low, est, </w>]
Why this encoding? "low" and "est" are frequent subwords. The model will see "est" in "lowest", "newest", "widest" → learns comparative/superlative morphology.
Why BPE Works: The Math
Why this formula? Each merge replaces 2 adjacent symbols with 1 wherever the pair occurs, growing the average token length . So the sequence length shrinks roughly linearly with : . Crucially, grows with the number of merges but with diminishing returns — the first merges (very frequent pairs) shorten sequences a lot, later merges (rare pairs) barely help. This is empirical, not a clean logarithmic law in .
Diminishing returns: Going from 10k → 50k vocab increases only slightly, so the extra sequence-length reduction is small compared to 1k → 10k.
Recall Explain BPE to a 12-Year-Old
Imagine you're creating a secret code for your friend group's messages. You could:
-
Use whole words: "pizza" = one code. But you'd need MILLIONS of codes for every possible word, and when someone invents a new slang word, you're stuck!
-
Use letters: "p" "i" "z" "z" "a" = 5 codes. Only 26 codes total (letters), but now every message is super long!
-
BPE approach: Start with letters. Notice you type "th" together ALL THE TIME? Make "th" its own code. Notice "the"? Make that one code. Keep combining the patterns you use most until you have exactly 10,000 codes. Now "the" is 1 code, "pizza" might be "pizz" + "a" (2 codes), and when your friend texts "supercalifragilistic", you break it into parts you've seen before: "super" + "cal" + "i" + "frag" + "il" + "istic".
The magic: Your 10,000 codes can handle INFINITE words by mixing and matching pieces. Common words = fewer pieces (fast). Rare words = more pieces (still works).
Modern BPE Variants
WordPiece (BERT)
- Similar to BPE but chooses each merge to maximize the training-corpus likelihood under a unigram language model
- Concretely, it picks the pair whose merge gives the largest increase in log-likelihood, . For a unigram model this is closely related to the ratio (pointwise mutual information), but the exact criterion is the likelihood gain, not raw PMI.
- Why: Better theoretical grounding (each merge is chosen to make the data more probable, not just more compressed)
SentencePiece (T5, LLaMA)
- Treats input as a raw byte/character stream (no pre-tokenization on whitespace)
- Learns BPE (or unigram LM) directly on Unicode characters or bytes
- Why: Language-agnostic, treats spaces as normal symbols, works for languages without clear word boundaries
Byte-level BPE (GPT-2, GPT-3)
- Runs BPE on bytes (UTF-8 encoded) instead of characters
- Base vocab = 256 bytes, then merge
- Why: Truly universal (any text in any language), no special handling needed
BPE in Practice: Hyperparameters
| Parameter | Typical Range | Effect |
|---|---|---|
| Vocab size | 10k-50k | Larger → longer training, shorter sequences, more rare-word memorization |
| Min frequency | 2-10 | Filter rare pairs to speed up training |
| Pre-tokenization | Word/byte | Word-level: keep words intact (GPT-2 splits on spaces + punctuation) |
| Special tokens | [PAD], [UNK], [CLS], etc. |
Added to vocab separately, never merged |
The 80/20: 30k vocab, min frequency = 2, byte-level pre-tokenization covers most modern LM needs.
Connections
- 4.2.01-Tokenization-Overview: BPE is one of three major tokenization strategies
- 4.2.03-WordPiece-Tokenization: Variant using likelihood gain instead of raw frequency
- 4.2.04-SentencePiece: Unigram LM + BPE without pre-tokenization
- 4.3.01-Language-Model-Basics: Tokenization is preprocessing for LMs; vocab size affects model size
- 3.1.05-Embedding-Layer: Vocab size determines embedding matrix size
- 6.2.02-Inference-Optimization: Smaller vocab → fewer embedding lookups → faster inference
#flashcards/ai-ml
What is the core idea of Byte-Pair Encoding (BPE)?
What are the three steps of BPE training?
Why does BPE start with characters instead of words?
During BPE encoding, why must merge rules be applied in the order they were learned?
How does the BPE sequence length scale with average token length k?
How does BPE handle out-of-vocabulary words?
What's the difference between BPE and WordPiece?
Why do modern LLMs (GPT-2, GPT-3) use byte-level BPE?
Common mistake: Why can't you apply all BPE merge rules simultaneously during encoding?
Concept Map
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Dekho, BPE ka core idea bahut simple hai - hume text ko chhote pieces (tokens) mein todna hai, par question ye hai ki kitne chhote? Agar hum pure words ko tokens banaein, toh vocabulary itni badi ho jaati hai (millions of words!) ki model handle nahi kar paata, aur koi naya ya galat spelled word aaye toh model bolta hai "unknown, samajh nahi aaya". Dusra extreme hai character-level, jahaan sirf a-z aur kuch symbols hote hain - vocabulary chhoti par har word bahut lambe sequence mein toot jaata hai aur model ko spelling se seekhna padta hai. BPE in dono ke beech ka smart middle ground hai - ye subword units banata hai jaha common words ek single token rehte hain aur rare words sensible pieces mein tootte hain, jaise "walking" = "walk" + "ing".
Ab ye kaam kaise karta hai? BPE originally ek data compression algorithm tha, aur idea ye hai ki jo character pair sabse zyada baar aata hai use ek naya token bana do. Pehle hum saare words ko individual characters mein tod dete hain, phir baar-baar dekhte hain ki kaunsa adjacent pair (jaise "e" aur "s") corpus mein sabse frequently aata hai, aur us pair ko merge karke naya token "es" bana dete hain. Ye process repeat hota hai jab tak humari vocabulary desired size (jaise 10k-50k tokens) tak na pahunch jaaye. Iski beauty ye hai ki ye greedy aur frequency-based hai - jo patterns zyada aate hain unhe efficiently store karta hai, aur same corpus par hamesha same result deta hai (deterministic).
Ye tumhe matter kyun karta hai? Aaj ke saare bade language models - ChatGPT, GPT, etc - ke andar tokenization ka yahi ya isi jaisa approach use hota hai. BPE tumhe word-level ki 80% efficiency deta hai sirf 20% vocabulary size mein, aur sabse important - kabhi bhi "unknown word" ka problem nahi aata kyunki worst case mein word characters mein toot jaayega. Toh jab bhi tum kisi AI model ke saath kaam karoge, samajhna ki tumhaara text pehle in subword tokens mein convert hota hai - yehi foundation hai jispe pura language modeling khada hai.