Skip to content
AriadneTechnology

The Outer Ring · Chamber 1 of 9

Tokens and Embeddings: How Text Becomes Numbers

Byte-pair encoding, vocabularies and the token tax, then the lookup table that turns every token into a vector.

55 min 50 XP + 12 questions + 1 challengeMathVideoPapersProofsCodeLab

In this chamber you will

  • Explain why models read subword tokens rather than characters or whole words
  • Train byte-pair encoding by hand and count the tokens a text costs
  • Read an embedding as a row of a matrix and compare embeddings by cosine similarity
  • Reason about context windows, token prices and the token tax on other languages
DiscoverLearnRead beyondPapers & lecturesYour turn

A language model never sees letters. It sees a list of integers, one per token, and the first thing it does with each integer is fetch a row from a table of learned vectors. Everything downstream, from attention to sampling, works on those vectors. In 2013, Mikolov and colleagues showed that such vectors can capture meaning well enough that vec("Madrid") − vec("Spain") + vec("France") lands closer to vec("Paris") than to any other word vector. Their model turned two vectors into a probability with a dot product and a softmax over the whole vocabulary: the same shape every LLM's output layer still has.

Spotted in the wild

p(wO∣wI)=exp⁡(vwO′⊤vwI)∑w=1Wexp⁡(vw′⊤vwI)p(w_O|w_I)=\frac{\exp\left({v'_{w_O}}^{\top}v_{w_I}\right)}{\sum_{w=1}^{W}\exp\left({v'_{w}}^{\top}v_{w_I}\right)}
Distributed Representations of Words and Phrases and their Compositionality

This chamber builds both halves: how text is cut into tokens, and how each token becomes a vector.

DiscoverLearnRead beyondPapers & lecturesYour turn
Symbols for this chamber
  • VV“V”
    Vocabulary size: the number of distinct token ids.
    V=50,257V=50{,}257
  • dd“d”
    Embedding dimension: the length of every token's vector.
  • E∈RV×dE\in\mathbb R^{V\times d}“E, a V by d real matrix”
    The embedding matrix. Row ii is the learned vector for token id ii.
  • xi\mathbf x_i“x sub i”
    The one-hot row vector for token id ii: a 1 in position ii and zeros elsewhere.
    xiE=Ei,:\mathbf x_iE=E_{i,:}
  • (a,b)→ab(a,b)\to ab“merge a and b”
    A BPE merge rule: wherever aa is followed by bb, write the single new token abab.
  • cos⁡(u,v)\cos(\mathbf u,\mathbf v)“cosine similarity of u and v”
    u⋅v/(∥u∥∥v∥)\mathbf u\cdot\mathbf v/(\|\mathbf u\|\|\mathbf v\|): the cosine of the angle between two vectors, from −1-1 to 11.
  • nctxn_{\text{ctx}}“n context”
    The context window: the most tokens the model can attend over, prompt and output together.
  • vw, vw′v_w,\ v'_w“v sub w and v prime sub w”
    Word2vec's input and output vectors for word ww, kept in two separate tables.

Why not characters, or words?

A tokeniser maps text to ids t1,…,tnt_1,\dots,t_n with each ti∈{0,…,V−1}t_i\in\{0,\dots,V-1\}. The two obvious units both fail. The figures below are rough, for English prose.

UnitVocabulary size VVTokens per English wordUnknown words?
Characters or bytesabout 100, or exactly 256about 5–6Never with bytes
Whole wordshundreds of thousands, and never complete1Constantly: names, typos, code, new coinages
Subwords (BPE and relatives)tens of thousands to a few hundred thousandroughly 1.3Never, given a byte fallback

Characters make sequences long, and attention, which the next chamber builds, costs time that grows with the square of sequence length; each position also carries little meaning, so the model must spend layers reassembling words. Whole words make the vocabulary enormous, leave rare words with too few examples to learn from, treat run, runs and runner as unrelated, and still meet words they have never seen, which older systems replaced with an [UNK] token. Chinese, Japanese and Thai are written without spaces, so there is not even an obvious word to look up. Subwords sit between: frequent words become single tokens, and rare words split into reusable pieces.

Byte-pair encoding

Byte-pair encoding (BPE) was a 1994 compression trick before Sennrich, Haddow and Birch used it to build subword vocabularies. Training is a loop: split the corpus into words (pre-tokenisation) and each word into base symbols; count every adjacent pair, weighting each word by its frequency; merge the most frequent pair everywhere and record the rule (a,b)→ab(a,b)\to ab; repeat until the vocabulary, base symbols plus one token per merge, reaches its target size.

Python
def merge(symbols, pair):                       # left to right, never overlapping
    out, i = [], 0
    while i < len(symbols):
        if tuple(symbols[i:i + 2]) == pair:
            out.append(symbols[i] + symbols[i + 1]); i += 2
        else:
            out.append(symbols[i]); i += 1
    return out

def train_bpe(words, num_merges):               # words: {("l", "o", "w"): 5, ...}
    merges = []
    for _ in range(num_merges):
        pairs = {}
        for w, c in words.items():
            for p in zip(w, w[1:]):
                pairs[p] = pairs.get(p, 0) + c
        best = max(pairs, key=pairs.get)
        merges.append(best)
        words = {tuple(merge(list(w), best)): c for w, c in words.items()}
    return merges

def encode(word, merges):                       # replay merges in learned order
    symbols = list(word)
    for pair in merges:
        symbols = merge(symbols, pair)
    return symbols

Encoding recounts nothing. It splits new text into base symbols and replays the merge list in order, so a word never seen in training still encodes, as a sequence of learned pieces.

Why the most frequent pair? Suppose a merge replaces kk occurrences in a sequence of nn symbols. Each replacement turns two symbols into one, and the left-to-right scan never reuses a position, so the result has n−2k+k=n−kn-2k+k=n-k symbols. Summed over the corpus, a pair's non-overlapping count is exactly the number of tokens its merge saves, and greedy BPE takes the largest one-step saving. Overlaps are the only subtlety: in aaaaaa the pair (a,a)(a,a) occurs twice but only one replacement fits. Greedy is also myopic: the best merge for the corpus now need not be best later, and it is certainly not best for every text you will encode. The lab below makes you beat it.

Quick check +20 XP

The sequence a a a a a has five symbols. Applying the merge (a,a)→aa(a,a)\to aa left to right, how many tokens remain?

Bytes, SentencePiece and vocabulary size

Byte-level BPE. GPT-2 ran BPE on UTF-8 bytes rather than Unicode characters. Its paper notes that character-level BPE would need a base vocabulary of over 130,000 symbols, while bytes need only 256, and every possible string is a byte sequence. It also stopped merges across character categories (except spaces), so dog, dog. and dog! would not each claim a vocabulary slot. Its vocabulary has 50,257 tokens.

SentencePiece (Kudo and Richardson, 2018) treats the input as a raw stream, with whitespace as an ordinary symbol written ▁, so it needs no language-specific splitting on spaces and decoding is exactly reversible. It implements BPE and the unigram language model, which starts from a large vocabulary and prunes it, and can fall back to bytes for unseen characters. Families such as T5 and Llama 2 used it.

Larger vocabularySmaller vocabulary
Shorter sequences: more text per window, fewer decoding stepsLonger sequences
Embedding and output matrices with VdVd parameters eachCheaper tables and softmax
Many rare tokens that each receive little trainingEvery token seen often
Room for merges in many scriptsFrequent languages, often English, take the merges

A common rule of thumb for English prose is about 0.75 words, or 4 characters, per token. Code, numbers, unusual names and most other languages cost more. Treat these as rough averages that vary by tokeniser, and count with the real one whenever it matters.

Quick check +20 XP

Why can a byte-level BPE tokeniser encode any string without an unknown token?

The token tax and other quirks

Tokenisers are not neutral. Petrov et al. (2023) found that the same text translated into different languages can differ in tokenised length by up to 15 times, and even character-level and byte-level models show more than 4-fold differences for some language pairs. Part of the gap is UTF-8 itself, so byte-level models are not immune; subword tokenisers widen it by spending their merges on whatever was frequent in their training data.

UTF-8 spends one byte on each ASCII character, two on accented Latin, Greek, Cyrillic, Arabic or Hebrew letters, three on Devanagari, Thai, Chinese, Japanese or Korean characters, and four on most emoji. A user writing in a heavily taxed language pays more per message, waits through more decoding steps and fits less text into the same window. Other quirks to know:

  • Numbers. LLaMA split every number into single digits; other tokenisers group up to three digits; early byte-level tokenisers kept whatever digit strings were frequent, so neighbouring numbers could split differently. Arithmetic is harder when tokens do not line up with place value.
  • Leading spaces. In GPT-style tokenisers hello and hello are different tokens, because the space travels with the word. A prompt that ends in a stray space can push the model towards unusual continuations.
  • Glitch tokens. Rumbelow and Watkins found tokens such as SolidGoldMagikarp that GPT-2 and GPT-3 models handled bizarrely, often unable even to repeat them. The likely cause: strings that were frequent in the tokeniser's training data but almost absent from the model's, so their embeddings were barely trained.
  • Special tokens. Reserved ids never produced by merges mark the end of a text (GPT-2's <|endoftext|>), padding, or chat roles. A chat template flattens a conversation into one token sequence; one common style looks like this:
Text
<|im_start|>system
You are a concise assistant.<|im_end|>
<|im_start|>user
How many tokens is this?<|im_end|>
<|im_start|>assistant

Each model family has its own template, and the wrong one quietly degrades output. Check how your tokeniser treats a literal <|im_end|> typed by a user, because libraries differ. Chamber 6, Prompting as Programming, goes deeper.

Embeddings: a lookup table that learns

Write token id ii as the one-hot row vector xi∈{0,1}V\mathbf x_i\in\{0,1\}^V and let E∈RV×dE\in\mathbb R^{V\times d}. Then

(xiE)j=∑k=1V(xi)kEkj=Eij,(\mathbf x_iE)_j=\sum_{k=1}^{V}(\mathbf x_i)_kE_{kj}=E_{ij},

because only k=ik=i contributes: multiplying by a one-hot vector selects row ii. Frameworks skip the multiplication and index the row directly (an embedding layer is a gather), and for a sequence of nn tokens the transformer consumes X=SE∈Rn×dX=SE\in\mathbb R^{n\times d}, where SS stacks the one-hot rows. The embedding says nothing about position; transformers add that separately.

EE starts random and is trained by backpropagation like any other weight. Since X=SEX=SE, the chain rule gives ∂L/∂E=S⊤ ∂L/∂X\partial L/\partial E=S^\top\,\partial L/\partial X: row ii of the gradient sums the gradients at the positions where token ii occurred, and every token absent from the batch gets exactly zero. Rare tokens are therefore rarely updated, which is how glitch tokens survive.

At the other end, the final hidden state h∈Rd\mathbf h\in\mathbb R^d is scored against every token, z=hWout⊤\mathbf z=\mathbf hW_{\text{out}}^\top, and a softmax turns the logits into next-token probabilities: Mikolov's Equation (2) with the rows of WoutW_{\text{out}} as the output vectors v′v'. Tied embeddings set Wout=EW_{\text{out}}=E (Press and Wolf, 2017), saving VdVd parameters: with an illustrative V=128,000V=128{,}000 and d=4096d=4096, that is about 524 million. GPT-2 ties them; many larger models keep two tables.

Quick check +20 XP

Token id 7 has the one-hot row vector x7∈{0,1}V\mathbf x_7\in\{0,1\}^V. What is x7E\mathbf x_7E?

Comparing embeddings: cosine similarity

cos⁡(u,v)=u⋅v∥u∥ ∥v∥.\cos(\mathbf u,\mathbf v)=\frac{\mathbf u\cdot\mathbf v}{\|\mathbf u\|\,\|\mathbf v\|}.

By Cauchy–Schwarz, ∣u⋅v∣≤∥u∥∥v∥|\mathbf u\cdot\mathbf v|\le\|\mathbf u\|\|\mathbf v\|, so the cosine lies in [−1,1][-1,1]; you will prove the equality cases below. It compares directions and ignores lengths, whereas a raw dot product also rewards long vectors. For word2vec-style embeddings, nearest neighbours by cosine tend to be related words, and differences can encode relations, as in the Madrid example; in code, normalise every row of EE once and a single matrix product gives all the cosines. An LLM's input embedding rows are a weaker notion of meaning than its contextual hidden states; dedicated embedding models produce one vector per passage, and Chamber 8, Retrieval, Tools and Agents, searches with them.

Quick check +20 XP

What is the cosine similarity of u=(1,2,2)\mathbf u=(1,2,2) and v=(2,1,2)\mathbf v=(2,1,2)?

Context windows and paying per token

The context window nctxn_{\text{ctx}} is the most tokens a model attends over in one call, prompt and output together: nprompt+noutput≤nctxn_{\text{prompt}}+n_{\text{output}}\le n_{\text{ctx}}. GPT-2's held 1,024 tokens; current models accept far more, but every token still costs compute, time and money. APIs bill per token, usually quoted per million, with input and output priced separately and output typically dearer; many discount input that repeats across calls through caching. Self-hosting pays in GPU time per token instead, which Chamber 9 prices out.

  • Count with the model's own tokeniser: tiktoken for OpenAI models, Hugging Face tokenizers for open-weight models, or the token-counting endpoints that APIs such as Anthropic's and Google's Gemini provide.
  • Budget the window: system prompt, history, retrieved documents, tool definitions and the reserved output must all fit.
  • Measure tokens per message for each language your users write in, not per English word.
DiscoverLearnRead beyondPapers & lecturesYour turn

Read beyond

Lecture notes · free online · ~25 min

Byte-Pair Encoding tokenization

Hugging Face LLM Course · Chapter 6, section 5

Train BPE by hand on their toy corpus of hug, pug, pun, bun and hugs, then check your merges against their code.

Book · free online · ~40 min

Speech and Language Processing (3rd edition draft)

Dan Jurafsky & James H. Martin · Chapter “Embeddings” (Chapter 5 in the August 2026 draft)

Read the section on cosine similarity and note why the chapter prefers it to the raw dot product.

Paper · free online · ~30 min

Language Model Tokenizers Introduce Unfairness Between Languages

Petrov, La Malfa, Torr & Bibi · Introduction and the tokenisation-length comparisons

Find which languages pay the largest premium over English, and whether byte-level models escape it.

Article · free online · ~25 min

The Illustrated Word2vec

Jay Alammar · From “Skipgram” to the end

Identify the embedding and context matrices: they are the v and v′ tables of Equation (2).

DiscoverLearnRead beyondPapers & lecturesYour turn

Read the equation in context

Neural Machine Translation of Rare Words with Subword UnitsRico Sennrich, Barry Haddow & Alexandra Birch · ACL 2016, 2016

Sennrich and colleagues wanted translation without a fixed word list: names, compounds and loanwords can be translated piece by piece. Their BPE learner is a few lines of Python, and segmenting rare words this way improved over a back-off dictionary baseline by up to 1.1 and 1.3 BLEU on English→German and English→Russian.

Distributed Representations of Words and Phrases and their CompositionalityTomas Mikolov, Ilya Sutskever, Kai Chen, Greg Corrado & Jeffrey Dean · NeurIPS 2013, 2013

Skip-gram learns vectors by predicting the words around each word. Section 2 maximises the average log probability (Equation 1)

1T∑t=1T∑−c≤j≤c,j≠0log⁡p(wt+j∣wt),\frac{1}{T}\sum_{t=1}^{T}\sum_{-c\le j\le c,j\ne0}\log p(w_{t+j}|w_t),

where cc is the window size, and defines each probability by the softmax of the opening Glimpse, with separate "input" and "output" vectors per word. The authors call that softmax impractical because its gradient costs time proportional to WW, often 10510^5–10710^7 terms, and replace it with hierarchical softmax and negative sampling. LLM training does compute the full softmax over VV at every position: GPUs made the price worth paying.

Decode the paper · Section 2, Equation (2): the basic Skip-gram softmax

Distributed Representations of Words and Phrases and their Compositionality

Tomas Mikolov, Ilya Sutskever, Kai Chen, Greg Corrado & Jeffrey Dean · NeurIPS 2013, 2013

+25 XP
p(wO∣wI)=exp⁡(vwO′⊤vwI)∑w=1Wexp⁡(vw′⊤vwI)p(w_O|w_I)=\frac{\exp\left({v'_{w_O}}^{\top}v_{w_I}\right)}{\sum_{w=1}^{W}\exp\left({v'_{w}}^{\top}v_{w_I}\right)}

Skip-gram learns word vectors by predicting the words around each word. Equation (1) averages log⁡p(wt+j∣wt)\log p(w_{t+j}|w_t) over a window of cc words either side, and Equation (2) defines that probability as a softmax over dot products between one input vector and every output vector. The paper calls this full softmax impractical, because the cost of its gradient is proportional to WW, often 10510^5–10710^7 terms, and replaces it with hierarchical softmax or negative sampling.

wIw_I
wOw_O
vwIv_{w_I}
vwO′v'_{w_O}
WW
∑w=1W\sum_{w=1}^{W}

Options

Let's build the GPT TokenizerAndrej Karpathy · 134 min
Word Embedding and Word2Vec, Clearly Explained!!!StatQuest with Josh Starmer · 16 min
DiscoverLearnRead beyondPapers & lecturesYour turn

Your turn

Train a tokeniser by hand. Greedy BPE merges whatever is most frequent in the corpus; your job is to choose merges that squeeze three particular phrases into their token budgets, the last built from words the corpus never contains. Watch your curve against greedy's as you go.

Interactive lab

Token squeezer

Train a tiny BPE tokeniser by hand. Each merge joins one adjacent pair everywhere in the corpus and adds one token to the vocabulary; the phrase is then encoded by applying your merges in order. Letters stand in for bytes (plain ASCII is one byte per character) and ▁ marks the start of a word, as in SentencePiece. Merges never cross words.

Training corpus: The sirens sing and the sailors sail. Singing sirens, sailing sailors. The singer sings and the sailor sails. The rowers row, the sails sing in the wind.

Fit “singing sailors” into 10 tokens using at most 3 merges. Find a merge that pays off more than once.

▁singing▁sailors

Phrase tokens

16 / 10

Merges used

0 / 3

Vocabulary

14

Corpus · greedy

148 · 148

Tokens in the phrase after each merge, by hand and by greedy BPE080.75111.5142.2517320Merges learnedPhrase tokens
● Greedy BPE● Your merges● Token budget

Pairs in the corpus (count) · tap to merge

Teal pairs occur in the phrase; −n is how many tokens that merge would save there. Below, merges in violet are the ones greedy BPE would also pick at that step.

    Challenge: Token squeezerChoose byte-pair merges by hand to fit three phrases into their token budgets.+40 XP

    Match · Term ↔ Meaning

    Tokenisation terms

    +20 XP
    Byte-level BPE
    SentencePiece
    Special token
    Glitch token
    Merge rule

    Options

    Match · Expression ↔ Meaning

    Embedding maths

    +20 XP
    xiE\mathbf x_iE
    u⋅v∥u∥∥v∥\dfrac{\mathbf u\cdot\mathbf v}{\|\mathbf u\|\|\mathbf v\|}
    hE⊤\mathbf hE^\top
    VdVd
    nprompt+noutput≤nctxn_{\text{prompt}}+n_{\text{output}}\le n_{\text{ctx}}

    Options

    Proof puzzle

    What one merge saves

    +25 XP

    Claim

    If applying the merge (a,b)→ab(a,b)\to ab to a sequence of nn symbols replaces kk occurrences, the result has exactly n−kn-k symbols.

    Tap lines in the order they should appear. Not every line belongs. Tap a line in your proof to send it back.

    Your proof

    1. Pick the first line below.

    Available lines

    Prove it yourself

    Cosine similarity is bounded

    +35 XP

    Claim

    For nonzero u,v∈Rd\mathbf u,\mathbf v\in\mathbb R^d, prove −1≤cos⁡(u,v)≤1-1\le\cos(\mathbf u,\mathbf v)\le1, and that cos⁡(u,v)=1\cos(\mathbf u,\mathbf v)=1 exactly when v\mathbf v is a positive multiple of u\mathbf u.

    Preview

    Your typeset proof appears here.

    Coding problems

    Problem 1·Warm-up

    Nearest by cosine

    +20 XP

    Toy 4-dimensional embeddings (illustrative, not from a real model): king (5,4,1,0)(5,4,1,0), queen (5,3,5,1)(5,3,5,1), man (4,0,1,1)(4,0,1,1), woman (4,0,5,1)(4,0,5,1), prince (4,4,0,2)(4,4,0,2), apple (0,1,2,5)(0,1,2,5). Form v=eking−eman+ewoman\mathbf v=\mathbf e_{\text{king}}-\mathbf e_{\text{man}}+\mathbf e_{\text{woman}}. Among the tokens other than king, man and woman, find the one with the largest cosine similarity to v\mathbf v, and give that similarity to 4 decimal places.

    A number, rounded to 4 decimal places

    Problem 2·Standard

    Train, then encode the unseen

    +35 XP

    Train BPE on the word counts low 5, lower 2, newest 6, widest 3. Write each word as its characters preceded by a word-start marker _ (so low is _ l o w). Repeat 10 times: count every adjacent pair of symbols, weighting each word by its count; pick the pair with the highest count, breaking ties by the lexicographically smallest pair (compare first symbols, then second symbols, as Python compares tuples of strings); then replace its non-overlapping occurrences, scanning each word left to right, by the concatenated symbol. Finally encode the unseen words lowest, newer, wider and slowest (each with its _ marker) by applying the 10 merges in the order learned. How many tokens do the four words take in total?

    An exact integer (or a fraction like 7/12)

    Problem 3·Challenge

    The token tax, simulated

    +50 XP

    Two toy languages share one tokeniser. Language A builds words from the syllables ka, lo, mi, ne, ru, to (in that order); language B from zu, xe, qa, vo, jy, wi. Use the Park–Miller generator xk+1=16807 xk mod (231−1)x_{k+1}=16807\,x_k\bmod(2^{31}-1) with x0=2026x_0=2026, where each call advances xx and returns the new value. Generate 1000 words. For each word: call once, and the word is in B if the value mod 10 is 0, otherwise in A; call again, and the word has 2+(value mod 3)2+(\text{value}\bmod3) syllables; then, for each syllable, call once and take syllable number value mod 6 (counting from 0) from that language's list. Join the syllables with no marker. Train 30 BPE merges on all 1000 words: count adjacent pairs over every word occurrence, take the most frequent pair, break ties by the lexicographically smallest pair, and replace non-overlapping occurrences left to right; merges never cross words. Finally compute the mean number of tokens per word for the B words and for the A words. Give the ratio, B over A, to 4 decimal places.

    A number, rounded to 4 decimal places

    Key takeaways

    • Models read integer token ids. Subword tokenisers trade vocabulary size against sequence length, and with a byte fallback they never meet an unknown word.
    • BPE learns merges by frequency and encodes by replaying them in order; each merge saves exactly its non-overlapping count.
    • Tokenisers are not neutral: other languages, numbers, leading spaces and rare tokens cost or behave differently, so count with the real tokeniser.
    • An embedding is a row of a learned V×dV\times d matrix, selected by a one-hot vector; tying it to the output layer saves VdVd parameters.
    • Cosine similarity compares directions and lies in [−1,1][-1,1]; context windows and bills are both measured in tokens.

    Checkpoint

    Prove it to the labyrinth

    Answer every question to clear this chamber. First-try answers earn the most XP.

    0/8
    Question 1 of 8 +20 XP

    Why does a tokeniser trained mostly on English text usually spend more tokens on the same message in, say, Burmese or Amharic?

    Question 2 of 8 +20 XP

    A byte-level BPE tokeniser starts from 256 byte tokens, learns 50,000 merges and adds one special end-of-text token. What is its vocabulary size?

    Question 3 of 8 +20 XP

    A model has a context window of 32,768 tokens. The system prompt takes 1,500 tokens and you reserve 2,000 tokens for the answer. Retrieved passages cost 600 tokens each. How many whole passages fit?

    Question 4 of 8 +20 XP

    Why could asking an early GPT model to repeat the token ' SolidGoldMagikarp' produce bizarre output?

    Question 5 of 8 +20 XP

    What does it mean to tie a model's input and output embeddings?

    Question 6 of 8 +20 XP

    In a GPT-style byte-level tokeniser, why are hello and hello (with a leading space) usually different tokens?

    Question 7 of 8 +20 XP

    A string has 10 ASCII letters, 5 Greek letters (2 bytes each in UTF-8) and 2 emoji (4 bytes each). Before any merges, how many base tokens does a byte-level tokeniser need?

    Question 8 of 8 +20 XP

    When a trained BPE tokeniser encodes new text, how does it choose which merges to apply?

    End of the chamber

    Clear this chamber

    +50 XPTokenByte-Pair EncodingEmbedding MatrixContext Window