Concepts / Token Embeddings and Vocabulary Mapping

Token Embeddings and Vocabulary Mapping

An embedding layer maps each token to a vector and is sized by two values: the vocabulary size and the output dimension.

  • Programming
Interactive lab

Try it: Text Vectorization: Tokens to Vectors

The text-to-tensor pipeline: standardize, split into tokens, build a frequency-ranked vocabulary with padding and [UNK], map tokens to integer ids, pad or truncate, then one-hot or multi-hot encode and look the ids up in an embedding table.

How it works

  1. Standardize: lowercase and delete punctuation.
  2. Split on whitespace into tokens.
  3. Build the vocabulary: 0 = padding, 1 = [UNK], then words by frequency (ties: first appearance), capped at max tokens.
  4. Map each token to its id (1 if it did not make the vocabulary), then pad with 0 or truncate to the sequence length.
  5. Encode: one-hot rows per position or one multi-hot row per text; embed: id k selects row k of the embedding table.

Default run (18 steps): Raw text (59 characters): "The movie was great. The plot was great, the acting wasn't!". A model cannot read strings, so it is turned into numbers step by step. … Embedding lookup: id k selects row k of a fixed 8 x 3 table, giving a (8, 3) dense matrix instead of (8, 8) sparse one-hots. Row 0 (padding) is looked up too; a trained Embedding layer would learn these rows.

Simplified: Bounded ASCII text (up to 200 characters, 40 tokens), whitespace splitting only, and a small FIXED embedding table (a real Embedding layer learns its rows). The multi-hot vector keeps the padding slot (always 0) so its positions line up with the ids.

Educational simulation

Loading the simulation…

Why a Model Needs Numbers Instead of Words

An LLM never works directly with words. Before any computation happens, each token in the input text is turned into a numeric identifier. That identifier is just a whole number, and it does not carry any information about what the token means. The model still needs something it can compute with, so the identifier must be converted into a vector of numbers. The component responsible for this conversion is the embedding layer.

Think of the embedding layer as a lookup structure. You give it a token, and it returns the vector assigned to that token. Everything in this article is about how that lookup structure is sized, what it contains when it is first created, and how to tell when its shape is wrong.

Predicting the Structure Before Looking

What do you think happens?

An embedding layer will hold a grid of numbers with two dimensions. Before reading on, decide which direction of the grid should correspond to tokens and which should correspond to the features of each token's vector.

  • Rows correspond to tokens and columns correspond to embedding features

  • Rows correspond to embedding features and columns correspond to tokens

  • Both directions correspond to tokens, and features are stored in a separate list

Reveal answer
Answer:

Rows correspond to tokens and columns correspond to embedding features.

The matrix is not an arbitrary block of memory. Its rows are indexed by tokens and its columns are indexed by embedding dimensions. If you can say which axis is which, you can predict the shape of any embedding layer without running it.

Two Numbers That Size the Lookup

A lookup structure has to be sized before it can be used, and two numbers decide that size. The first is how many distinct tokens the layer must cover, which is the vocabulary size. The second is how many numbers make up each token's vector, which is the output dimension. Once these two values are fixed, the layer has a definite shape and a definite amount of storage.

Definition

An embedding layer maps each token to a vector and is sized by two values: the vocabulary size and the output dimension.

An embedding layer is created by calling a PyTorch module class and passing it the two sizes. The signature has exactly two positional parameters, and their order matters. The first argument is the vocabulary size and the second is the output dimension. Swapping them does not raise an error in the way a typo might, but it gives the layer a different shape than you intended, so the order must be treated as part of the design.

The two constructor arguments map onto the two axes of the weight matrix. The vocabulary size sets the number of rows, one row per token. The output dimension sets the number of columns, one column per embedding feature. The weight matrix therefore has the shape vocab_size by output_dim. Written as math, a layer built with a vocabulary of $V$ tokens and an output dimension of $d$ has a weight matrix of shape $V \times d$.

Tracing a Token ID Through the Lookup

Once the layer exists, a token ID arrives and selects a row. Suppose the token ID is 5. Because the vocabulary has 6 tokens, IDs run from 0 to 5, so ID 5 is the last row of the weight matrix. The layer does not search for anything. It uses the ID as a position and returns the row stored at that position. That returned row is the vector for that token.

Token ID 5incoming integerRow 0vector for token 0Row 1vector for token 1Row 2vector for token 2Row 3vector for token 3Row 4vector for token 4Row 5vector for token 5selects
When the token ID 5 arrives, the layer uses it as a position and returns the row stored at that position, which becomes the token's vector.

Notice what this means for the whole table. The lookup never mixes rows. Token 5 always reads row 5, and no other token's row is touched. This is why the vocabulary mapping is a one-to-one association between each token ID and one row.

The Weight Matrix as Stored Memory

The matrix is a block of stored numbers with a fixed layout. Its rows are indexed by tokens and its columns by embedding dimensions. Because the two sizes are fixed when the layer is created, the layer has a definite amount of storage from the start. Every token row has the same width, and the total number of entries is always the vocabulary size multiplied by the output dimension.

vocab_size = 6one row per tokenWeight matrix6 rows by 3 columns, 18valuesoutput_dim = 3one column per featuresets rowssets columns
The two constructor arguments map onto the two axes of the weight matrix, giving a 6 by 3 grid of stored values in this example.

What the Numbers Contain Before Training

When the layer is created, every entry of the weight matrix is filled with a small random number. These numbers are not chosen to represent any particular word. At creation time they carry no linguistic meaning. The row for token 5 is simply some small random values, and so is every other row. They are a starting point from which training can begin.

The values are not fixed for good. They are adjusted during LLM training, as part of the same optimization process that trains the rest of the model. Over many updates, the rows that correspond to tokens are nudged toward values that help the model predict text well. This is why the initial values are a beginning rather than a result. A trained embedding table and a freshly created one have the same shape, but very different contents.

The weights are marked as trainable parameters, which is why the printed representation of the layer reports that gradients are required. This flag tells PyTorch to track operations on the matrix so that it can be updated during optimization.

Where Embeddings Sit in the Pipeline

The embedding layer is one stage in a longer chain. Text is first split into tokens and converted to numeric IDs. Those IDs are passed to the embedding layer, which returns vectors. Those vectors are then passed on to the rest of the model, which expects them to have a particular shape. A problem at any stage shows up as a shape that the next stage does not accept.

Input textraw charactersToken IDswhole numbersEmbedding layerrows by output_dimVector tensorone vector per tokenDownstream modelexpects a set shapetokenizelook upreturns vectorspassed on
Each stage changes the shape of the data, so a mismatch can originate at any stage and surfaces at the next one that expects a different shape.

Reproducible Starting Values with a Seed

Random initialization creates a practical problem. If every run produced different starting numbers, two people running the same code could see different results and find it hard to compare notes. A random seed solves this. Setting a seed makes the random generator produce the same sequence every time, so the starting weights are reproducible.

A fixed seed makes the starting values reproducible without changing the shape. The seed controls which numbers fill the matrix, not how many there are. A layer built with a vocabulary of 6 and an output dimension of 3 still has 6 rows and 3 columns whether or not a seed is set.

Mistakes That Cause Shape Mismatches

When an embedding layer behaves unexpectedly, the fastest route to the cause is to compare the observed weight shape against the shape you predicted from the arguments. A mismatch almost always traces back to one of three places: the values passed in, the order in which they are passed, or the moment the seed is set relative to layer creation. Checking the shape first isolates the first two causes quickly. Checking the seed ordering isolates the third.

  • Common mistake

    Swapping the vocabulary size and the output dimension

    What it looks like

    A layer meant to hold 6 tokens with 3 features per token is created with the output dimension first, so it holds 3 tokens with 6 features each.

    Why it fails

    The first constructor argument always sets the number of rows, and the second always sets the number of columns. The order is part of the design.

    Do this instead

    Predict the shape from the arguments before running the code, then compare it with the observed weight shape.

  • Common mistake

    Passing a token ID that is outside the vocabulary

    What it looks like

    A vocabulary of 6 has valid IDs 0 through 5, and an ID of 7 is passed in.

    Why it fails

    The ID is used as a row position, and no row exists at position 7 in a matrix with 6 rows.

    Do this instead

    Confirm that the vocabulary size covers every token ID the tokenizer can produce.

  • Common mistake

    Setting the seed after creating the layer

    What it looks like

    The layer is created, then the seed is set, and two runs still produce different starting values.

    Why it fails

    The seed only affects values generated after it is set, and the layer already received its values at creation.

    Do this instead

    Set the seed before the layer is instantiated.

  • Common mistake

    Expecting the starting values to carry meaning

    What it looks like

    Treating the row for token 5 as if it already encodes what that token means.

    Why it fails

    At creation the values are small random numbers. Meaning only develops as training adjusts them.

    Do this instead

    Treat the initial matrix as a starting point, not a result.

Practice Predicting and Checking Shapes

MEDIUM

A layer is created with a vocabulary size of 50,257 and an output dimension of 12,288. Without running anything, state the shape of its weight matrix, and state how many numbers the matrix holds. Then explain which of the two numbers controls the number of rows.

Hints
  • The first constructor argument sets the number of rows.
  • The number of entries is the number of rows multiplied by the number of columns.

Key Takeaways

  • An embedding layer maps each token to a vector and is sized by two values: the vocabulary size, which sets the number of rows, and the output dimension, which sets the number of columns.
  • The weight matrix has shape vocab_size by output_dim, and a token ID selects one row of it as that token's vector.
  • At creation, every weight is a small random number with no linguistic meaning; training adjusts these values over many updates.
  • A fixed random seed, set before the layer is created, makes the starting values reproducible without changing the shape.
  • Shape mismatches usually come from the argument values, their order, or the timing of the seed; checking the observed shape against the predicted shape locates the problem quickly.

Related concepts

More concepts starting with T