Token IDs and the Vocabulary
Token IDs are zero-based row indices. The first row is row 0, so token ID 3 retrieves the fourth row, not the third.
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
- Standardize: lowercase and delete punctuation.
- Split on whitespace into tokens.
- Build the vocabulary: 0 = padding, 1 = [UNK], then words by frequency (ties: first appearance), capped at max tokens.
- Map each token to its id (1 if it did not make the vocabulary), then pad with 0 or truncate to the sequence length.
- 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.
Loading the simulation…
From Words to Integers
Before a model learns anything, every token in a text has already been reduced to an integer. That integer is the token ID. It tells the model which entry of its vocabulary the token corresponds to, but on its own it carries no information about meaning. A token ID is only a label, the way a seat number tells you where a passenger sits without describing the passenger.
A neural network cannot do much with a bare label, so an embedding layer converts each token ID into a vector of numbers. The question this article answers is how that conversion happens. The short answer is that the layer does not perform a complicated calculation. It looks up a row. The rest of the article explains what that means, why the lookup returns exactly the vector you expect, and how it connects to a different way of writing the same operation.
Predict the Returned Row
Consider a small embedding matrix with five rows, one for each vocabulary entry. The rows are numbered 0 through 4. Suppose the token ID you pass in is 3. Before reading on, decide which row you think comes back, and whether the layer computes anything new to produce it.
What do you think happens?
Given token ID 3 and the five-row matrix described in the example below, which row does the embedding layer return?
Reveal answer
Row 3, the fourth row, returned exactly as stored.
Token IDs are zero-based row indices, so token ID 3 retrieves the fourth row. The returned vector is not a fresh calculation. It is identical to the stored row, which is why the lookup gives an exact match rather than an approximation.
The Vocabulary as a Row Index
The embedding layer is a lookup operation: a token ID selects a row of the weight matrix by position. The token ID is used as a position, the layer moves to that position in the weight matrix, and it reads the row found there.
The weight matrix of an embedding layer has one row per vocabulary entry and one column per embedding dimension. Each token in the vocabulary therefore owns exactly one row. When the layer receives a token ID, it does not inspect the other rows for this lookup. It reads only the row whose position matches the ID.
The diagram shows a five-token vocabulary in which each row is labeled with its token and its three embedding values. Token ID 3 is the token 'on', and it selects the highlighted row at position 3. The values are illustrative numbers chosen for this example, not values from a trained model.
Token IDs are zero-based row indices. The first row is row 0, so token ID 3 retrieves the fourth row, not the third.
Tracing Token ID 3 Through the Matrix
Looking up token ID 3 and verifying the result
The vocabulary is ['the', 'cat', 'sat', 'on', 'mat'] with token IDs 0 through 4. The embedding matrix has the rows shown in the earlier diagram. The layer receives token ID 3. What vector should it return, and how do you confirm the result?
- 1Identify the token
Counting from zero, token ID 0 is 'the', 1 is 'cat', 2 is 'sat', 3 is 'on', and 4 is 'mat'. Token ID 3 therefore refers to 'on'.
- 2Convert the ID to a row position
Because token IDs are zero-based row indices, the ID 3 is used directly as the row position. The row to read is the fourth row, which is the row at position 3.
- 3Read the stored row
The fourth row of the matrix holds the values 0.9, -0.1, and 0.4. The layer copies this row as the output vector.
- 4Verify the match
Compare the returned vector with the matrix entry at position 3. The values are identical, element by element. A match confirms that the lookup used the right index.
The embedding layer returns [0.9, -0.1, 0.4]. This is exactly the fourth row of the matrix, not an approximation of it.
The verification step is the most useful habit to build. Because the returned vector is a copy of a stored row, you can check any embedding output against the matrix. If the values differ, the problem lies in the index that was used, not in some hidden calculation.
Mistakes With Zero-Based Rows
Common mistake Treating the first row as row 1
What it looks likeReading token ID 3 as the third row because the rows seem to start at 1.
Why it failsToken IDs are zero-based row indices. Token ID 0 maps to the first row, so token ID 3 maps to the fourth row.
Do this insteadCount rows from 0. Position 3 is the fourth row in the matrix.
Common mistake Expecting the output to be newly computed
What it looks likeAssuming the layer calculates a fresh vector each time token ID 3 appears.
Why it failsThe returned vector is identical to the stored row. The layer copies that row rather than approximating it.
Do this insteadCompare the output directly with the matching row of the matrix.
Common mistake Assuming the token ID carries meaning
What it looks likeBelieving that token ID 3 is numerically close to token ID 2 because the numbers are close.
Why it failsA token ID is only a label that identifies a vocabulary entry. Adjacent IDs do not imply related meanings.
Do this insteadTreat the ID as a position. The learned meaning, if any, lives in the values of the row.
Common mistake Mixing up the vocabulary size with the number of embedding dimensions
Lookup Versus One-Hot Multiplication
Readers who know one-hot encoding may recognize the lookup as a shortcut. One-hot encoding represents a token ID as a vector whose length equals the vocabulary size. That vector holds a single 1 at the position of the token and 0 everywhere else. The one-hot vector is then multiplied by a weight matrix in a fully connected layer.
For the five-token vocabulary, the one-hot vector for token ID 3 has a 1 in position 3 and zeros in the other four positions. Written as a row vector, it is multiplied by the matrix as follows.
Here $\mathbf{x}$ is the one-hot vector, $W$ is the weight matrix, and $W_{3,:}$ is the row at index 3. Each entry of the product is a sum of terms, and every term except one is multiplied by zero. Only the term that multiplies the 1 survives, so the product reproduces the row at index 3. This is the same row the embedding layer would have returned directly.
The two paths produce the same output. The one-hot path does extra work: it builds a vector of vocabulary length, multiplies it against every row, and adds up terms that are mostly zero. The lookup path skips all of that and reads one row. This is why the source describes the embedding layer as the more efficient implementation of the same operation.
Locating Where a Lookup Goes Wrong
When an embedding output does not match what you expected, follow the path from token string to token ID to matrix row to returned vector. The mismatch appears at exactly one step, and checking each step in order will find it. The returned vector is a copy of a stored row, so a wrong output almost always means the wrong row was read.
Suppose the output for 'on' is [0.0, 0.5, -0.7] instead of [0.9, -0.1, 0.4]. The token string and the token ID are both correct, since 'on' is ID 3. The output matches the fifth row, which is row 4. The error therefore sits in the step that converts the ID to a row position: an off-by-one index was applied, so the lookup moved one position too far. Fixing that index restores the expected vector.
This procedure works because each step has a checkable output. You can confirm the token ID against the vocabulary, the position against the zero-based count, and the returned values against the matrix row. The step where the check fails is the step that diverges.
Check Your Lookup
Using the five-token vocabulary ['the', 'cat', 'sat', 'on', 'mat'] and the matrix rows 0 through 4 from the earlier diagram, a learner gets the vector [0.7, 0.3, -0.2] for the token 'cat'. Is this correct? If not, identify the row that should have been returned and explain which step went wrong.
Hints
- Find the token ID for 'cat' by counting from zero.
- Compare the returned vector with each row of the matrix, not only the one you expect.
- Check whether the error is in the token-to-ID step or the ID-to-row step.
Key Takeaways
- The embedding layer is a lookup: a token ID is used as a zero-based position, and the layer returns the row of the weight matrix found there.
- The returned vector is an exact copy of a stored row, so you can verify any embedding output by comparing it with the matching matrix row.
- Looking up a row gives the same result as multiplying a one-hot vector by the weight matrix, but the lookup avoids the extra computation over mostly zero terms.
- When an output is unexpected, check the token-to-ID step, the ID-to-row step, and the returned values in that order to find where the path diverges.