A small, readable Byte-Pair Encoding implementation in Go. The algorithm behind most modern subword tokenizers, without pulling in a framework.
Algorithm (as implemented)#
- Seed tokens. Split the corpus into words. Each word becomes a char sequence plus a word-boundary marker (
_). - Count adjacent pairs across the corpus.
- Merge the most frequent pair into a new token everywhere it shows up.
- Repeat for a fixed number of merges (or until no pairs remain).
- Rebuild a vocabulary from the resulting tokens.
Toy demo corpus in main.go:
low lower lowestAfter a couple of merges you can watch common digraphs (e.g. lo, ow) collapse into single tokens. Same pressure that grows real BPE merges on large corpora, just tiny.
Layout#
| File | Role |
|---|---|
main.go | pair counting, merge loop, vocab update, demo main |
NOTES.txt | step-by-step BPE notes I kept while writing the code |
Makefile | build helpers |
No external ML deps. Just stdlib (fmt, strings) so the data structures stay obvious.
Why it exists#
Tokenization is easy to treat as a black box (tiktoken, HF tokenizers). Implementing BPE once in a systems language makes merge tables, word boundaries, and vocab growth concrete. Good background for any LM or embedding work.