← All tutorials

Tokenizers

On this page

1 How big should the vocabulary be? 2 When a tokenizer runs 3 Three algorithms and a toolkit 4 What current models use 5 Side effects of subword tokenization 6 How tokenizers are used in practice 7 References

What does a language model actually read? Not letters. A tokenizer cuts the text into pieces called tokens, looks each one up in a fixed list, the vocabulary, and hands the model one integer per token, its token id. The id picks one row of the model’s embedding table (The Transformer Block). Text to ids is encoding, ids back to text is decoding. V is the number of vocabulary entries and T the number of tokens in one input.

1tiktoken is great!2tiktoken␣is␣great!T = 63838251248838222120ids4embeddingrowsevery id lies between 0 and V − 1
Figure 1. GPT-4o’s tokenizer turns text (1) into six tokens (2), six ids (3) and six embedding rows (4). Data from Reference 12.

1 How big should the vocabulary be?

Long pieces give a short T but need a huge V; short pieces need only a small V but give a long T.

1.1 One token per word

One token per word gives the shortest T. But the list of words never ends: names, typos, new words, other languages. A real system caps the list and maps every other word to one unknown token, <unk>, which the model can neither read nor write. Sennrich, Haddow and Birch (2016) note that word vocabularies in neural machine translation, models that translate text, are usually capped somewhere between 30,000 and 50,000 words.

1.2 One token per character or byte

With one token per character or byte, nothing is unknown. UTF-8 writes every character as 1 to 4 bytes, and a byte has only 256 values. The price is a T several times longer, and attention, which compares every token with every other token (Attention), does work that grows with the square of T (Transformer Cost and Efficiency).

a611 byteéc3a92 bytes誕e8aa953 bytesお誕生日おめでとう9 characters, 27 bytes
Figure 2. Real UTF-8 byte counts. a takes 1 byte, é 2 and 誕 3, so the 9-character greeting takes 27 bytes.

1.3 Subwords sit in between

Subword tokenizers keep frequent words whole and split rare words into frequent pieces, so nothing is unknown and T stays short.

text length (million tokens)02004006001K10K100K1M10Mvocabulary size (distinct tokens)characters, 0 unknownsubwords(BPE)0 unknownwords1,079 unknownunknown = words of a held-out test textthat are not in the vocabulary
Figure 3. German training text. With 63,000 subword entries made by BPE, a merge-based subword algorithm, the text is almost as short as with words, and nothing is unknown. Data from Reference 1.

A bigger vocabulary costs parameters and buys a shorter sequence.

Nemb = V · d
The embedding table has one row of width d for each of the V entries, so its parameter count Nemb grows in step with V. The output layer has the same shape unless the two share weights. Doubling V doubles the table.
attention work ∝ T2
∝ means grows in proportion to. Every token is compared with every other token, so halving T cuts attention work about four times. A bigger V means longer tokens and so a shorter T.
costs (Gemma 2B)d = 2048V =256,128rows524,550,144parametersbuys (English text)characters per tokenLlama 2, 32K3.17Llama 3, 128K3.94so about 20% fewertokens per text
Figure 4. What a large vocabulary costs (left) and buys (right). Data from References 7, 8; the 20% is computed from 3.17 and 3.94.

The next-token loss is a categorical cross-entropy over the V entries (Cross-Entropy Loss), so V is also the number of classes.

2 When a tokenizer runs

The tokenizer is trained once, before the model, on a large collection of text called a corpus. The result is a fixed file that holds the vocabulary and the rules for splitting text with it (splitting new text with the merge list shows them for BPE). The model’s embedding rows are tied to these exact ids, so a new tokenizer means training the model, or at least its embeddings, again. API use “is priced by token” (Reference 12), so a tokenizer that needs more tokens for a text makes it cost more and fit less.

Each call encodes one text on its own, before the model runs. During generation the tokenizer only decodes each new id. It keeps no state between calls: unless sampled splits are turned on while a model trains (sampling a different split each time), the same text always gives the same ids.

1once, before the modeltrain on a corpusa fixed filevocabularyand rules2model trainingencode every document3every prompt and replyencode, then decodesamefile
Figure 5. Trained once (1), then the same file runs on every document (2) and every prompt and reply (3).

3 Three algorithms and a toolkit

BPE and WordPiece grow a vocabulary by merging pieces (byte-level BPE is BPE run on bytes), Unigram shrinks a large list by pruning, and SentencePiece is a toolkit that runs either kind on raw text.

BPE, WordPiece and Unigram are each built step by step in How Subword Tokenizers Are Built: BPE, WordPiece and Unigram.

TermWhat it meansExample or where used
mergeBPE joins the adjacent pair of pieces that appears most often into one new token, and repeats; byte-level BPE starts from the 256 byte valuesu g becomes ug
scoreWordPiece merges like BPE but picks the pair that occurs together more often than its parts’ own counts predict: the pair’s count divided by the product of its two parts’ countsBERT
pruningUnigram starts from a big list of pieces and drops the ones the corpus needs leastT5
##WordPiece’s mark on a piece that continues a wordanti ##dis
[UNK], <unk>the unknown token, for text the vocabulary cannot spell; BERT writes [UNK]a word with no matching piece
▁SentencePiece writes each space as this visible symbol, on the front of the next piece▁is
byte fallbacka character missing from the vocabulary is written as its UTF-8 bytes instead of the unknown token誕 as 3 bytes
byte fragmenta byte-level token that holds only part of a character, not text on its own; hatched in Figure 121 of the 3 bytes of 誕
Figure 6. What a merge, a score and pruning do, and the markers the tokenizers on this page write into their tokens.

4 What current models use

Released vocabularies grew from about 30K entries to about 262K, and byte-level BPE is the most common choice among them. The 2025 releases keep the same families: Qwen3 uses byte-level BPE and Gemma 3 uses SentencePiece (References 18, 19).

tiktoken, OpenAI’s tokenizer library, names OpenAI’s byte-level BPE vocabularies by encoding: r50k_base, the same vocabulary as GPT-2’s, for the original GPT-3, p50k_base for Codex and text-davinci-002 and text-davinci-003, cl100k_base for GPT-3.5 and GPT-4, and o200k_base for GPT-4o (References 12, 13). It maps GPT-5 to o200k_base and the open gpt-oss models to o200k_harmony. o200k_harmony keeps the same merges and adds special tokens, entries that mark structure rather than text (Section 5.6); 1,081 of its 201,088 ids are reserved placeholders (Reference 13).

BERT30,522 [4, 16]T532,000 [5, 11]Llama 232K [6]GPT-250,257 [3]GPT-350,257 [13]GPT-3.5, GPT-4about 100K [13]Llama 3128K [7]DeepSeek-V3128K [10]Qwen2151,646 [9]Qwen3151,669 [18]GPT-4o, GPT-5about 200K [13]gpt-oss201,088 [13]Gemma256,128 [8, 11]Gemma 3about 262K [19]SentencePiece UnigramWordPieceSentencePiece BPEbyte-level BPEapproximate size
Figure 7. Vocabulary size per model through 2025, colored by algorithm. Gemma and Gemma 3 are drawn as SentencePiece BPE (References 8, 11, 19).

5 Side effects of subword tokenization

A vocabulary learned from frequent text decides how numbers, other languages and spaces are split, and the model sees only those splits.

5.1 Numbers split in different ways

r50k_base and p50k_base learned number tokens by plain BPE, so which numbers get one token is an accident; Singh and Strouse (2024) note that in p50k_base “710 may get a dedicated token, while 711 will not”. cl100k_base and o200k_base cut digit runs into chunks of at most three digits, left to right, with no space in front (Reference 13). Llama 2 and Gemma split every number into single digits (References 6, 8).

toy3-digit chunks, left to right83020801commas every 3 digits from the right8,302,0802single digits8302080
Figure 8. Toy. Chunks from the left leave a lone digit at the end (1); commas line chunks up with place value (2).

The paper gave gpt-3.5-turbo and GPT-4 (March 2023 versions) 90 addition problems with 7 to 9 digit numbers and 8 solved examples in the prompt (8-shot), always took the most likely next token (greedy decoding), and changed only the digit grouping.

gpt-3.5-turbo75.6%97.8%GPT-484.4%98.9%plain digits, 8302080commas, 8,302,080
Figure 9. Commas only change the tokens, yet addition accuracy jumps. Data from Reference 14.

5.2 Other languages cost more tokens

A tokenizer trained mostly on English has long tokens for English and short pieces for other scripts. Petrov et al. (2023) counted tokens for the same sentences translated into each language and divided by the English count.

GPT-2 vocabularycl100k_baseEnglish11French2.001.60German2.141.58Chinese (Simplified)3.211.91Japanese3.002.30Bulgarian5.512.64Standard Arabic4.403.04Burmese16.8911.70Shan18.7615.05tokens relative to English, which is 1
Figure 10. The same text needs up to 18.76 times as many tokens; cl100k_base narrows the gap. Data from Reference 15.

5.3 A space belongs to the token after it

In GPT tokenizers “spaces are usually grouped with the starts of words” (Reference 12), so the same word is a different token with and without a space in front. SentencePiece does the same with ▁.

r50k_base2␣+␣2␣=␣412two different tokenso200k_base2␣+␣2␣=␣43
Figure 11. In r50k_base, 2 (1) and 2 after a space (2) are different tokens; o200k_base gives that space its own token (3).

5.4 One string, many vocabulary sizes

A byte-level BPE vocabulary holds the 256 byte values plus one entry per merge (counting pairs and merging). To encode, the text is first cut into chunks (runs of letters, digits or other symbols, each with the space before it, and endings like 's), and no merge crosses a chunk border. Each chunk starts as single bytes, and the merges are replayed inside it in the order they were learned (splitting new text with the merge list). GPT-2 keeps 50,000 merges; GPT-4o’s tokenizer, about 200,000 entries, splits “tiktoken is great!” into six tokens (Figure 1). Keeping fewer merges gives a smaller V and, usually, a longer T, the trade-off of Figure 3. A merge exists only for byte pairs that were frequent in the training text.

Figure 12. Each added entry joins two tokens, so T (2) never grows with V.

5.5 Glitch tokens

Rumbelow and Watkins (2023) found tokens in the 50,257-token vocabulary shared by GPT-2 and GPT-3 that make models behave strangely. One explanation they suggest is that these tokens were rarely or never seen in training, so their embeddings stayed close to their starting values.

GPT-2 and GPT-3 vocabulary␣SolidGoldMagikarpid 43453bert-base-uncasedsolid##gold##ma##gi##kar##p
Figure 13. One token in GPT-2’s vocabulary, six ordinary pieces in BERT’s. Data from References 16, 17.

5.6 Special tokens and chat templates

Special tokens are vocabulary entries that never come from text; they mark structure. GPT-2’s <|endoftext|> is id 50256, and BERT wraps every input in [CLS] and [SEP]. The tokenizer must match the model: id 2212 means ␣great only under o200k_base. Chat models are trained on conversations wrapped in control tokens, special tokens that mark who is speaking. A chat template writes them, and with the wrong ones models perform “drastically worse” (Reference 2).

messagessystemYou are a friendly chatbot who alwaysresponds in the style of a pirateuserHow many helicopters can a human eatin one sitting?apply_chat_templatetext the model reads<|system|>You are a friendly chatbot who alwaysresponds in the style of a pirate</s><|user|>How many helicopters can a human eatin one sitting?</s><|assistant|>1
Figure 14. The template turns messages into one sequence; the last line (1) asks the model to answer. Data from Reference 2.

CTC adds a blank token to its vocabulary (CTC Loss), a special token that never comes from text, like the ones here. The Q-Former’s outputs enter the language model as soft prompts, vectors that act like extra tokens without ids, placed before the text token embeddings (From BLIP to the Q-Former).

6 How tokenizers are used in practice

You load the tokenizer that ships with the model; you train one only when you pretrain a model (training your own vocabulary). The official code lives in tiktoken, Hugging Face tokenizers and SentencePiece.

6.1 Counting tokens with tiktoken

Code 1 loads GPT-4o mini’s encoding, turns the string of Figure 1 into ids and back, and counts tokens with a named encoding.

import tiktoken

encoding = tiktoken.encoding_for_model("gpt-4o-mini")
ids = encoding.encode("tiktoken is great!")
print(ids)  # [83, 8251, 2488, 382, 2212, 0]
print(encoding.decode(ids))  # tiktoken is great!
print([encoding.decode_single_token_bytes(t) for t in ids])
# [b't', b'ikt', b'oken', b' is', b' great', b'!']

def num_tokens_from_string(string, encoding_name):
    encoding = tiktoken.get_encoding(encoding_name)
    return len(encoding.encode(string))

print(num_tokens_from_string("tiktoken is great!", "o200k_base"))  # 6
  1. 1encoding_for_model picks o200k_base for gpt-4o-mini.
  2. 2The ids of Figure 1 and the way back to the string.
  3. 3Bytes per token, with the space inside b' is'. Decoding a single token can be lossy when it is not a whole UTF-8 character, so this call returns bytes.
  4. 4The cookbook’s counting function with a named encoding.

6.2 Chat templates in Hugging Face

Code 2 loads the tokenizer that ships with a chat model and builds the prompt of Figure 14.

from transformers import AutoTokenizer

tok = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta")
messages = [
    {"role": "system", "content": "You are a friendly chatbot who always responds in the style of a pirate"},
    {"role": "user", "content": "How many helicopters can a human eat in one sitting?"},
]
prompt = tok.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
print(prompt)
prompt_ids = tok(prompt, add_special_tokens=False)["input_ids"]
  1. 1The tokenizer that matches the model.
  2. 2The messages of Figure 14.
  3. 3The template writes the control tokens; add_generation_prompt=True adds the last line.
  4. 4The text already holds its special tokens, so add_special_tokens=False stops them being added twice.

Every tokenizer here works from a vocabulary learned once from a corpus. How is that list of pieces chosen, and why do BPE, WordPiece and Unigram split the same word differently? How Subword Tokenizers Are Built: BPE, WordPiece and Unigram builds each one step by step.

7 References

  1. Sennrich, R., Haddow, B., Birch, A. (2016). Neural Machine Translation of Rare Words with Subword Units. ACL 2016. arXiv:1508.07909.
  2. Hugging Face. Chat templates.
  3. Radford, A., et al. (2019). Language Models are Unsupervised Multitask Learners. OpenAI.
  4. Devlin, J., et al. (2019). BERT. NAACL 2019. arXiv:1810.04805.
  5. Raffel, C., et al. (2020). Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer. JMLR. arXiv:1910.10683.
  6. Touvron, H., et al. (2023). Llama 2. arXiv:2307.09288.
  7. Llama Team (2024). The Llama 3 Herd of Models. arXiv:2407.21783.
  8. Gemma Team (2024). Gemma. arXiv:2403.08295.
  9. Qwen Team (2024). Qwen2 Technical Report. arXiv:2407.10671.
  10. DeepSeek-AI (2024). DeepSeek-V3 Technical Report. arXiv:2412.19437.
  11. Hugging Face. Summary of the tokenizers.
  12. OpenAI Cookbook. How to count tokens with tiktoken.
  13. OpenAI. tiktoken, openai_public.py and model.py.
  14. Singh, A. K., Strouse, D. J. (2024). Tokenization counts. arXiv:2402.14903.
  15. Petrov, A., et al. (2023). Language Model Tokenizers Introduce Unfairness Between Languages. NeurIPS 2023. arXiv:2305.15425.
  16. bert-base-uncased tokenizer.json, Hugging Face Hub.
  17. Rumbelow, J., Watkins, M. (2023). SolidGoldMagikarp II.
  18. Qwen Team (2025). Qwen3 Technical Report. arXiv:2505.09388.
  19. Gemma Team (2025). Gemma 3 Technical Report. arXiv:2503.19786.