› 01 · Tokens › Subword Tokens
⚡ Visual Simulator
AI Journey · Understand Language

Subword Tokens

The conceptual bridge that explains why subword tokenization exists before you dive into BPE, WordPiece, or SentencePiece. Discover how learned pieces — smaller than words, larger than characters — eliminate OOV errors and power every modern LLM.

🔴 MUST 15 Study Phases Tokens Core Prerequisite: Characters vs Tokens
🧙‍♂️ The Wise Scholar's Metaphor Root Morphemes & Lego Blocks
⏮️ 00 · Math & Foundations Hub →

Subwords: The Scholar's Universal Lego Set

Just as an ancient linguist recognizes prefixes ("un-", "re-"), roots ("struct", "play"), and suffixes ("-ing", "-able"), the LLM uses subwords as reusable linguistic building blocks. When confronted with an alien or compound word like "neurotranscriptional", the scholar never panics — they snap together familiar subword blocks with zero information loss.

01

IntroductionWhat Are Subword Tokens?

A subword token is a learned textual fragment that sits on the spectrum between a single character and a complete word. It is the fundamental unit of text representation in every major modern language model — GPT, BERT, LLaMA, Gemini, Claude, and beyond.

  • Core definition: subword = a reusable, statistically-learned piece of text
  • Size range: from 1 character (e.g. a) up to a full common word (e.g. the)
  • Key property: the vocabulary is finite and fixed yet can represent any possible input without unknown-token errors

Think of the tokenization spectrum as a dial you can turn from "characters" all the way to "whole words." Subwords sit in the productive middle ground — large enough to carry meaning, small enough to cover everything:

🔡 Characters
256 – 1k pieces
→
🧩 Subwords
30k – 250k pieces
→
📝 Whole Words
500k – 5M pieces

This page is the conceptual bridge — understanding why this middle ground exists will make BPE, WordPiece, and SentencePiece immediately intuitive when you reach those topics.

02

WhyThe Problems Subwords Solve

Before subword tokenization, NLP engineers were forced to choose between two painful extremes. Each had a critical flaw:

❌ Word-Level Problem

  • Vocabulary must be pre-defined at training time — millions of entries
  • Any unseen word becomes [UNK], erasing all meaning
  • New words (COVID-19, emoji, code identifiers) are permanently invisible
  • Morphological variants (run / running / ran) each need separate entries

❌ Character-Level Problem

  • Zero OOV, but sequences become 4–6× longer than word-level
  • Self-attention cost is quadratic in sequence length → massive compute
  • Each character alone carries almost no semantic meaning
  • Context windows fill up before the model can "see" long-range structure

✅ Subword Solution

  • No OOV — rare words split into known pieces; any text is representable
  • Compact sequences — fertility ratio of ~1.2 vs ~5× for character-level
  • Shared morphology — run, running, runner all share the run piece
  • Fixed vocabulary size — typically 32k–250k, a practical engineering sweet spot
💡 Tip: The [UNK] token is catastrophic in practice. If a model encounters a medical term, a proper noun, or a foreign word it has never seen, [UNK] replaces the entire word with a single, featureless placeholder — all semantic signal is lost.
03

IntuitionThe LEGO Brick Analogy

The LEGO analogy is the most reliable way to build correct intuition about subword tokenization.

🧱 Character-Level = Individual LEGO Studs

Imagine trying to build a house using only individual plastic studs — the tiny bumps on top of each brick. You can technically represent any structure, but it takes thousands of studs for even a simple door. The sheer number of pieces makes working with them exhausting.

🏗️ Word-Level = Pre-Built LEGO Sets

Now imagine you can only use pre-assembled custom sets — a specific police station, a specific bakery. Perfect when you need exactly those things. But if you want a space-age coffee shop, no such kit exists. You are stuck; you cannot represent it at all.

🔵 Subword-Level = Standard LEGO Bricks

The Lego Store sells standard bricks in a finite set of shapes: 1×1, 1×2, 2×4, roof slopes, window frames. For common structures (a wall) there might be a large pre-formed piece. For anything exotic, you assemble it from standard bricks. You can build anything without needing an infinite catalogue.

This is exactly what subword tokenizers do: build a finite vocabulary of reusable pieces, then assemble any word — however rare or new — from those pieces.

  • Common words like the, is, and → one brick each (whole token)
  • Common affixes like un-, -ing, -tion → dedicated bricks
  • Rare or new words → assembled from multiple bricks (subwords)
  • Any text can be built — zero [UNK], ever
04

TheoryThree Core Principles

All subword tokenization algorithms — BPE, WordPiece, SentencePiece — share three fundamental design principles:

① Common words stay whole

High-frequency words that appear thousands of times in the training corpus are typically kept as single tokens. Examples: the, is, and, you, have, that. Splitting these common words would needlessly inflate sequence length for no benefit.

② Rare or compound words are split into reusable pieces

Low-frequency or never-before-seen words are decomposed. The split points are determined statistically — whichever segmentation maximises use of already-common pieces. Examples:

  • tokenization → token + ##ization
  • unbelievable → un + ##believe + ##able
  • preprocessing → pre + ##processing
  • COVID-19 → CO + ##V + ##ID + - + 19

③ Any text is representable — zero [UNK]

As a last resort, any character that exists in the base alphabet is a valid single-character token. Because the alphabet is always included, every possible input can be represented. No word will ever be replaced by [UNK].

📘 Note: The ## prefix in BERT-style WordPiece tokenization marks a continuation piece — a subword that attaches to the previous token without a space. SentencePiece uses a different convention: a ▁ (underscore) prefix marks word-starts. BPE uses space-prefixed tokens (e.g. Ġtoken) in GPT-family models. The encoding convention differs, but the principle is identical.
05

How It WorksFrequency-Based Learning

Subword vocabularies are learned from data, not hand-crafted. The core mechanism is frequency-based: pieces that appear often in the training corpus earn a place in the vocabulary; pieces that are rare get split further.

The Training Loop (simplified)

Start: base alphabet
a–z, digits, punctuation
→
Count all pairs
bigram frequencies
→
Merge most frequent pair
add to vocabulary
→
Repeat until
target vocab size

The Threshold Intuition

The boundary between "keep as one token" and "split into pieces" is set implicitly by the target vocabulary size V. You choose, say, V = 50,000 merge operations. After those merges are learned:

  • Any sequence that appeared frequently enough during training will have been merged into a single token
  • Any sequence that was too rare will remain as multiple smaller pieces

Concrete example with the vs tokenization:

Word:"the" (appears ~50M times in English web text)
Result:1 token — the entire string "the" was merged early in training

Word:"tokenization" (appears ~80,000 times)
Result:2–3 tokens — "token" was merged but "##ization" is a separate piece

Word:"supercalifragilistic" (very rare)
Result:8+ tokens — broken into many short familiar pieces
⚠️ Statistical, not linguistic: Subword splits do not follow grammar, morphology, or syllable boundaries. They follow corpus statistics. tokenization might split as token + ization in one model and token + iz + ation in another — entirely depending on what pairs were most frequent in that model's training data.
06

ExamplesWorked Tokenization Cases

Let's trace exactly how several real words tokenize under BERT-style WordPiece notation and contrast with word-level and character-level approaches:

Ex 1 "playing" → subword: play + ##ing = 2 tokens
Word-level: 1 token (if in vocab) or [UNK]
Char-level: p l a y i n g = 7 tokens
Ex 2 "unbelievable" → subword: un + ##believ + ##able = 3 tokens
Word-level: almost certainly [UNK] (too rare for large vocab)
Char-level: 12 characters = 12 tokens
Ex 3 "GPT-4" → subword: GP + ##T + - + 4 = 4 tokens
Word-level: [UNK] (post-training term unknown)
Char-level: G P T - 4 = 5 tokens
Ex 4 "COVID-19" → subword: CO + ##V + ##ID + - + 19 = 5 tokens
Word-level: [UNK] (pandemic-era neologism unseen in pre-2020 training)
Char-level: 8 characters = 8 tokens
Ex 5 "😊" → subword: [unused0] or ##8+##f+... (UTF-8 byte fallback) = 3–4 tokens
Word-level: [UNK]
Byte-level BPE (GPT-4): 1 token (emoji bytes get their own entry)
💡 Key pattern: Notice that the ## prefix marks pieces that continue a word without whitespace. When you decode, you strip the ## and concatenate. The prefix is a lossless signal that lets the tokenizer perfectly reconstruct the original text.
07

MathematicsVocabulary Size & Sequence Length

Two fundamental quantities govern the subword tokenization trade-off: vocabulary size V and expected sequence length L.

Vocabulary Size Formula

BPE $$V = |\Sigma_{\text{base}}| + N_{\text{merges}}$$ where $|\Sigma_{\text{base}}|$ is the size of the base alphabet (256 for byte-level BPE) and $N_{\text{merges}}$ is the number of merge operations you choose to run.
Example GPT-2: $|\Sigma| = 256$ bytes, $N_{\text{merges}} = 50{,}000 - 256 = 49{,}744$ → $V = 50{,}257$ (with special tokens)
LLaMA-3: $V = 128{,}000$ (SentencePiece BPE, much larger merge table)

Sequence Length & Coverage Trade-off

Bound $$L_{\text{char}} \;\geq\; L_{\text{subword}} \;\geq\; L_{\text{word}}$$ Character sequences are always the longest; word sequences are shortest (but suffer OOV). Subword sequences sit between these extremes.
Fertility The fertility ratio $F$ quantifies this: $$F = \frac{L_{\text{subword}}}{L_{\text{word}}}$$ Typical values: $F \approx 1.1$–$1.3$ for English with $V = 32{,}000$. Low vocabulary → higher $F$ → longer sequences → more compute.
Cost Self-attention compute scales as $O(L^2 \cdot d)$. Doubling sequence length quadruples compute. This is why fertility matters — a tokenizer with $F = 2.0$ is roughly 4× more expensive than one with $F = 1.0$ for the same text.

Embedding Matrix Memory

Vocabulary size also directly controls GPU memory consumption for the embedding layer:

Formula $$\text{Params}_{\text{embed}} = V \times d_{\text{model}} \times 2 \quad \text{(input + output projection)}$$
BERT $V = 30{,}522,\; d = 768 \;\Rightarrow\; 46.9\text{M params} \approx \mathbf{93.7\text{ MB}}$ at FP16
LLaMA-3 $V = 128{,}000,\; d = 4{,}096 \;\Rightarrow\; 1.05\text{B params} \approx \mathbf{2.09\text{ GB}}$ at FP16
08

VisualizeLive Multi-Algorithm Subword Visualizer & Pipeline Trace

Type any sentence, programming code, prompt, or emoji below to visualize how different subword algorithms (BPE, WordPiece, SentencePiece, and Character-level) split the exact same input string into tokens and map them to Token IDs in real-time.

Try Instant Presets:
0
Characters
0
Words
0
Tokens
0.00x
Fertility (Tokens/Word)
🎨 Color-Coded Subword Slices (Hover to see details): 0 tokens rendered
Tokens will appear here as you type...
🔢 Integer Token IDs Array (What the Neural Network Actually Reads)
[]
Byte-Pair Encoding (BPE): Splits common words into full tokens (e.g. ĠThe, Ġfast) and breaks rare or compound words into frequent subword chunks (e.g. Ġtoken + izer, Ġun + believ + able). The Ġ represents a leading whitespace character.
🔍 Behind-the-Scenes: Step-by-Step Subword Tokenizer Trace Click to expand / collapse
Step 1 (Normalization): Raw characters are cleaned, Unicode NFC/NFKC normalized, and standardized so slight keyboard variations match identical dictionary keys.
Step 2 (Pre-tokenization): The text stream is split along whitespace and punctuation boundaries into candidate token words, preserving space tokens (like Ġ or ).
Step 3 (Subword Model Search): The algorithm compares substrings against the pre-trained vocabulary table (e.g., iteratively applying learned BPE pair merges or BERT MaxMatch). Rare words are broken down into familiar syllables.
Step 4 (Integer Encoding): Each resolved token string is mapped to its exact integer index in the vocabulary dictionary matrix $W_e$ ($0 \le \text{ID} < V$). These numbers are what the Transformer neural network digests!
09

CodeThree Tokenizers Side-by-Side

This Python example shows the critical difference between word-level, character-level, and subword-level tokenization on the same inputs — including rare words, neologisms, and emoji:

Python
"""
Comparison of word-level, char-level, and subword tokenization.
Shows exactly why subwords are the right default for LLMs.
"""

# ── 1. Word-level tokenizer ──────────────────────────────────────────
WORD_VOCAB = {"the", "is", "this", "playing", "game", "a", "good"}

def word_tokenize(text):
    tokens = []
    for word in text.lower().split():
        word = word.strip(".,!?")
        tokens.append(word if word in WORD_VOCAB else "[UNK]")
    return tokens

# ── 2. Character-level tokenizer ─────────────────────────────────────
def char_tokenize(text):
    return list(text)  # every character is a token

# ── 3. Simple subword tokenizer (greedy max-match) ───────────────────
SUBWORD_VOCAB = [
    # Whole common words (sorted longest-first for greedy matching)
    "the", "is", "this", "playing", "game", "good", "a",
    # Common prefixes
    "un", "pre", "re",
    # Common roots
    "believ", "play", "token", "process", "covid",
    # Common suffixes (## = continuation, no preceding space)
    "##able", "##ation", "##ing", "##er", "##ed", "##ize",
    "##ization", "##ment", "##ness", "##ly",
    # Fallback: individual letters
    *list("abcdefghijklmnopqrstuvwxyz0123456789-"),
]

def subword_tokenize(word):
    """Greedy max-match subword segmenter (WordPiece-style)."""
    tokens = []
    start = 0
    while start < len(word):
        matched = None
        for piece in SUBWORD_VOCAB:
            clean = piece.lstrip("#")
            if word[start:].startswith(clean):
                candidate = piece if start == 0 else ("##" + clean)
                if candidate in SUBWORD_VOCAB or clean in SUBWORD_VOCAB:
                    matched = ("##" + clean) if start > 0 else clean
                    start += len(clean)
                    break
        if matched is None:
            tokens.append("[UNK]")
            break
        tokens.append(matched)
    return tokens

def subword_tokenize_sentence(text):
    all_tokens = []
    for word in text.lower().split():
        word = word.strip(".,!?")
        all_tokens.extend(subword_tokenize(word))
    return all_tokens

# ── Run comparison ────────────────────────────────────────────────────
test_sentences = [
    "this is a good game",         # all common words
    "unbelievable tokenization",   # rare / morphologically rich
    "COVID-19 preprocessing",      # neologism + compound
]

for sentence in test_sentences:
    print(f"\nInput: '{sentence}'")
    print(f"  Word-level  : {word_tokenize(sentence)}")
    print(f"  Char-level  : {char_tokenize(sentence)[:15]}...")
    print(f"  Subword     : {subword_tokenize_sentence(sentence)}")

Notice that word-level produces [UNK] for anything outside its static vocabulary, character-level produces a torrent of single characters, but subword-level handles everything — including the COVID-19 neologism — without any unknown tokens.

10

ExperimentHands-On Tokenization Lab

Run these experiments in any Python environment with pip install transformers. Compare how four challenging inputs tokenize across approaches:

Test inputs: "unbelievable", "COVID-19", "😊", "tokenization"

>>>from transformers import AutoTokenizer
>>>bert = AutoTokenizer.from_pretrained("bert-base-uncased")
>>>gpt2 = AutoTokenizer.from_pretrained("gpt2")

# "unbelievable"
BERT['un', '##believe', '##able'] ← 3 tokens
GPT2['un', 'believ', 'able'] ← 3 tokens (no ## prefix)

# "COVID-19"
BERT['co', '##vi', '##d', '-', '19'] ← 5 tokens
GPT2['COV', 'ID', '-', '19'] ← 4 tokens

# "😊" (smiling face emoji)
BERT['[UNK]'] ← unknown! BERT lacks emoji coverage
GPT2['ðŁĺ', 'Ŀ'] ← 2 UTF-8 byte tokens

# "tokenization"
BERT['token', '##ization'] ← 2 tokens
GPT2['token', 'ization'] ← 2 tokens

Complete your understanding — check off each observation:

11

CompareWord vs Character vs Subword

A comprehensive side-by-side comparison of the three tokenization strategies and the two main subword algorithms:

Property Word-Level Character-Level Subword — BPE Subword — WordPiece
Vocab size 500k – 5M 256 – 1k 32k – 128k 30k – 100k
Seq length (fertility) Shortest (F≈1.0) Longest (F≈5–6) F ≈ 1.1–1.3 F ≈ 1.1–1.3
Rare word handling [UNK] — total loss Zero OOV Zero OOV Zero OOV
Merge criterion N/A N/A Raw pair frequency Likelihood gain (PMI-like)
Continuation marker N/A N/A Ġ (space prefix) ## (continuation prefix)
Used by Early NLP (pre-2015) Character LMs, some speech GPT family, LLaMA, Mistral BERT, DistilBERT, ELECTRA
Known limitation OOV catastrophe Quadratic attention cost Frequency-greedy, not linguistic Slower training than BPE
📘 Note: SentencePiece (used by T5, LLaMA, Gemini) is a framework that can run either BPE or Unigram Language Model under the hood. Its distinguishing feature is treating whitespace as a regular character (▁), making it language-agnostic and eliminating any need for pre-tokenization.
12

ApplyWhy Every Major LLM Uses Subwords

The industry-wide convergence on subword tokenization is not an accident — it is the result of consistent empirical evidence that subwords outperform alternatives across every evaluation dimension.

🏛️ Models and Their Tokenizers

BERT (WordPiece)

30,522 tokens. ##-continuation style. Trained on Wikipedia + Books. Bidirectional — both left and right context. First model to demonstrate that subword sharing enables true cross-lingual transfer.

GPT-2 / GPT-3 / GPT-4 (BPE)

50,257 – 100,000+ tokens. Byte-level BPE with space-prefix. Handles any Unicode, any emoji, any code — zero OOV guaranteed by byte fallback. Unidirectional (left-to-right generation).

LLaMA / Mistral / Gemma (SentencePiece BPE)

32,000 – 128,000 tokens. Whitespace as ▁ character. No language-specific pre-tokenizer — works identically for English, Chinese, Arabic, code. Enables strong multilingual ability.

T5 / mT5 (SentencePiece Unigram)

32,000 tokens. Unigram Language Model variant — probabilistic rather than greedy. Explicitly optimised for multilingual corpora. Same ▁ whitespace convention.

🌍 Cross-Lingual Transfer

One of the most powerful benefits of subword tokenization: models learn shared representations across languages that happen to share subword pieces. For example:

  • English nation and French nation share the same token → shared embedding
  • English ##ing and German ##ung are different tokens but the model discovers their semantic parallel through training
  • Multilingual BERT (mBERT) supports 104 languages from a single 110k-token vocabulary

💻 Code Models Learn Code-Specific Pieces

When LLMs are trained on code, the BPE merge process discovers code-specific tokens: def, return, import, self., =>, != become single tokens. This dramatically reduces token counts for code, giving models a larger effective context for code understanding.

13

LimitsWhat Subwords Cannot Do

Subword tokenization is a major improvement over its predecessors — but it has real, documented limitations that matter in practice.

⚠️ Arbitrary segmentation: The same word can tokenize completely differently between models. tokenization splits as [token, ization] in BERT and [token, iz, ation] in another model. There is no single "correct" split — it depends entirely on the training corpus and vocabulary size. This means prompts, fine-tuning datasets, and tokenizer outputs are not interchangeable between models.
⚠️ Subword ≠ morpheme: BPE and WordPiece are statistical algorithms. They have no knowledge of linguistics. The piece ##ation emerges because the character sequence "ation" appeared together frequently — not because the algorithm understands it is a nominalizing suffix. The split pre + ##processing is a coincidence of frequency, not a morphological analysis.
⚠️ Tokenizer lock-in: Once a model is trained with a specific tokenizer, that tokenizer is permanently bound to that model. You cannot swap tokenizers without re-training from scratch. This is why tokenizer choice is a critical, irreversible engineering decision made before pretraining begins.

🔢 Arithmetic and Spelling Challenges

Because numbers and characters are split at arbitrary byte/subword boundaries, subword models struggle with tasks that require character-level awareness:

  • Spelling: "How many 'r's in 'strawberry'?" fails because strawberry is 2–3 tokens, not 10 characters
  • Arithmetic: 123456789 + 1 splits into many number tokens, not digits — addition rules don't transfer cleanly
  • Reversing strings: the model never "sees" individual characters, only pieces

These limitations are a direct consequence of the subword design. Character-level or byte-level models handle them better, at the cost of much longer sequences.

14

Feynman ChallengeExplain It Like a 12-Year-Old

🗣️ The LEGO Brick System — Teach It Out Loud

Imagine you have to explain subword tokenization to someone who has never heard of it. Use only the LEGO analogy. Cover these four points:

  1. Why individual characters (plastic dust) are too small to be useful
  2. Why whole words (pre-built sets) fail on anything new
  3. Why standard bricks (subwords) are the Goldilocks solution
  4. What the ## marker represents in LEGO terms (a brick that snaps directly onto the previous brick without a gap)

Then address these common misconceptions:

  • Misconception 1: "Subwords are just syllables."
    Reality: Syllables are defined by pronunciation rules. Subwords are defined by corpus statistics. token is 2 syllables but 1 token. COVID is 2 syllables but 3–5 tokens depending on the model.
  • Misconception 2: "Subwords = morphemes."
    Reality: Morphemes are the smallest grammatical units (un-, -able). Subwords may accidentally align with morphemes but do so only when those morphological boundaries happen to be high-frequency character junctions in the training corpus.
  • Misconception 3: "A bigger vocabulary is always better."
    Reality: Larger vocabularies reduce fertility (good) but increase embedding matrix memory (bad) and require more training data for rare tokens to be well-represented.
15

BuildMini-Project: Subword Frequency Analyzer

Build a tool that answers the question: "Given a text corpus, which subword patterns are most frequent — and therefore would become vocabulary entries in a trained tokenizer?"

🎯 Project: Subword Frequency Analyzer

Goal: Given any text corpus, count the most common character n-grams (bigrams, trigrams) that would be candidates for BPE merges. This directly shows why certain pieces end up in a trained vocabulary.

  1. Corpus ingestion: Load any text file (e.g., a Wikipedia article, your own writing). Split into words, then split each word into characters separated by spaces: "playing" → ["p", "l", "a", "y", "i", "n", "g"].
  2. Bigram counter: Count all adjacent character pairs. The pair ("i", "n") appearing 1,200 times means "in" would be an early BPE merge candidate.
  3. Top-N ranking: Print the top 20 most frequent pairs. These are exactly the first 20 merges a BPE tokenizer would learn from your corpus.
  4. Iterative merge simulation: Apply the top merge to all words (replace every ["i", "n"] pair with ["in"]), then recount. Repeat 10 times.
  5. Visualize: Print each merge step: Merge 1: ('i','n') → 'in' (frequency: 1,247)

🔍 What you'll discover: The most frequent English bigrams are th, he, in, er, an — exactly the pieces you'll find in every BPE vocabulary. This makes the statistical nature of subword tokenization viscerally concrete.

🚀 Extension challenge: Run the same analyzer on a Python source code corpus. Notice how different the top bigrams are — se, lf, de, f emerge early, reflecting Python's heavy use of self and def. This is why code-trained models tokenize Python more efficiently than general-purpose models.

📌 Summary — 6 Things to Remember

  • Subwords are the middle ground between characters (too small, sequences too long) and words (too large, OOV problem).
  • The core guarantee: any text can be represented without [UNK] — rare words split into known pieces, as a last resort into individual characters.
  • Vocabulary is learned, not hand-crafted — high-frequency sequences become tokens; rare sequences get split. The threshold is implicit in the target vocab size.
  • Statistical, not linguistic — splits follow corpus statistics, not grammar or syllable rules. Don't expect morphological correctness.
  • Three main algorithms: BPE (GPT family — merge by raw frequency), WordPiece (BERT — merge by likelihood gain), SentencePiece (T5/LLaMA — no pre-tokenizer needed, treats whitespace as a character).
  • Tokenizer lock-in is real — vocabulary choice is made once, before training, and is irreversible. Different models with different tokenizers cannot share token IDs.
🐙
Go Deeper · Code it yourself
ai-engineering-from-scratch
Two lessons cover exactly the subword algorithms described here — BPE, WordPiece, Unigram, and SentencePiece — with runnable Python and Rust implementations you build from the merge loop up.
This page 0:00
This session 0:00
Total (all pages) 0:00
Today 0:00
▶ Running
📊 View all study stats →
0:00 studying