› 01 · Embeddings › Embedding Matrix
⚡ Visual Simulator
AI Journey · Understand Language

Embedding Matrix

Understand the embedding matrix as a learned table: one row per vocabulary entry, with the token ID as the row index that selects a vector.

🔴 MUST 15 study phases Embeddings
🧙‍♂️ The Wise Scholar's Metaphor The Scholar's Memory Drawers
⏮️ 00 · Math & Foundations Hub →

The Embedding Matrix: A Cabinet of Numbered Drawers

The scholar keeps one drawer for every entry in the vocabulary. The drawer number is the token ID; what is inside is a card of learned numbers. Opening a drawer is a lookup. Training is the scholar rewriting the cards in the drawers that were used.

01

IntroductionWhat is the embedding matrix?

Visual lesson: Rows = vocabulary tokens, columns = dimensions. Walk through a 3×4 matrix and the input matrix. Open "Rows. Dimensions. Vectors." →
#charan #dimension #vector
Infographic: What does Dimension (1,536) mean? Embedding matrix shape 50,000 × 1,536 and input matrix stacking
Infographic: Embedding matrix (50,000 rows × 1,536 columns) and input vector stacking. Click to open full size.
Infographic: from your question to the LLM — tokens, token IDs, embedding matrix rows and columns, input matrix, and the Transformer
Rows = vocabulary tokens, columns = dimensions; the input matrix keeps only the rows your question selects. Click to open full size. Numbers are illustrative.
🤔 Layman Curiosity Hook

"If a token ID is just a number, where does the model actually keep what it has learned about each word?"

In a big table of numbers called the embedding matrix. It has one row for each entry in the vocabulary, and the token ID tells the model which row to read.

💡 This is how it happens: picture a spreadsheet. The row number is the token ID. The columns are the dimensions of the vector. When the tokenizer says 1, the model reads row 1 and gets back that token's list of numbers. Training adjusts those numbers; nothing else about the table changes.

The embedding matrix E is a learned table with shape [V, D]: V rows (one per vocabulary entry, usually) and D columns (the embedding dimension). A token ID selects a row; that row is the token's embedding.

Embedding matrix E (illustrative, V = 5, D = 3) Row Vector 0 [ 0.2, 0.5, -0.1] 1 [ 0.8, -0.3, 0.4] ← token ID 1 selects this row 2 [-0.2, 0.7, 0.1] 3 [ 0.1, 0.6, -0.5] 4 [ 0.0, 0.4, -0.6]
Text→ Token ID→ Row of E→ Vector→ Transformer

💡 The embedding matrix is the model's learned lookup table. The token ID is the row index; the row is the learned content.

02

WhyWhy a table of learned rows?

The transformer needs numbers it can do arithmetic on, and token IDs are not those numbers (see Token Embeddings). A table solves three problems at once.

  • Fast access: a token ID is a ready-made index. Reading row i needs no search.
  • Learnable: every number in the table is a parameter. Training can nudge a token's row to make the model's predictions better.
  • Rich representation: a row of hundreds of numbers can hold far more than a single integer.

Without a table

You would need a rule that computes a vector from a token. For a vocabulary of tens of thousands of arbitrary subwords there is no such rule to write by hand.

With a table

Each token gets its own free parameters. The model discovers useful vectors during training instead of someone designing them.

Insight: the matrix is memory, not computation. The lookup reads it; training writes it.
03

IntuitionTwo tables, one ID

A token ID works like a row ID. The same number is the key into two different tables. (Small IDs below are illustrative.)

Table 1 — Vocabulary (tokenizer)

Token IDToken
0the
1cat
2dog
3bank
4river

Maps token ↔ ID. the cat becomes [0, 1].

Table 2 — Embedding matrix E (model)

RowVector (illustrative)
0[ 0.2, 0.5, −0.1, …]
1[ 0.8, −0.3, 0.4, …]
2[−0.2, 0.7, 0.1, …]
3[ 0.1, 0.6, −0.5, …]
4[ 0.0, 0.4, −0.6, …]

Maps ID → learned vector. ID 1 selects row 1: the vector for cat.

  • The vocabulary is a dictionary-like mapping ("cat" → 1), usually a hash map.
  • The embedding matrix is not a dictionary. It is a dense array indexed by position, E[1], and stores no token strings.
  • They line up only through the shared number. Change the tokenizer and every ID points at the wrong row.

💡 Think of the token ID as a database row index, not as the meaning of the word. The learned vector in that row is what provides the numerical representation the transformer works with.

Is the vector stored inside the token ID?

No. For token ID 1 (cat), the matrix row is a short list of learned numbers (illustrative, 4 values):

Token ID 1 → identifies the row for "cat" Row E[1] = [ 0.80, −0.30, 0.40, 0.15 ] dim 1 dim 2 dim 3 dim 4 ← "dimension" = how many numbers are in the row

The ID is the address; the four numbers are the vector. Here the dimension is 4. A real matrix with 50,000 tokens and 4,096 dimensions has shape 50,000 × 4,096: 50,000 rows of 4,096 numbers each. See Vector Dimensions for a slider that shows how the vector grows, and How Embeddings Are Learned for where these numbers come from.

04

TheoryAnatomy of E: rows, columns, and what is learned

PartWhat it isNotes
Rows (V)One per vocabulary entry, usuallySome models pad the row count beyond the vocabulary size.
Columns (D)The embedding dimensionFor example 768 for GPT-2 small and BERT-base. Individual columns generally have no human-readable meaning.
EntriesLearned floating-point parametersUsually start random; adjusted by backpropagation.
Row iThe embedding of token iSame row every time token i appears, in any sentence.

What the matrix is not

  • Not a dictionary of definitions. A row is a learned numeric pattern, not a stored meaning.
  • Not context-aware. A row does not depend on the other tokens. Context is added later (see Contextual Embeddings).
  • Not the whole model. Knowledge also lives in the transformer weights. The matrix is one set of learned parameters among several.
Rule: geometry, not position. Two rows are related if their vectors point in similar directions, never because their row numbers are close.
05

How It WorksLookup in the forward pass, update in training

Forward
1. Tokenizer produces IDs, e.g. [0, 1].
2. The embedding layer reads rows E[0] and E[1].
3. The rows are stacked into a [seq_len, D] matrix and passed on.
Loss
The model's output is compared with the target and a loss is computed.
Backward
Gradients flow back to the rows that were read. Rows of tokens that did not appear in the batch receive no gradient for that step.
Update
The optimizer adjusts the used rows. Next time token 1 appears, row 1 holds slightly different numbers.
graph LR
    A["Text: the cat"] --> B["Token IDs: 0, 1"]
    B -->|"read rows"| C["E[0], E[1]"]
    C --> D["Transformer"]
    D --> L["Loss"]
    L -->|"gradient"| C
    C -->|"optimizer updates only used rows"| E["E (slightly changed)"]

    style A fill:#3b82f6,stroke:#1d4ed8,color:#fff
    style B fill:#10b981,stroke:#047857,color:#fff
    style C fill:#8b5cf6,stroke:#6d28d9,color:#fff
    style E fill:#f59e0b,stroke:#b45309,color:#fff
    
Fig 1. Read rows going forward; update those same rows after the gradient comes back.
06

CalculateA 5 × 3 matrix by hand

Use the matrix from the introduction (V = 5, D = 3). All numbers are invented for teaching.

Step 1
Shape: 5 rows × 3 columns = 15 learned numbers.
Step 2
Lookup "the cat": IDs [0, 1] give
[[0.2, 0.5, −0.1],
 [0.8, −0.3, 0.4]]  — a 2 × 3 matrix (sequence length × D).
Step 3
Same result as a one-hot product: the one-hot vector for ID 1 is [0, 1, 0, 0, 0]. Multiplying it by E picks out row 1: [0.8, −0.3, 0.4].
Step 4
One training update on row 1. Suppose the gradient for that row is [0.5, −1.0, 0.2] and the learning rate is 0.1. New row 1 = [0.8 − 0.05, −0.3 + 0.10, 0.4 − 0.02] = [0.75, −0.20, 0.38]. Rows 0, 2, 3, 4 are unchanged.
Step 5
Repeated token. If ID 1 appears twice in the batch ([1, 1]), each use contributes its gradient to the same row. With the same numbers the contributions add: new row 1 = [0.70, −0.10, 0.36].
Simplification: Step 4 uses plain gradient descent with an invented gradient. Real training uses optimizers such as Adam, and the gradient comes from the whole model.
07

MathematicsLookup, gradient, and the output side

$$\mathbf{E} \in \mathbb{R}^{V \times D} \qquad \mathbf{e}_i = \mathbf{E}[i,:] \qquad \mathbf{X} = \mathbf{E}[\,[i_1,\ldots,i_L]\,] \in \mathbb{R}^{L \times D}$$

Lookup equals a one-hot product

$$\mathbf{o}_i^{\top}\mathbf{E} = \mathbf{E}[i,:]$$

Frameworks index the row directly instead of multiplying, because the one-hot vector is almost all zeros.

Why the gradient is sparse

Row $j$ contributes to the loss $\mathcal{L}$ only through the positions where the token ID equals $j$:

$$\frac{\partial \mathcal{L}}{\partial \mathbf{E}[j,:]} = \sum_{p\,:\,i_p = j} \frac{\partial \mathcal{L}}{\partial \mathbf{x}_p}$$

If token $j$ is absent from the batch, the sum is empty and the row gets zero gradient for that step.

Parameter count and the output side

GPT-2 small : 50,257 × 768 = 38,597,376 parameters fp32 (4 bytes each): 154,389,504 bytes ≈ 154 MB (≈ 147 MiB) fp16 (2 bytes each): 77,194,752 bytes ≈ 77 MB (≈ 74 MiB) BERT-base : 30,522 × 768 = 23,440,896 parameters

Many language models reuse $\mathbf{E}$ to turn the final hidden vector $\mathbf{h}$ into scores over the vocabulary ("weight tying"): $\text{logits} = \mathbf{h}\,\mathbf{E}^{\top}$. GPT-2 does this.

Scale: the GPT-2 small matrix is roughly 31% of that model's ~124M parameters (the tied output layer adds no extra parameters).
08

VisualizeLive lookup: type tokens, see the rows

Type words from the toy vocabulary (the cat dog bank river). The lab shows their IDs, highlights the rows that get read, and stacks them into the output matrix.

🗄️ Live Lab: tokens → IDs → rows of E
Row (ID)Tokend0d1d2
Output matrix ():
09

CodeBuild the table, then use PyTorch

Part A — pure Python:

Python — Vocabulary and embedding matrix
vocab = {"the": 0, "cat": 1, "dog": 2, "bank": 3, "river": 4}     # Table 1: token -> ID (illustrative)

E = [                                                              # Table 2: ID -> vector (illustrative)
    [ 0.2,  0.5, -0.1],
    [ 0.8, -0.3,  0.4],
    [-0.2,  0.7,  0.1],
    [ 0.1,  0.6, -0.5],
    [ 0.0,  0.4, -0.6],
]

ids = [vocab[w] for w in "the cat".split()]
print(ids)                                    # [0, 1]

X = [E[i] for i in ids]                       # the lookup
print(X)                                      # [[0.2, 0.5, -0.1], [0.8, -0.3, 0.4]]

# same thing as a one-hot product
one_hot = [0, 1, 0, 0, 0]
row = [sum(one_hot[r] * E[r][c] for r in range(5)) for c in range(3)]
print(row)                                    # [0.8, -0.3, 0.4]

# one gradient-descent step on row 1
grad, lr = [0.5, -1.0, 0.2], 0.1
E[1] = [round(E[1][c] - lr * grad[c], 3) for c in range(3)]
print(E[1])                                   # [0.75, -0.2, 0.38]

Part B — PyTorch:

Python — PyTorch
import torch
import torch.nn as nn

emb = nn.Embedding(num_embeddings=5, embedding_dim=3)     # E has shape [5, 3], random start
ids = torch.tensor([0, 1])

x = emb(ids)
print(x.shape)                                             # torch.Size([2, 3])
print(torch.equal(x, emb.weight[ids]))                     # True  -> a lookup is row indexing

one_hot = torch.nn.functional.one_hot(ids, num_classes=5).float()
print(torch.allclose(one_hot @ emb.weight, x))             # True  -> same as a one-hot product

emb(torch.tensor([1, 1])).sum().backward()                 # use token 1 twice
used = (emb.weight.grad.abs().sum(dim=1) > 0).nonzero().flatten().tolist()
print(used)                                                # [1]  -> only row 1 received gradient
Note: Part A's outputs were checked by running it. Part B needs torch and its outputs follow from how nn.Embedding works, but they were not run for this page.
10

ExperimentPoke a real embedding matrix

11

CompareVocabulary vs embedding matrix vs related tables

PropertyVocabularyEmbedding matrix EOutput head (unembedding)Positional embeddings
Mapstoken ↔ IDID → vectorhidden vector → scores per tokenposition → vector (in models that use them)
ShapeV entries[V, D][D, V] (often tied to E)[max_len, D]
Learned by gradient?No (built before training)YesYes (or shared with E)Yes in learned schemes
Lives inTokenizerModelModelModel
Stores token text?YesNoNoNo
12

ApplyWhere the embedding matrix matters in practice

  • Memory and size: V × D parameters. Doubling the vocabulary doubles this table.
  • Adding tokens: after adding tokens to a tokenizer, call model.resize_token_embeddings(len(tokenizer)) so each new ID has a row. New rows start untrained and need fine-tuning to become useful.
  • Weight tying: reusing E as the output projection saves V × D parameters.
  • Fine-tuning choices: some recipes freeze E to save memory or keep the original vocabulary behaviour; others train it, especially when new tokens are added.
  • Swapping tokenizers: not possible without retraining or remapping, because rows are aligned to the original vocabulary.
13

LimitationsCommon mistakes and traps

Trap 1 — "The matrix stores the word." It stores learned numbers only. The token string lives in the vocabulary.
Trap 2 — "Nearby row numbers mean related words." Row order follows vocabulary construction, not meaning.
Trap 3 — "Each column means something." In general you cannot name a single dimension. Meaning is spread across many.
Trap 4 — "A fresh matrix already knows language." A new nn.Embedding is random. Useful structure appears with training or by loading trained weights.
Trap 5 — "V always equals the vocabulary size." Usually close; some models pad the row count. Check the model config.

Mistakes to avoid

  • Mixing a tokenizer with the wrong model
  • Resizing the vocabulary without resizing E
  • Reading meaning from row numbers

Correct mental models

  • ID = row index; row = learned content
  • Vocabulary and E are two tables joined by the ID
  • Only rows used in a batch get updated that step
14

ExplainFeynman Challenge: the spreadsheet

Feynman Challenge — Explain It Simply

The embedding matrix is a spreadsheet with one row per vocabulary entry. The token ID is the row number. The cells are numbers the model learned. To "read a word", the model looks up its row and takes the numbers it finds there.

Try explaining this to someone right now: "What is the difference between the vocabulary and the embedding matrix, and how does a token ID connect them?"

🚫 Common Misconceptions to Correct

  • Misconception: the vocabulary and the embedding matrix are one thing.
    Reality: The vocabulary belongs to the tokenizer; the matrix belongs to the model. The ID joins them.
  • Misconception: the lookup learns.
    Reality: The lookup only reads. Learning happens when the optimizer updates the rows during training.
  • Misconception: the matrix is the model's whole knowledge.
    Reality: The transformer weights hold a large part of it too.
15

BuildMini-project and summary

🎯 Four Things to Build for Mastery

1 — Embedding layer class

Write Embedding(V, D) with forward(ids) using plain lists. Add a method that returns the parameter count.

2 — Sparse updater

Implement step(ids, grads, lr) that updates only the rows in ids, summing gradients for repeated IDs. Test it with the Calculate phase numbers.

3 — Size calculator

Given V, D and bytes per value, print the parameters and memory. Reproduce the GPT-2 small figures.

4 — Resize experiment

Add tokens to a tokenizer, resize a model's embeddings, and inspect the new rows against the old ones.

📌 Summary — Everything in Six Bullets

  • E is a learned table of shape [V, D]: one row per vocabulary entry, usually.
  • The token ID is the row index. It is a key, not a meaning.
  • Two tables, one ID. The vocabulary maps tokens to IDs; E maps IDs to vectors.
  • Lookup reads, training writes. Only rows used in a batch receive gradient.
  • Geometry carries meaning. Closeness of vectors matters; closeness of row numbers does not.
  • Pipeline: Text → Token ID → Embedding matrix row → Vector → Transformer.
This page 0:00
This session 0:00
Total (all pages) 0:00
Today 0:00
▶ Running
📊 View all study stats →
0:00 studying