Byte Pair Encoding (BPE): How It Works and How to Support Multiple Languages

Published on October 28, 2026

Byte Pair Encoding (BPE): How It Works and How to Support Multiple Languages

A large language model's tokenizer divides text into units called tokens and maps them to integer IDs. Two translations of the same sentence can take very different numbers of tokens, leaving room for different amounts of text in a fixed context window. For a model that generates one token at a time, a longer representation also requires more generation steps.
Byte Pair Encoding (BPE) learns tokens by repeatedly merging frequent adjacent pairs in training text. Training chooses merges by frequency; encoding applies the learned rules in a fixed priority order. Frequent strings become single tokens, so the language mix of the training data influences how compactly each language is represented.
For multilingual BPE, character coverage and compact representation require different choices. Starting from all 256 byte values covers every character that UTF-8 can represent. Learning useful merges then reduces the number of tokens those characters need. Training weights and merge selection control that allocation when building a new tokenizer; extending an existing model also requires compatible merge rules and weights for the new IDs.

1. Vocabulary training

A tokenizer's vocabulary is its set of available tokens. BPE begins with small units such as characters and learns longer tokens from their occurrences in the training text. The character-based approach used by Sennrich et al. for neural machine translation[1] repeats these steps:
  1. Count every adjacent pair of tokens and select the most frequent pair.
  2. Join the pair into a new token, add it to the vocabulary, and replace occurrences of the pair from left to right without overlap.
  3. Save the merge rule and its position in the learning order, then update the pair counts.
Training stops at the target vocabulary size or when no pair remains to merge. Earlier tokens remain available, so a new word made from known characters can still be represented by shorter tokens.

1.1. A four-word example

Suppose the training data contains low 5 times, lower 2 times, newest 6 times, and widest 3 times. Start from individual characters and allow merges only within words. To make the example reproducible, ties go to the smaller pair of token IDs.

Sort the initial characters by Unicode code point: d, e, i, l, n, o, r, s, t, w. Give them IDs 0 through 9, and assign new tokens IDs from 10 onward. For equal pair counts, compare the left IDs first, then the right IDs; the smaller pair wins.

For example, e + s has IDs (1, 7) and s + t has (7, 8), so e + s wins. The four words and their frequencies come from Algorithm 1 of Sennrich et al.[1]; this example omits their end-of-word symbol and uses the tie-breaking rule above.

  1. [1] Rico Sennrich, Barry Haddow, Alexandra Birch, "Neural Machine Translation of Rare Words with Subword Units," ACL, 2016.
The most frequent pairs are initially e + s and s + t. Both appear in newest and widest, giving each a count of \(6+3=9\). The tie-breaking rule selects e + s → es. Both words now end in es | t, where | marks a token boundary. The new pair es + t also occurs 9 times and wins the next round, creating est.
The next two merges build low, shared by the 5 occurrences of low and the 2 of lower. A rule's rank records when it was learned, starting at 0. Frequencies below are counted immediately before each merge; output IDs identify the new tokens.
RankMerge ruleFrequencyOutput ID
0e + s → es910
1es + t → est911
2l + o → lo712
3lo + w → low713
After four merges, low is one token, lower is low | e | r, and both newest and widest end in the token est. The vocabulary contains 14 entries: 10 initial characters and 4 merged tokens. Here est coincides with an English suffix; the selection rule needed only its frequency.

1.2. Pair frequency and sequence length

Each replacement removes one token from the sequence. A frequent pair offers many opportunities for that saving, which is why frequency guides training. Merging also changes the neighboring pairs: creating es removes s + t and introduces es + t. BPE updates the pair counts and makes its next choice from the new sequence. This is a greedy procedure: it selects the current most frequent pair without looking ahead to later merges.

Counts include overlapping positions, while replacements do not. In aaa, a + a occurs twice, but only one occurrence can be replaced. Pair frequency can therefore exceed the number of tokens a merge removes.

Let \(f(s)\) be the number of times the token sequence \(s\) occurs in the training data. The frequency of the pair \((a,b)\) is then

\[ C(a,b)=\sum_s f(s)\sum_{i=1}^{|s|-1} \mathbf{1}[(s_i,s_{i+1})=(a,b)], \]

where \(|s|\) is the current length of the sequence, \(s_i\) is its \(i\)-th token, and \(\mathbf{1}\) is the indicator function, equal to 1 when its condition holds and 0 otherwise.

The inner sum counts matching positions in one sequence; the outer sum weights that count by the sequence's frequency. Thus the 5 occurrences of low initially contribute 5 to both l + o and o + w.

2. Encoding with the learned merge ranks

Encoding starts from the same initial units used in training. Among the pairs currently adjacent in the input, BPE applies the rule with the smallest rank, giving earlier rules priority. It repeats this process until no rule applies.
For lowest, which was absent from the training data, the initial sequence is l | o | w | e | s | t. Two learned rules apply: e + s at rank 0 and l + o at rank 2. Rank 0 wins, and the resulting es enables es + t at rank 1. The remaining merges create lo and then low. The result is low | est: an unseen word represented by two learned tokens.
lowest is split into l, o, w, e, s, and t; rank 0 forms es, rank 1 forms est, rank 2 forms lo, and rank 3 forms low, giving the two tokens low and est. The final IDs are 13 and 11.
Figure 1: Encoding lowest with fixed merge ranks Starting from characters, the four learned rules reduce lowest to low | est. Orange marks each merge. The final row gives the token IDs in text order.
The model receives [13, 11], the IDs for low and est in text order. Rank controls the order of operations; ID identifies a token in the model's vocabulary. Some implementations use the same number for both roles.

2.1. Merge order and longest match

Merge priority can make BPE start in the middle of the input. Suppose the only rules are b + c → bc, a + b → ab, and c + d → cd, in that order of priority. For abcd, BPE first creates bc and stops at a | bc | d. Choosing the longest vocabulary match from left to right would instead give ab | cd. The same vocabulary permits both segmentations; BPE's merge order selects the first, even though it uses an extra token.

2.2. A minimal encoder

A short Python implementation makes the rule selection explicit. Store each adjacent ID pair with its rank and output ID. On each iteration, scan for applicable rules, select the smallest rank, and replace that pair. If the same pair appears more than once, choose its leftmost occurrence.

The dictionary below contains the four rules from §1.1. Each value is (rank, output ID).

def encode_ids(initial_ids, rules):
    sequence = list(initial_ids)
    while len(sequence) >= 2:
        candidates = [
            (rules[pair][0], i, rules[pair][1])
            for i, pair in enumerate(zip(sequence, sequence[1:]))
            if pair in rules
        ]
        if not candidates:
            break
        # Pick the smallest rank, then the leftmost position.
        _, i, output = min(candidates)
        sequence[i:i + 2] = [output]
    return sequence

# Assign IDs 0 through 9 to the initial characters.
alphabet = {char: i for i, char in enumerate("deilnorstw")}
rules = {
    (1, 7): (0, 10),   # e  + s → es
    (10, 8): (1, 11),  # es + t → est
    (3, 5): (2, 12),   # l  + o → lo
    (12, 9): (3, 13),  # lo + w → low
}
initial_ids = [alphabet[char] for char in "lowest"]
print(encode_ids(initial_ids, rules))  # [13, 11] = low | est

The function also works with byte IDs and their merge rules. The code and data archive includes training, decoding, and the experiments in §4.2; it requires only the Python standard library.

The full scan repeats work after every merge. An encoder can reduce this work on long inputs by updating only neighboring candidates and using a priority queue to select the next pair.

Let \(n\) be the number of initial tokens and assume constant-time ID-pair lookup. If \(m\) merges occur, the Python code performs up to \(O(n)\) work per merge to scan candidates and modify the list. Including the first scan gives \(O(n+mn)\). Since \(m\leq n-1\), the worst case is \(O(n^2)\).

With a linked structure for adjacency and a priority queue, each merge creates only a constant number of new candidates. There are \(O(n)\) candidates over the whole run, each costing \(O(\log n)\) to insert or remove. This gives \(O(n\log n)\), assuming constant-time ID-pair lookup and adjacency updates.

For short inputs, array scans can be faster because they avoid the overhead of these structures. tiktoken 0.12.0 uses arrays and cites cache locality on short pieces as its reason[9]. Runtime comparisons should therefore use the piece lengths that the tokenizer actually processes after pre-tokenization (§3.2).

  1. [9] OpenAI, "tiktoken: BPE implementation (v0.12.0)," GitHub, 2025.

3. Characters, bytes, and preprocessing

3.1. Byte-level BPE and unseen characters

A vocabulary built from observed characters has a gap: an unseen character has no initial token. Byte-level BPE, as used in GPT-2[2], starts from all 256 byte values and applies merges to the input's UTF-8 bytes. That base vocabulary can represent any valid UTF-8 text, including characters absent from training.
In UTF-8, A occupies 1 byte, 猫 ("cat" in Chinese and Japanese) occupies 3, and 🙂 occupies 4[3]. Before any merges, these require 1, 3, and 4 tokens respectively. Learned merges can combine the bytes of a character or join several characters. They can also leave a token boundary inside a character: BPE operates on adjacent bytes without requiring each token to be valid UTF-8 on its own.
The code points and 8 UTF-8 bytes of A猫🙂: A is 41, 猫 is E7 8C AB, and the emoji is F0 9F 99 82. The illustrative tokens are 41, E7 8C, AB, and F0 9F 99 82, with a boundary inside 猫.
Figure 2: Character boundaries and token boundaries The rows show A猫🙂 as 3 Unicode code points, 8 UTF-8 bytes, and an illustrative segmentation into 4 tokens. The token boundary inside 猫 splits its byte sequence into E7 8C and AB. Byte values are hexadecimal.
To decode the IDs, concatenate their byte sequences first, then interpret the result as UTF-8. In Figure 2, E7 8C and AB together recover 猫. Decoding either token separately can raise an error or insert replacement characters, depending on the decoder's error handling.
A character-based tokenizer can also cover unseen characters through byte fallback. It represents a character missing from its vocabulary as individual UTF-8 byte tokens, while using its learned character tokens elsewhere.

SentencePiece enables this behavior with byte_fallback[10]. The 256 byte entries count toward the requested vocabulary size, leaving fewer entries for characters and longer strings. Here bytes cover missing characters; in byte-level BPE, bytes are the starting units for learning every merge.

  1. [10] Google, "SentencePiece Training Options," SentencePiece Documentation, 2026.

3.2. Normalization and pre-tokenization

BPE runs inside a larger text-processing pipeline. Hugging Face Tokenizers, for example, applies normalization, pre-tokenization, a segmentation algorithm such as BPE, and post-processing[4]. These stages determine the text BPE sees and the boundaries within which it can merge.
Normalization gives equivalent representations a common form. The accented letter é can be one code point or e followed by a combining accent; Unicode NFC maps both to the same sequence. NFKC also applies compatibility mappings, such as converting full-width A to A[5]. This pools the variants' training counts and gives them the same encoding. It also discards their original distinction, so decoding recovers the normalized text.
Pre-tokenization divides text into pieces that BPE processes separately. If it splits hello world into hello and world, merges can build tokens within either piece but cannot cross the boundary. Increasing the vocabulary size leaves that restriction in place.
GPT-2 separates character classes such as letters, digits, and punctuation, with an exception that allows spaces to join the following text[2]. The choice of boundaries matters across languages. Splitting only at spaces usually separates English words, while leaving an unspaced Japanese or Chinese sentence as one piece in which merges can cross word boundaries.
Special tokens, such as document-boundary markers, have rules separate from ordinary text. For applications that must recover the exact input, check the normalization, whitespace, and special-token settings. Encode and decode representative inputs, including literal spellings of special tokens, and compare the result with the original.
ImplementationSegmentation componentsSettings to check
tiktoken[9]A rank table keyed by byte sequences, plus a regular expression for pre-tokenizationThe encoding name, special tokens, and the correspondence between ranks and IDs
SentencePiece[10]The segmentation algorithm, normalization, and other settings saved in one model fileCharacter coverage, byte fallback, normalization, and whitespace handling
Hugging Face Tokenizers[4]A normalizer, a pre-tokenizer, a segmentation model such as BPE, and a decoderThe settings of each component and how added tokens are matched

SentencePiece defaults to a custom NFKC-based rule set. Its identity option disables character normalization; whitespace has separate controls[11]. Check those too: collapsing consecutive spaces, for example, loses information even when the characters are otherwise preserved.

  1. [9] OpenAI, "tiktoken: BPE implementation (v0.12.0)," GitHub, 2025.
  2. [10] Google, "SentencePiece Training Options," SentencePiece Documentation, 2026.
  3. [4] Hugging Face, "The tokenization pipeline," Tokenizers Documentation, 2026.
  4. [11] Google, "Text Normalization in SentencePiece," SentencePiece Documentation, 2026.

4. Language mix and token counts

4.1. Training weights and shared strings

Ordinary BPE sums pair counts across the training corpus. A language with more data contributes more occurrences, making its frequent strings more likely to receive vocabulary entries. Per-language weights change that contribution: multiply each language's pair counts by its weight, then sum them to choose the next merge.

For pair \((a,b)\), let \(C_\ell(a,b)\) count its occurrences in language \(\ell\), and let \(w_\ell\) be that language's training weight. Select the pair with the largest weighted count:

\[ C(a,b)=\sum_\ell w_\ell C_\ell(a,b). \]

A weight of 2 gives the same counts as including every training sentence in that language twice. The weights stay fixed during training, while the counts change as merges alter the sequences.

Vocabulary entries can also serve several languages. Shared strings pool their counts, helping their merges rank highly. Writing systems, word forms, and pre-tokenization boundaries affect how much sharing is possible and which strings recur. Equal amounts of training data therefore need not produce equal token counts for equivalent texts.

4.2. The effect of training weights

To illustrate the effect, I trained three byte-level BPE tokenizers on the same small set of sentences I wrote in five languages. Each has 512 vocabulary entries; only the language weights change. English accounts for 80%, 50%, or 20% of the weighted UTF-8 training bytes, with the remainder divided equally among the other four languages. Evaluation uses 8 separate sentences per language, expressing roughly the same content across languages.

The dataset contains 16 training sentences and 8 evaluation sentences per language. The translations have not been professionally checked; the dataset is intended to demonstrate the mechanism.

Let \(B_\ell\) be the total UTF-8 bytes of the training sentences in language \(\ell\), and \(p_\ell\) its target byte share. Each sentence of that language receives the weight \(100000p_\ell/B_\ell\). The shares \(p_\ell\) sum to 1, so the weighted byte total is 100,000 in every condition. The weights are exact Python Fraction values, and no random sampling is involved. The 50% English condition takes the square root of each share in the 80% condition and normalizes the results to sum to 1.

The initial vocabulary is the 256 byte values, and 256 merges are learned. There is no character normalization; merges cannot cross sentence boundaries but can cross spaces within a sentence. Evaluation applies no weights and sums the token counts of the 8 sentences in each language.

Extract the code and data archive and run this command from the extracted directory. It runs the tests and writes the experiment outputs to results/.

python3 code/run_all.py

The inputs are in data/toy_parallel.json, and the table values are in results/multilingual_metrics.csv. The code uses only the Python standard library. Its README is in Japanese; code/bpe_core.py contains the minimal byte-level implementation, and code/minimal_bpe.py also supports characters.

Total tokens for 8 evaluation sentences per language; vocabulary size 512
Language80% English50% English20% English
(equal shares)
English137140184
Japanese310259208
Chinese266233177
Arabic344229189
Hindi452347259
Reducing the English training share from 80% to 20% lowers the Japanese count from 310 to 208 and raises the English count from 137 to 184. The weights change which strings occupy the 512 entries. Even with equal byte shares, the counts differ across languages.

5. Vocabulary allocation with PA-BPE

Fixed weights choose each language's influence before training starts. Parity-aware BPE (PA-BPE), proposed by Foroutan et al.[6], revisits that choice after every merge. Its variant using parallel development data prioritizes the language whose translations currently require the most tokens.
Until the vocabulary reaches its target size, it repeats three steps:
  1. Select the language with the highest mean token count per sentence on the development set.
  2. In that language's training data, select the most frequent adjacent pair.
  3. Apply the merge to the training and development data of every language.
The parallel development set makes the language comparison meaningful because its sentences express the same content. Pair counts come from a separate training corpus, which only needs language labels. Every language shares the resulting merge rules, and encoding follows the usual BPE procedure.
The language with the largest mean token count is selected on parallel development data, and the most frequent pair is selected in that language's training data. The merge is applied to the training and development data of all languages, segmentations and statistics are updated, and the loop repeats until the target vocabulary size.
Figure 3: Vocabulary training in PA-BPE Parallel development sentences determine which language to prioritize; that language's training data supplies the pair to merge. Applying the merge across all languages updates the sequences for the next choice. This depicts the parallel-data variant in §4 of Foroutan et al.[6].
In the paper's 30-language experiment with a vocabulary of 128,000, PA-BPE reduced the disparity in token counts while keeping the total count on FLORES+ parallel text nearly unchanged[6].

Table 1 reports tokenizers trained on an unbalanced 30-language sample of FineWeb2 and evaluated on the corresponding FLORES+ languages[6]. Both vocabularies have 128,000 entries.

MethodGini coefficientCompression
(sentences per token)
BPE0.0640.0275
PA-BPE0.0070.0276

A Gini coefficient closer to 0 means less disparity in token counts across languages. Compression divides the number of sentences by the total token count, so a larger value means shorter token sequences for this fixed evaluation corpus.

  1. [6] Negar Foroutan, Clara Meister, Debjit Paul, Joel Niklaus, Sina Ahmadi, Antoine Bosselut, Rico Sennrich, "Parity-Aware Byte-Pair Encoding: Improving Cross-lingual Fairness in Tokenization," ACL, 2026.
In a separate model study, the authors tested hybrid variants that begin with ordinary BPE and switch to PA-BPE partway through vocabulary training. Across 12 multilingual benchmarks with 3-billion-parameter models, they reported no consistent performance decline relative to ordinary BPE[6].

Table 2 compares ordinary BPE with two variants: hybrid learns the first half of its merges with ordinary BPE and the second half with PA-BPE; hybrid+window also limits how often the same language can be selected within a window of recent merges[6].

The tokenizers were trained on mC4, and the models on 100 billion FineWeb2 tokens. Evaluation covered 22 languages. These model results use different tokenizer training data and PA-BPE variants from the tokenizer-only comparison in Table 1.

  1. [6] Negar Foroutan, Clara Meister, Debjit Paul, Joel Niklaus, Sina Ahmadi, Antoine Bosselut, Rico Sennrich, "Parity-Aware Byte-Pair Encoding: Improving Cross-lingual Fairness in Tokenization," ACL, 2026.

6. Extending an existing BPE tokenizer

6.1. Merge conflicts and continued BPE training

For a pretrained model, adding tokens while preserving existing IDs lets each old token keep its corresponding model weights. The new merge rules must work with the old ones: rules learned independently can conflict, leaving added tokens unreachable through merging.
Consider two tokenizers that use the same IDs for shared characters. Combine exactly these three rules, keeping the original rule first. As in the encoder in §2.2, each rule specifies a pair of input IDs and one output ID.
RankMerge ruleSource
0a + b → abOriginal tokenizer
1b + c → bcSecond tokenizer
2a + bc → abcSecond tokenizer
Encoding abc now gives a | b | c → ab | c and stops. The first merge consumes the b needed to form bc, blocking the path to abc. The rule that would complete this sequence is ab + c → abc.
Continued BPE training, proposed by Purason et al.[7], learns from the segmentation the existing tokenizer actually produces. Encode the new language's training text with that tokenizer, then resume pair counting and merging from those ID sequences, appending the new rules after the old ones. In the example, ab | c supplies the candidate ab + c. The original pre-tokenization boundaries still constrain the new merges.
Verify the extension with added strings both in isolation and inside longer text. Some implementations look up a whole piece before applying merges. Direct lookup can return one token for a string whose merge path fails when it appears inside a larger piece.

In Hugging Face Tokenizers 0.22.1, BPE with ignore_merges=True and dropout disabled returns the ID directly if the whole pre-tokenized piece is in the vocabulary[12]. With the three rules above, abc succeeds by direct lookup. Add the initial character x and pass xabc as one piece, absent from the vocabulary: merging yields x | ab | c.

tiktoken 0.12.0 also checks whole pieces first. It then finds merge candidates by looking up the concatenated bytes of neighboring tokens in a rank table[9]. That differs from registering only a specific ID pair such as a + bc; the conflict example depends on the explicit pair rules stated in the body.

The downloadable examples reproduce the pair-rule conflict in results/integration_conflicts.json.

  1. [12] Hugging Face, "Tokenizers: BPE model (v0.22.1)," GitHub, 2025.
  2. [9] OpenAI, "tiktoken: BPE implementation (v0.12.0)," GitHub, 2025.

6.2. Model weights for the new IDs

Each added ID needs an input embedding and a row in the model's output matrix. Append those rows while retaining the existing rows at their original IDs. One initialization method splits each new token with the old tokenizer and averages the corresponding vectors[7]. Continued pretraining then teaches the model to use the new tokens in context.
Keeping the old rows preserves their association with the old tokens, but model behavior also depends on the sequences it receives and the output candidates it scores. New segmentations change token positions; new output candidates change the softmax denominator and hence the probabilities of existing tokens. Evaluate the adapted model on both the added language and the languages it must continue to support.

7. Evaluating a tokenizer change

7.1. Token counts across languages

Use the same evaluation text to compare tokenizers, and aligned translations to compare languages. Report the tokenizer and dataset: text domain and translation choices both affect the counts.
Report absolute counts alongside ratios. In §4.2, the Japanese-to-English ratio falls from \(310/137\approx2.26\) to \(208/184\approx1.13\) when training changes from 80% English to equal byte shares. Both shorter Japanese sequences and longer English sequences contribute to the smaller ratio.

7.2. Vocabulary size and compute cost

For a fixed text, fewer tokens mean fewer positions for the model to process. Dense attention over the full sequence includes work proportional to the square of its length, and generating one token at a time takes fewer steps when the output has a shorter encoding.
Increasing the vocabulary adds a different cost. The input embedding matrix has one vector per ID: \(Vd\) weights for vocabulary size \(V\) and dimension \(d\). At \(d=4096\) and 2 bytes per weight, adding 50,000 entries requires about 410 MB more weights per matrix. A separate output matrix grows by the same amount.

The added parameters number \(50000\times4096=204800000\). Stored at 2 bytes per element, as in the 16-bit floating-point format BF16, they take \(409600000\) bytes, or 409.6 MB in decimal megabytes. With separate input and output matrices, the total increase is 819.2 MB.

These figures count weights only. Training also needs gradients, optimizer state, and other memory, and actual memory use depends on the training method.

A larger vocabulary also requires more work to score every output candidate. Vocabulary expansion trades potential sequence savings against larger matrices and more output scores. Measure the combined effect on runtime and memory with the intended model and workload.

7.3. Model quality

Evaluate quality on the intended tasks, such as question answering or translation. The PathPiece study illustrates why token counts are insufficient for this decision. Its tokenizer selects the shortest segmentation for a fixed vocabulary, but the experiments did not support the hypothesis that fewer tokens yield better downstream performance[8].
For prediction loss, use a common unit such as bits per byte. Per-token loss changes its unit when the tokenizer changes. Score the same evaluation text, and confirm that encoding and decoding preserve it; unknown-token substitutions or lossy preprocessing would change the text being evaluated.

To compute bits per byte (BPB), sum the negative log-likelihood of the evaluation text's token sequence in bits, then divide by the text's UTF-8 byte count. For the same text, a lower BPB means the model assigns a higher probability to its token sequence.

Perplexity exponentiates mean loss per token, so it retains the tokenizer-dependent unit. BPB instead gives the compared token sequences a shared denominator.

When training models for a comparison, choose the budget that answers the practical question: a fixed amount of text, a fixed token count, or fixed compute. At a fixed token count, shorter encodings let the model read more text; at a fixed amount of text, they reduce the number of training tokens.

Conclusion

A new multilingual tokenizer can spend its vocabulary budget differently by changing training weights or using PA-BPE. An existing model can gain tokens through continued BPE training, with corresponding model adaptation. Parallel-text counts reveal where these changes help; task quality, runtime, and memory measurements determine whether they are useful for the application.

References

  1. [1] Rico Sennrich, Barry Haddow, Alexandra Birch, "Neural Machine Translation of Rare Words with Subword Units," ACL, 2016. (§3.2 and Algorithm 1; the original application of character-level BPE to neural machine translation)
  2. [2] Alec Radford, Jeffrey Wu, Rewon Child, David Luan, Dario Amodei, Ilya Sutskever, "Language Models are Unsupervised Multitask Learners," OpenAI Technical Report, 2019. (§2.2 describes GPT-2's byte-level BPE and pre-tokenization)
  3. [3] François Yergeau, "UTF-8, a transformation format of ISO 10646," RFC 3629, 2003.
  4. [4] Hugging Face, "The tokenization pipeline," Tokenizers Documentation, 2026.
  5. [5] Ken Whistler, "Unicode Normalization Forms (Unicode 18.0.0, Revision 58)," Unicode Standard Annex #15, 2026.
  6. [6] Negar Foroutan, Clara Meister, Debjit Paul, Joel Niklaus, Sina Ahmadi, Antoine Bosselut, Rico Sennrich, "Parity-Aware Byte-Pair Encoding: Improving Cross-lingual Fairness in Tokenization," ACL, 2026. (ACL 2026 final version; the training procedure is in §4, compression and Gini coefficients in Table 1, and model quality in Table 2)
  7. [7] Taido Purason, Pavel Chizhov, Ivan P. Yamshchikov, Mark Fishel, "Teaching Old Tokenizers New Words: Efficient Tokenizer Adaptation for Pre-trained Models," Findings of EACL, 2026. (§3.1 describes continued BPE training; §2.4 and Appendix E cover embedding initialization)
  8. [8] Craig W Schmidt, Varshini Reddy, Haoran Zhang, Alec Alameddine, Omri Uzan, Yuval Pinter, Chris Tanner, "Tokenization Is More Than Compression," EMNLP, 2024. (Compares segmentation methods and other factors against model quality using 64 models with 350 million to 2.4 billion parameters)