BPE pair counts and merges
Lesson: BPE Tokenizer From ScratchCheat sheetTrack: LLM inference
Problem
Byte-Pair Encoding builds a tokenizer vocabulary from a corpus. It counts how often each pair of adjacent symbols occurs. It merges the most frequent pair into a new symbol. Then it repeats. The merge list that this loop makes is the tokenizer that a language model reads its text with.
Task
The corpus is a dict. Each key is a word as a tuple of integer symbol ids. Each value is the number of times the word occurs.
Write four functions.
count_pairs(units)returns a dict from each adjacent pair(a, b)to its count. A pair in a word adds the frequency of the word. Pairs do not cross from one word to the next.best_pair(pairs)returns the pair with the highest count. When two or more pairs have the highest count, return the smallest pair in tuple order. For example,(2, 9)is smaller than(5, 1). Whenpairsis empty, returnNone.apply_merge(symbols, pair, new_id)returns a tuple in which each occurrence ofpairis replaced bynew_id. Scan from left to right. After a match, continue after the second symbol of the match, so two matches never share a symbol.train(units, num_merges, first_id=256)runs up tonum_mergesmerge steps. Each step counts the pairs, picks the best pair and merges it in every word. Merge number i, from 0, gets the idfirst_id + i. Stop early when there are no pairs or when the best pair has a count less than 2.
train returns a tuple (merges, units). merges is a list of (pair, new_id) tuples in training order. units is the merged corpus as a new dict.
Input and output
| Name | Type | Shape | Meaning |
|---|---|---|---|
units | dict of tuple of int to int | any number of words | each word as a tuple of symbol ids, mapped to its frequency |
pairs | dict of tuple to int | any size | pair counts, as count_pairs returns them |
symbols | tuple of int | length 0 or more | one word |
pair | tuple of two int | (a, b) | the pair to merge |
new_id | int | scalar | the id of the merged symbol |
num_merges | int | scalar | the largest number of merges, 0 or more |
first_id | int | scalar | the id of the first merge |
count_pairsreturns a dict from pair tuples to int.best_pairreturns a tuple of two int, orNone.apply_mergereturns a tuple of int.trainreturns a tuple(list of (pair, int), dict).
Constraints
- Up to 100 words, each of length 0 to 20. Frequencies are 1 or more.
new_idand the ids fromfirst_iddo not occur in the corpus before the merge.- Do not change the input dict or the input tuples.
- Use Python and the standard library. numpy is available.
Examples
pythonunits = {(1, 2, 3): 5, (1, 2): 3, (2, 3, 2, 3): 2}
count_pairs(units)text{(1, 2): 8, (2, 3): 9, (3, 2): 2}pythonapply_merge((7, 7, 7), (7, 7), 300)text(300, 7)pythonwords = {tuple(b"low"): 5, tuple(b"lower"): 2, tuple(b"newest"): 6, tuple(b"widest"): 3}
train(words, 4)text([((101, 115), 256), ((256, 116), 257), ((108, 111), 258), ((258, 119), 259)],
{(259,): 5, (259, 101, 114): 2, (110, 101, 119, 257): 6, (119, 105, 100, 257): 3})In the first step, (101, 115) and (115, 116) both have count 9. The smaller pair (101, 115) wins the tie.
Hints
4 hintsSolution and notes
LockedPass every check with Submit to open the reference solution and the notes.
Run it on your computer
Clone the repository, install numpy and run the same checks in a terminal:
python3 scripts/practice/run.py bpe-merge-step my_answer.py
python3 scripts/practice/run.py bpe-merge-step my_answer.py --examplesStart my_answer.py from starter.py.
Your code is saved in this browser as you type. On a phone you can read and edit the code, but the checks are easier to use on a desktop.
Keyboard shortcuts
- Ctrl Enter
- Run the examples
- Ctrl Shift Enter
- Submit
- Tab / Shift Tab
- Indent or outdent the lines
- Esc then Tab
- Move the focus out of the editor
- Alt H
- Show the next hint
On a Mac, use Cmd in place of Ctrl.
Select Run to check the examples, or Submit to run every check.