4.2.2Tokenization & Language Modeling

Byte-Pair Encoding (BPE)

3,273 words15 min readdifficulty · medium2 backlinks

What Problem Does BPE Solve?

Three tokenization approaches and their problems:

  1. Word-level: Vocabulary explodes (millions of words), can't handle typos/"unknownwords" → <UNK> tokens everywhere
  2. Character-level: Small vocab (26-100 chars), but sequences become VERY long, model must learn spelling from scratch
  3. 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.

Figure — Byte-Pair Encoding (BPE)

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 VV → 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 V0={l,o,w,e,r,n,s,t,i,d,</w>}V_0 = \{l, o, w, e, r, n, s, t, i, d, \text{</w>}\} → size = 11

Frequencies of pairs (multiply pair occurrences by word count):

  • (l, o): appears in low(×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>

V1=V0{es}V_1 = V_0 \cup \{\text{es}\} → 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>

V2=V1{est}V_2 = V_1 \cup \{\text{est}\} → 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):

  1. e s → es
  2. es t → est
  3. l o → lo
  4. lo 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 kk. So the sequence length shrinks roughly linearly with kk: LBPEC/kL_{\text{BPE}} \approx C/k. Crucially, kk 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 VV.

Diminishing returns: Going from 10k → 50k vocab increases kk 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:

  1. 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!

  2. Use letters: "p" "i" "z" "z" "a" = 5 codes. Only 26 codes total (letters), but now every message is super long!

  3. 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, ΔlogP(corpus)\Delta \log P(\text{corpus}). For a unigram model this is closely related to the ratio P(ab)P(a)P(b)\frac{P(ab)}{P(a)\,P(b)} (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 VV 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 VV determines embedding matrix size (V×d)(V \times d)
  • 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)?
BPE is a data compression algorithm that learns a vocabulary by iteratively merging the most frequent character pairs, creating subword units that balance vocabulary size with the ability to represent rare words.
What are the three steps of BPE training?
1. Initialize with character-level vocabulary. 2. Iteratively merge the most frequent adjacent pair and add to vocabulary. 3. Stop when target vocabulary size is reached.
Why does BPE start with characters instead of words?
Starting with characters guarantees that ANY input text can be encoded (no unknown tokens), and then frequent patterns are built up from this universal base.
During BPE encoding, why must merge rules be applied in the order they were learned?
Because later merge rules depend on earlier ones. For example, "es" must be created before "est" can be merged. Applying out of order breaks the dependency chain.
How does the BPE sequence length scale with average token length k?
Roughly linearly: L_BPE ≈ C/k, where C is corpus length in characters and k is average characters per token. It does NOT scale logarithmically with vocabulary size.
How does BPE handle out-of-vocabulary words?
BPE has no true OOV problem. Any word can be decomposed into subword tokens, down to individual characters if needed. Rare words become sequences of subword pieces.
What's the difference between BPE and WordPiece?
BPE merges the pair with the highest raw frequency. WordPiece merges the pair that maximizes the increase in corpus likelihood (Δ log-probability) under a unigram model, which is related to but not identical to raw PMI.
Why do modern LLMs (GPT-2, GPT-3) use byte-level BPE?
Operating on bytes (UTF-8 encoding) makes tokenization language-agnostic and universal. Base vocab is exactly 256 bytes, and it handles any text in any language without special cases.
Common mistake: Why can't you apply all BPE merge rules simultaneously during encoding?
Because merge rules have dependencies. "es" must exist before you can create "est". Simultaneous application would fail to find dependent pairs. Rules must be applied sequentially in learning order.

Concept Map

problem: huge vocab and UNK

problem: long sequences

adapted into

discovers

starts from

builds

selects most frequent pair for

grows until

enables

captures

eliminates

Word-level tokens

Character-level tokens

Byte-Pair Encoding

Subword units

Data compression algorithm

Iterative pair merging

Frequency counting

Fixed vocab size V

Rare word decomposition

Morphological patterns

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.

Go deeper — visual, from zero

Test yourself — Tokenization & Language Modeling

Connections