Module 06 · Part II · The Transformer
Attention
Queries, Keys and Values, Scaled Dot-Product Attention by Hand, the Variance Proof, Masks, Permutation Equivariance, and Multi-Head Attention
By the end you can compute attention by hand, prove why scores are divided by √d_k, and explain what multiple heads add.
Check yourself ▸
Before you start, can you already…
- ☐explain why recurrence hit a wall, and how attention first appeared inside RNN translation models. (Module 5)
If any is shaky, the linked module teaches it.
In June 2017, Vaswani and colleagues at Google published "Attention Is All You Need". Before it, sequence models read text with recurrence (section 5.2) or convolutions (small filters slid along the text, each seeing a few neighbours; section 25.1). The Transformer dropped both: every token looks directly at every other token through self-attention. Almost every large language model today is built on that design.
This module builds attention by hand on small numbers, proves why scores are divided by , explains masks, shows what attention cannot do alone (tell word order), and ends with multi-head attention and its cost.
6.1 The Question Attention Answers
For each token, attention answers: "which other tokens should I take information from, and how much?" It uses the three projections of section 1.6:
- Queries : one row per asking token, describing what it looks for.
- Keys : one row per token that can be looked at, describing what it offers.
- Values : one row per key, the information handed over if chosen.
6.2 Scaled Dot-Product Attention, by HandRun this section
In self-attention all three come from the same sentence, so ; they differ in cross-attention (section 8.1). The whole computation is one line:
Read it from the inside out:
- is an table of scores: entry is query dotted with key (section 1.4).
- Dividing by keeps the scores from growing with the vector width (section 6.3).
- The mask holds where attention is allowed and where it is not, so blocked pairs get weight (section 6.4).
- Softmax turns each row into weights that sum to 1 (section 4.3).
- Multiplying by gives each query a weighted average of the value rows.
The letter does double duty: as a size () it is the key count; as a matrix () it is the mask. , the query and key width, is usually or ; is the value width.
In words. Each query is scored against every key; the scores are scaled, masked and softmaxed into weights, which average the values. Each query gets one output vector, built from the tokens it was allowed to see.
The Whole Computation on Two Tokens
Finish section 1.6's example. Its and , plus a value matrix with rows , , , , give:
| query | key | value | |
|---|---|---|---|
| token 1 | |||
| token 2 |
- Scores. Every query against every key: , , , .
- Scale by : the rows become and .
- Mask. With a causal mask, token 1 may not look at token 2, so its second score becomes : row 1 is .
- Softmax each row. Row 1 has only one allowed entry, so its weights are . Row 2 is , divided by their sum : weights .
- Weighted sum of values. Token 1's output is just . Token 2's output is .
Each output is a mix of value vectors chosen by the scores. And the mask changed the answer: without it, nearly all of token 1's weight would go to token 2, which it is not supposed to see.
The two tokens from section 1.6, pushed through every step of the attention formula. Switch the mask and the scaling to see what each changes downstream.
Step to the softmax with the causal mask switched off. Where does token 1 put almost all of its weight, and why does the very negative score make the answer so lopsided?
In words. A stepper walks the two-token example from queries and keys through scores, scaling, mask and softmax to the output, highlighting the entries involved. Mask and scaling can be toggled, and later steps update.
6.3 Why Divide by the Square Root of the Key WidthRun this section
The division is not a tuning trick; it follows from a short calculation with the rules of section 3.2. At the start of training, treat each query and key entry as independent with mean 0 and variance 1: . One raw score is
a sum of products. Find its mean and variance.
- The mean is zero, by rules 1 and 2, since each :
- Each product has variance 1. Its mean is 0, and by independence , each factor being a variance of 1:
- The variances add (rule 4), over terms:
- So a typical score has size :
At a typical score is about ; at , about .
What Goes Wrong Without the Scaling
A gap of between two scores makes one weight times the other. At , gaps of 20 are common, and is about 500 million, so softmax puts almost all weight on one key. This saturation stalls learning: section 4.3 showed that the softmax Jacobian is then nearly zero, so the query and key weights barely change.
By rule 3, dividing by divides the variance by :
Scaled scores have variance 1 at any head width, so softmax starts training where its gradients are healthy.
Left: scores of random queries and keys. Right: in 300 trials of one query against 64 keys, how often the softmax puts more than 99% of its weight on one key.
Turn scaling off and raise from 16 to 256. Predict what happens to the histogram of scores and to the share of trials in which one key takes more than 99% of the weight. Then turn scaling on.
In words. A histogram of random query-key scores at a chosen head width, with or without scaling. A second panel runs softmax trials over 64 keys and reports how often the largest weight exceeds 0.99, and how small p times one minus p becomes when it does.
Measured (lab 2b,
experiments/variance_scaling.py). The variance result holds at every head width. Over 200,000 random draws per width, comes out at , , and for . The scaled variance is throughout.
Measured (lab 2b). Over 500 random trials at with keys, of the unscaled trials push above . With scaling, do. In the trials that do saturate, the gradient term is , close to zero. The result is a fraction of trials because saturation depends on the random draw: one draw clears while the next can fall short.
6.4 MasksRun this section
A mask added to the scores puts on forbidden pairs, so softmax spreads each row's weight over the allowed keys only. Three kinds cover every model in the course:
- No mask. Every token sees every token. Encoders use this (section 8.2), so a token's meaning can depend on both sides.
- Causal mask. Token sees tokens to only. Every text-writing model uses this (section 8.4), since token must not be visible while predicting it. For four tokens, with for :
- Padding mask. Short sequences in a batch are filled out with placeholder tokens; the mask puts in their columns so no real token attends to them.
Masks combine by adding. Section 16.3 meets a fourth kind, the sliding window. Every row must keep at least one allowed key, or the softmax computes = NaN.
6.5 Attention Cannot See Word OrderRun this section
A score is built from two tokens' vectors and nothing else; no position appears anywhere. Shuffle the tokens and, with no mask, the outputs come back shuffled the same way and otherwise unchanged. This is permutation-equivariance: for any permutation matrix (one that reorders rows), . In "The dog bit the man" and "The man bit the dog", "dog" gets exactly the same output vector. The model cannot tell who bit whom.
Self-attention (no mask) over four words. Each row is one word’s output vector. Hover a cell to read its value, then shuffle and compare the row for the same word.
Shuffle the tokens. Before looking at the output panel, predict whether any output vector changes its values, or only its position in the list.
In words. Self-attention on a short sentence, showing every token's output vector. Shuffling the tokens reorders the outputs without changing their values. A switch adds position vectors, and then shuffling changes the outputs themselves.
The fix is to give each token its position before attention: section 7.1 shows the classic way, and section 15.1 the modern way, which builds position into the query–key score itself.
6.6 Multi-Head AttentionRun this section
One attention computation gives one set of weights per query, so linking a verb to its subject and a pronoun to its noun must blend into one average. Instead, run several smaller attention computations, heads, side by side, each with its own projections, and join the results:
is the number of heads, and means concatenate along the feature axis. and make head 's queries, keys and values; the output projection maps the joined outputs back to model width. Usually : the paper uses and , so , and eight heads cost about the same as one head of width 512.
In words. Each head projects the tokens to its own 64 features and runs full attention there. The labels are patterns heads in trained models have been seen to learn; nobody assigns them. The outputs are joined and mixed by one output projection.
Each head has its own query and key projections, so each computes its own attention table over the same tokens. Together the tables stack into one tensor, a layer per head. Pick a head to bring its table forward, and a query word to see where each head sends it.
Pick the query word it and look at the four heads. Before you do, guess which head's weights would let the model work out what it refers to.
In words. Four heads read "The animal didn't cross the street because it was tired", with hand-set weights mimicking trained models: one looks at the previous word, one sends "it" to "animal", one sends each verb to its subject, and one attends to the sentence start and "because". The four tables stack into one tensor, a layer per head.
Why the Output Projection Is Needed
- It mixes the heads. After joining, each head occupies its own 64 features; every output feature of combines all 512, so it can use what every head found.
- It writes back into the shared vector. Each layer adds its output to the token's vector (the residual stream, section 7.2), and lets each head write in any direction of it, not just its own slice. It also fixes the shape when .
The Cost of Multi-Head Attention
Costs are counted in FLOPs (floating-point operations). For tokens, counting multiply-adds:
- Projecting queries, keys and values for all heads: three by products, .
- The scores : each head multiplies by , costing . Over heads that is , because .
- The weighted sum : likewise .
- The output projection : .
Adding up (the softmax is small and left out):
(Counting multiply and add separately doubles both terms; the comparison is unchanged.) The first term grows with , the second with , and the second wins when , that is, . Past that length the score table dominates compute and memory. This is why long contexts are expensive.
Exercises
In one sentence each, what are the query, the key and the value of a token for?
Scores for one query are (already scaled). Compute the attention output when the values are the scalars .
Using the rules of section 3.2, prove that when is a sum of independent products, each with mean 0 and variance 1.
Write the causal mask for three tokens, and say what the softmax weights of the first row must be whatever the scores are.
For , at what sequence length does the term of multi-head attention's cost overtake the term?
What does a head compute if its softmax weights are exactly uniform over all tokens? Why is that not useless?
Show that self-attention without a mask or positions is permutation-equivariant: if the rows of are reordered by a permutation matrix , the output rows are reordered the same way.
Core Academic References
- Vaswani et al. (2017): Attention Is All You Need. NeurIPS 2017. arXiv:1706.03762
- Bahdanau, Cho & Bengio (2014): Neural Machine Translation by Jointly Learning to Align and Translate. ICLR 2015. arXiv:1409.0473
- Lee et al. (2019): Set Transformer: A Framework for Attention-based Permutation-Invariant Neural Networks. ICML 2019. arXiv:1810.00825
Measured labs
These labs test what this module says by running real code. Each card states the idea, what the experiment found, and what it does not prove. The numbers come from experiments/results.json, the output of running experiments/run_all.sh on the tiny-transformers reference code at version 137f7ef. The project checks fail if a measured number in the module text stops matching that file.
Lab 2b — why attention divides by √d_k, measured
What the module says
Section 6.3 shows that if every entry of the query and key is random with mean 0 and variance 1, their dot product has variance , the vector length. Dividing by brings the variance back to 1. Without that division, scores grow with , softmax puts nearly all weight on one key, and the gradient nearly vanishes.
What the experiment found
Over 200,000 random draws for each vector length, the variance divided by is 0.9987, 1.0040, 1.0029 and 1.0038 for : essentially 1 each time, as the math predicts. After dividing by the variance is about 1.0. The softmax effect varies from draw to draw, so it is reported as a share of trials. With and 64 keys, 35% of unscaled trials put more than 0.99 of the weight on one key, against 0% of scaled trials. In those peaked trials the gradient term for the top key averages 0.0020.
- variance ÷ at
- 0.9987
- variance ÷ at
- 1.0029
- variance after dividing by ,
- 1.0038
- share of trials with top weight above 0.99
- 0.35 unscaled → 0 scaled
- gradient term in the peaked trials
- 0.00202255
the math predicts 1
the math predicts 1
stays near 1 whatever is
500 trials, 64 keys,
the gradient the module says vanishes
What this does not prove
Why the result is reported this way. Whether softmax becomes peaked depends on the random draw: one draw puts more than 0.99 on a single key and the next does not, so a single draw proves nothing and the lab reports a share of trials instead. The lab also reports rather than the size of the whole gradient matrix, because is largest at : the matrix can grow while the term that matters is falling toward zero.
Run it yourself
cd tiny-transformers && .venv/bin/python experiments/variance_scaling.pyThe code being tested