Building a Minimal BPE Tokenizer from Scratch
Byte Pair Encoding is a tokenization method used in natural language processing, including in GPT-2.
Why Models Read Tokens Instead of Sentences
A language model does not read text as whole sentences. It reads a sequence of tokens, and something has to decide where one token ends and the next begins. That something is the tokenizer. The choice of tokenizer affects how much text fits into a model's input, how common words and rare words are represented, and how the model handles spellings it has never seen before.
This article builds a clear mental model of one tokenization method, Byte Pair Encoding, usually abbreviated BPE. The goal is to understand what happens step by step, so that the implementations and interactive demonstrations you meet later make sense. The central idea is small enough to trace by hand, and you will do exactly that below.
What BPE Is and Where It Is Used
Byte Pair Encoding is a tokenization method used in natural language processing. It is the method behind the tokenizer used to train GPT-2.
The name points to the core operation. A BPE tokenizer works on pairs of adjacent symbols and combines frequent pairs into single units. Repeating that combination step gradually builds a vocabulary of units that are longer than one character and shorter than a whole word. Because the units are pieces of words, BPE belongs to the family of subword tokenization methods.
The method has a well-known origin in machine translation. The research paper that introduced this approach is titled Neural Machine Translation of Rare Words with Subword Units. It was published in 2015 by Sennrich et al. and is available on arXiv. Its title states the motivation directly: rare words are the hard case, and subword units are the proposed way to handle them.
Why Subword Units Sit Between Two Extremes
There are two obvious ways to cut text into tokens, and both have costs. If a tokenizer treats every whole word as one token, it needs a huge vocabulary, and any word it has not seen during training has no entry at all. If it treats every character as one token, the vocabulary stays small, but the sequences become long and the individual units carry little meaning on their own.
| Tokenization approach | Vocabulary size | Sequence length | Handling of a word never seen in training |
|---|---|---|---|
| Whole words as tokens | Huge | Short | No entry exists for the word |
| Single characters as tokens | Small | Long | Units carry little meaning on their own |
| Subword units (BPE) | Between the two | Between the two | Assembled from smaller pieces the vocabulary already holds |
Where subword units fall relative to whole-word and character tokenization
Subword units resolve this tension. Common words can stay whole, while rare or unfamiliar words are assembled from smaller pieces that the vocabulary already contains. Subword units let a tokenizer represent a rare word by combining pieces it already knows, rather than needing a dedicated entry for that word.
Tracing One Merge on a Token Sequence
The core of BPE is a single operation repeated many times: look at the current sequence of units, find the adjacent pair that occurs most often, and replace every occurrence of that pair with one new unit. Before looking at a real corpus, trace one merge on a tiny example. Start with the symbol sequence l o w l o w l o t, which is the word-like pattern low, low, lot written as single characters with no spaces.
One merge step on a character sequence
Starting from the symbols l o w l o w l o t, perform one BPE merge step and describe how the sequence changes.
- 1Count adjacent pairs
Reading left to right, the adjacent pairs are lo, ow, wl, lo, ow, wl, lo, ot. The pair lo appears three times, ow appears twice, wl appears twice, and ot appears once.
- 2Pick the most frequent pair
The pair lo has the highest count, so it is the one to merge. The other pairs are left alone for this step.
- 3Create the new unit and replace occurrences
The pair lo becomes a single new unit called lo. Scanning left to right, each non-overlapping occurrence of l followed by o is replaced by lo. The three occurrences sit at positions 0, 3, and 6.
- 4Read the new sequence
The sequence drops from nine symbols to six: lo w lo w lo t. The units at positions 0, 2, and 4 are now the merged unit, and the rest of the sequence is unchanged.
After one merge, the sequence is lo w lo w lo t, and the vocabulary has gained one entry: lo. A unit longer than one character now exists and can be used as a building block for later merges.
Notice what did not change. The w and t symbols kept their positions in the sequence, and only the three occurrences of the pair lo were affected. This is the general pattern: a merge touches exactly the places where the chosen pair occurs, and everywhere else the sequence stays as it was. The new unit lo is now available, so a later merge can combine it with a neighbor, such as w, to form a longer unit.
Counting Pairs and Choosing the Next Merge
Choosing which merge to make is a counting problem. Each pass looks at the current sequence of units, counts how often each adjacent pair occurs, and selects the pair with the highest count. The selection rule is simple and is the same at every step: the most frequent adjacent pair is the one that gets merged. Each merge then adds one new entry to the vocabulary.
- 1Start from the current sequence of units, which at the beginning is just the basic symbols.
- 2Count every adjacent pair of units across the sequence.
- 3Select the pair with the highest count.
- 4Replace each occurrence of that pair with a single new unit.
- 5Record the new unit so that it can serve as a building block for later merges.
Repeating the Merge Loop
The loop between counting and merging is the heart of the method. A single merge only produces a unit two symbols long. Because each merged unit is then available as a building block, a later pass can merge a unit with a neighbor and produce something longer. Over many passes, units grow from single characters into longer pieces, which is how the vocabulary ends up holding units that are longer than one character.
In round 2 of this example, the sequence lo w lo w lo t contains the pair lo followed by w twice, so the walkthrough merges that pair into low. The longer unit low is a piece of a word, not a full word, and it was built entirely from the earlier merged unit lo. Real training runs over a large body of text and performs many merges, but the rule at each step is the same: find the most frequent adjacent pair, merge it, and record the new unit.
Training and Application as Two Stages
A BPE tokenizer is best understood as a pipeline with two distinct stages. Training builds the vocabulary: it starts from a basic set of symbols and performs the merge loop, recording each merge as one entry. Application uses the vocabulary that training produced to split new text into tokens. These are separate jobs, and mixing them up is a common source of confusion.
The diagram shows the flow of data. Training takes raw text, works on its symbols, and produces a vocabulary with one entry per merge. Application takes that vocabulary and a new piece of text and cuts the text into tokens. The vocabulary is the link between the two stages, which is why it is the thing you save after training and reload later.
Mistakes Beginners Make with BPE
Common mistake Starting the merge process from whole words
What it looks likeBeginning with the words low and lot as the initial units and trying to merge them
Why it failsBPE starts from a basic set of symbols. Whole words are the thing a subword method is designed to avoid needing as dedicated entries.
Do this insteadStart from the basic symbols, such as single characters, and let frequent pairs build longer units.
Common mistake Merging the least frequent pair
What it looks likeIn the sequence l o w l o w l o t, choosing ot (count 1) because it looks unusual
Why it failsThe selection rule is to merge the most frequent adjacent pair. Picking a rare pair does not follow that rule.
Do this insteadCount every adjacent pair and merge the one with the highest count.
Common mistake Treating training and application as the same step
What it looks likeExpecting that tokenizing new text will add new merges to the vocabulary
Why it failsTraining is the stage that builds the vocabulary. Application uses a vocabulary that already exists to split new text.
Do this insteadBuild the vocabulary during training, then reuse it unchanged when splitting new text.
Common mistake Expecting a single merge to produce a long word-sized unit
What it looks likeExpecting one merge of l and o to produce low
Why it failsEach merge combines exactly two adjacent units. Longer units come from many rounds, with each round building on earlier merged units.
Do this insteadRepeat the counting and merging loop, so that merged units can combine with neighbors in later rounds.
Common mistake Forgetting that a merge changes only the positions where the chosen pair occurs
Where to Inspect or Build a BPE Tokenizer
Once the mental model is clear, there are resources that let you go further. The source material points to three concrete resources, and each suits a different goal: moving from the concept to real code, or moving from the concept to a visual demonstration. The reading that started it all is the 2015 paper by Sennrich et al., available on arXiv, which explains why subword units were proposed for rare words in machine translation.
- Read the original paper, Neural Machine Translation of Rare Words with Subword Units, on
arXivto understand the motivation behind the method. - Use a real code implementation to see the counting and merging loop running on actual text.
- Use an interactive visual demonstration to watch pairs being counted and merged step by step.
- Compare the three resources against your own hand traces to check that you understand the merge rule.
Predicting the First Merge
What do you think happens?
Given the symbol sequence a a a b, which pair is merged first, and what is the sequence afterward?
Reveal answer
The pair aa is merged, giving aa a b
The adjacent pairs are aa, aa, and ab. The pair aa occurs twice and ab occurs once, so aa is the most frequent pair. Scanning left to right, the first two symbols form a non-overlapping occurrence and become aa, leaving a and b after it.
Take the symbol sequence c a t c a t c o t. Count every adjacent pair, identify the most frequent pair, and write the sequence after one merge of that pair. Then state how many entries the vocabulary gains and which positions changed.
Hints
- List all adjacent pairs first, reading from left to right, before deciding anything.
- Two positions in the original sequence are the start of the pair you are merging; check how many occurrences there are.
- Only the positions where the chosen pair occurs should change.
Key Takeaways
- BPE is a tokenization method, used in natural language processing and in the tokenizer behind GPT-2, that builds subword units by repeatedly merging the most frequent adjacent pair of symbols.
- Subword units sit between whole-word and character tokenization, letting common words stay whole while rare words are assembled from smaller pieces already in the vocabulary.
- Each merge counts adjacent pairs, selects the most frequent one, replaces its occurrences with a single new unit, and adds one entry to the vocabulary.
- Training builds the vocabulary through the merge loop; application uses that vocabulary to split new text into tokens.
- The open-source resources to explore are the original 2015 paper, real code implementations, and interactive visual demonstrations.