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.
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.
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:
256 – 1k pieces
30k – 250k pieces
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.
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
runpiece - Fixed vocabulary size — typically 32k–250k, a practical engineering sweet spot
[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.
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
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+##izationunbelievable→un+##believe+##ablepreprocessing→pre+##processingCOVID-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].
## 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.
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)
a–z, digits, punctuation
bigram frequencies
add to vocabulary
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:
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.
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:
play + ##ing = 2 tokensWord-level: 1 token (if in vocab) or
[UNK]Char-level:
p l a y i n g = 7 tokens
un + ##believ + ##able = 3 tokensWord-level: almost certainly
[UNK] (too rare for large vocab)Char-level: 12 characters = 12 tokens
GP + ##T + - + 4 = 4 tokensWord-level:
[UNK] (post-training term unknown)Char-level:
G P T - 4 = 5 tokens
CO + ##V + ##ID + - + 19 = 5 tokensWord-level:
[UNK] (pandemic-era neologism unseen in pre-2020 training)Char-level: 8 characters = 8 tokens
[unused0] or ##8+##f+... (UTF-8 byte fallback) = 3–4 tokensWord-level:
[UNK]Byte-level BPE (GPT-4): 1 token (emoji bytes get their own entry)
## 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.
MathematicsVocabulary Size & Sequence Length
Two fundamental quantities govern the subword tokenization trade-off: vocabulary size V and expected sequence length L.
Vocabulary Size Formula
LLaMA-3: $V = 128{,}000$ (SentencePiece BPE, much larger merge table)
Sequence Length & Coverage Trade-off
Embedding Matrix Memory
Vocabulary size also directly controls GPU memory consumption for the embedding layer:
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.
Ġ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
Ġ or ).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:
"""
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.
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"
Complete your understanding — check off each observation:
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 |
▁), making it language-agnostic and eliminating any need for pre-tokenization.
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
nationand Frenchnationshare the same token → shared embedding - English
##ingand German##ungare 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.
LimitsWhat Subwords Cannot Do
Subword tokenization is a major improvement over its predecessors — but it has real, documented limitations that matter in practice.
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.
##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.
🔢 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
strawberryis 2–3 tokens, not 10 characters - Arithmetic:
123456789 + 1splits 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.
Feynman ChallengeExplain It Like a 12-Year-Old
Imagine you have to explain subword tokenization to someone who has never heard of it. Use only the LEGO analogy. Cover these four points:
- Why individual characters (plastic dust) are too small to be useful
- Why whole words (pre-built sets) fail on anything new
- Why standard bricks (subwords) are the Goldilocks solution
- 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.tokenis 2 syllables but 1 token.COVIDis 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.
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.
- 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"]. - Bigram counter: Count all adjacent character pairs. The pair
("i", "n")appearing 1,200 times means "in" would be an early BPE merge candidate. - 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.
- Iterative merge simulation: Apply the top merge to all words (replace every
["i", "n"]pair with["in"]), then recount. Repeat 10 times. - 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.
