Step 2 · Embeddings and position
Turning token ids into vectors, and telling the model what order they came in. Two lookup tables, one subtle idea.
In 60 seconds
Step 2 · Embeddings and position
Turning token ids into vectors, and telling the model what order they came in. Two lookup tables, one subtle idea.
import torch, torch.nn as nn
vocab_size, d_model = 50257, 768
tok_emb = nn.Embedding(vocab_size, d_model) # a (50257, 768) lookup table
ids = torch.tensor([[15496, 995, 0]]) # batch 1, sequence 3
x = tok_emb(ids) # -> (1, 3, 768)nn.Embedding is a matrix where row i is the vector for token i, and the lookup is differentiable, so training moves those rows around until similar tokens sit near each other.The order problem
| Method | How it works | Used by |
|---|---|---|
| Learned absolute | A second lookup table indexed by position 0,1,2… | GPT-2, BERT |
| Sinusoidal | Fixed sine and cosine waves of different frequencies | Original transformer paper |
| RoPE (rotary) | Rotate the query and key vectors by an angle proportional to position | Llama, Mistral, Qwen, most modern models |
| ALiBi | Add a distance penalty directly to attention scores | Some long-context models |
Why RoPE won
def rope_frequencies(head_dim, seq_len, base=10000.0, device="cpu"):
# one angular frequency per pair of dimensions
inv = 1.0 / (base ** (torch.arange(0, head_dim, 2, device=device).float() / head_dim))
pos = torch.arange(seq_len, device=device).float()
ang = torch.outer(pos, inv) # (seq_len, head_dim/2)
return torch.cos(ang), torch.sin(ang)
def apply_rope(x, cos, sin):
# x: (batch, heads, seq, head_dim) -- rotate each adjacent pair of dims
x1, x2 = x[..., 0::2], x[..., 1::2]
cos, sin = cos[None, None], sin[None, None]
out1 = x1 * cos - x2 * sin
out2 = x1 * sin + x2 * cos
return torch.stack((out1, out2), dim=-1).flatten(-2)What embeddings are not
- They are not a dictionary of meanings. A token vector is a starting point that every later layer rewrites in context.
- The famous "king − man + woman ≈ queen" arithmetic came from older word-vector models. Transformer token embeddings are much less interpretable in isolation.
- Embedding and output layers are often tied — the same matrix, transposed, produces logits. It saves parameters and usually helps.
Watch and read more
Lab
Position encoding, and the failure when you remove it.
The problem
# Prove attention is permutation-invariant without positions
x = torch.randn(1, 5, 64)
perm = torch.randperm(5)
assert torch.allclose(attn(x).sum(1), attn(x[:, perm]).sum(1), atol=1e-5)You are done when
Hard questions
Try to answer before you reveal. If you can answer these, you understood the lesson.
Q1Rescaling RoPE frequencies extends context with no retraining. Why is this insufficient, and what does the model actually lack?Reveal
Questions people ask
How big should d_model be?
It scales with the model. Roughly: 128–384 for a tiny teaching model, 768 for GPT-2 small, 4096 for a 7B model, 8192+ at frontier scale. It should be divisible by the number of attention heads.
Are these the same as sentence embeddings for search?
Different things with the same name. Retrieval embeddings represent a whole passage as one vector, produced by a model trained for similarity. Token embeddings are per-token inputs to a generative model.
Why does the embedding table dominate small models?
With a 50k vocabulary and d_model 768, that table alone is 38M parameters. In a 100M-parameter model it is a third of everything. This is why tiny models often use smaller vocabularies.
Can I add RoPE to a model trained with learned positions?
Not without substantial retraining. Position encoding is baked into what every attention head learned. Conversions exist and are all approximate.
Lesson test
5 questions. Get 3 right (60%) to pass and complete this lesson.
Sign in with your phone number to take the test and save your progress