Chapter 4 · Section 4.3 · 60 min

Scaled dot-product attention

Take the attention head from §4.2, make it the size real models use, say dk=512d_k = 512, initialize it the standard way so that queries and keys have unit-variance entries, compute the scores as QK⊤\mathbf{Q}\mathbf{K}^\top exactly as that section did, and look at the attention weights before any training. Most rows are nearly one-hot. Each query has already "decided" on a single key, at random, and the gradient flowing back through the softmax is close to zero. The head cannot learn, because it is stuck in the hard lookup that §4.1 worked so hard to escape.

The fix is one division, and it is the reason the formula in every Transformer paper looks the way it does,

Attention⁡(Q,K,V)=softmax⁡ ⁣(QK⊤dk)V.\operatorname{Attention}(\mathbf{Q}, \mathbf{K}, \mathbf{V}) = \operatorname{softmax}\!\left(\frac{\mathbf{Q}\mathbf{K}^\top}{\sqrt{d_k}}\right)\mathbf{V}.

This section derives the dk\sqrt{d_k} from a variance argument, shows exactly how the gradient dies without it, and then does the thing every lab interview eventually asks for. We derive the backward pass of attention by hand and check it against numerical gradients.

The formula, piece by piece

Fix one head. The queries are Q∈RTq×dk\mathbf{Q} \in \R^{T_q\times d_k}, the keys K∈RTk×dk\mathbf{K} \in \R^{T_k\times d_k}, and the values V∈RTk×dv\mathbf{V} \in \R^{T_k\times d_v}, as in §4.2 (a batch dimension, and later a head dimension, ride along in front). Scaled dot-product attention computes three matrices,

S=QK⊤dk∈RTq×Tk,A=softmax⁡(S)∈RTq×Tk,O=AV∈RTq×dv,\mathbf{S} = \frac{\mathbf{Q}\mathbf{K}^\top}{\sqrt{d_k}} \in \R^{T_q\times T_k}, \qquad \mathbf{A} = \operatorname{softmax}(\mathbf{S}) \in \R^{T_q\times T_k}, \qquad \mathbf{O} = \mathbf{A}\mathbf{V} \in \R^{T_q\times d_v},

where the softmax acts on each row of S\mathbf{S} separately, so aij=esij/∑lesila_{ij} = e^{s_{ij}}/\sum_l e^{s_{il}} and every row of A\mathbf{A} sums to 1.

In plain words, score every query against every key, shrink the scores by the square root of the key width, turn each query's scores into weights, and average the values with them.

In the language of §4.1, dividing by dk\sqrt{d_k} is a soft lookup at temperature τ=dk\tau = \sqrt{d_k}. The question is why that particular temperature.

Why dot products grow with the width

Suppose that at initialization the entries of a query q\mathbf{q} and a key k\mathbf{k} are independent random variables with mean 0 and variance 1. This is roughly true in a freshly initialized network whose inputs have been normalized (LayerNorm, §5.2) and whose projections use a variance-preserving initialization (§0.7). The score is a sum of dkd_k products,

q⊤k=∑m=1dkqmkm.\mathbf{q}^\top\mathbf{k} = \sum_{m=1}^{d_k} q_m k_m .

Each term has mean E[qmkm]=E[qm] E[km]=0\mathbb{E}[q_m k_m] = \mathbb{E}[q_m]\,\mathbb{E}[k_m] = 0 by independence. Its variance is

Var⁡(qmkm)=E[qm2km2]−(E[qmkm])2=E[qm2] E[km2]−0=1⋅1=1.\operatorname{Var}(q_m k_m) = \mathbb{E}[q_m^2 k_m^2] - \big(\mathbb{E}[q_m k_m]\big)^2 = \mathbb{E}[q_m^2]\,\mathbb{E}[k_m^2] - 0 = 1 \cdot 1 = 1 .

The dkd_k terms are independent of each other (they involve different coordinates), so their variances add,

E[q⊤k]=0,Var⁡(q⊤k)=∑m=1dkVar⁡(qmkm)=dk.\mathbb{E}[\mathbf{q}^\top\mathbf{k}] = 0, \qquad \operatorname{Var}(\mathbf{q}^\top\mathbf{k}) = \sum_{m=1}^{d_k}\operatorname{Var}(q_m k_m) = d_k .

In plain words, the typical size of a raw score is dk\sqrt{d_k}. Double the key width and the scores grow by a factor of 2\sqrt 2, for no reason other than that there are more terms in the sum.

Dividing by dk\sqrt{d_k} undoes exactly that growth, since Var⁡(q⊤k/dk)=dk/dk=1\operatorname{Var}(\mathbf{q}^\top\mathbf{k}/\sqrt{d_k}) = d_k/d_k = 1. The scaled scores have unit variance at every width. (If the entries have variances σq2\sigma_q^2 and σk2\sigma_k^2 instead of 1, the same steps give Var⁡(q⊤k)=dkσq2σk2\operatorname{Var}(\mathbf{q}^\top\mathbf{k}) = d_k\sigma_q^2\sigma_k^2, and the scaling still removes the dependence on dkd_k.) This is the argument in footnote 4 of Vaswani et al. (2017), which also notes that additive attention outperformed unscaled dot-product attention at large dkd_k. It is also Fact 1 of §1.3 in a new role. There it explained why random vectors are nearly orthogonal. Here it explains why their raw dot products are large.

Python · cell 1

What large scores do to the softmax

Why should we care that scores have standard deviation dk\sqrt{d_k} rather than 1? Because softmax only sees differences between scores, and when the differences are large the softmax saturates. If the largest score in a row beats the runner-up by 10, the winner's weight is at least e10/(e10+T−1)e^{10}/(e^{10} + T - 1), which for T=32T = 32 keys is 0.9986. The lookup has become hard, and §4.1 told us that a hard lookup has no gradient. To see how little gradient is left, we need the derivative of the softmax as a matrix.

The Jacobian of softmax, and what saturation does to it

Write one row of scores as s∈Rn\mathbf{s} \in \R^n and its softmax as a\mathbf{a}. §0.2 derived the softmax Jacobian with the quotient rule (and §4.1 used its entries, ∂ai/∂sj=ai(1[i=j]−aj)\partial a_i/\partial s_j = a_i(\mathbb{1}[i=j] - a_j)). As a matrix,

∂a∂s=diag⁡(a)−aa⊤  ∈  Rn×n.\frac{\partial \mathbf{a}}{\partial \mathbf{s}} = \operatorname{diag}(\mathbf{a}) - \mathbf{a}\mathbf{a}^\top \;\in\; \R^{n\times n}.

Recall its three properties from that section. It is symmetric, its rows sum to zero (shift invariance again), and it is positive semidefinite, because for any u∈Rn\mathbf{u} \in \R^n

u⊤(diag⁡(a)−aa⊤)u=∑iaiui2−(∑iaiui)2=Var⁡a(u)≥0,\mathbf{u}^\top\big(\operatorname{diag}(\mathbf{a}) - \mathbf{a}\mathbf{a}^\top\big)\mathbf{u} = \sum_i a_i u_i^2 - \Big(\sum_i a_i u_i\Big)^2 = \operatorname{Var}_{\mathbf{a}}(u) \ge 0,

the variance of the numbers uiu_i when entry ii is chosen with probability aia_i. Two consequences matter for attention.

The first is a single number for how much gradient can pass. The trace of the Jacobian, the sum of its eigenvalues, is ∑iai(1−ai)=1−∥a∥2\sum_i a_i(1 - a_i) = 1 - \lVert\mathbf{a}\rVert^2. It is largest, 1−1/n1 - 1/n, for uniform weights, and it shrinks to 0 as the weights concentrate.

The second is the punchline. If a\mathbf{a} is one-hot, then every variance under a\mathbf{a} is zero, so the quadratic form vanishes for every u\mathbf{u}, and a symmetric positive semidefinite matrix with a zero quadratic form is the zero matrix. A saturated softmax has a zero Jacobian. No gradient reaches the scores, and therefore none reaches WQ\mathbf{W}_Q or WK\mathbf{W}_K. The head's attention pattern is frozen wherever it happened to land at initialization, exactly the stuck query of Exercise 4.1e.

In backpropagation we never build this n×nn\times n matrix. We only need its product with the upstream gradient g=∂L/∂a\mathbf{g} = \partial\mathcal{L}/\partial\mathbf{a}, the O(n)O(n) vector-Jacobian product you wrote in Exercise 0.2c,

∂L∂s=(diag⁡(a)−aa⊤)g=a⊙(g−(a⊤g)1).\frac{\partial\mathcal{L}}{\partial\mathbf{s}} = \big(\operatorname{diag}(\mathbf{a}) - \mathbf{a}\mathbf{a}^\top\big)\mathbf{g} = \mathbf{a}\odot\big(\mathbf{g} - (\mathbf{a}^\top\mathbf{g})\mathbf{1}\big).

In plain words, each score's gradient is its weight times how much its upstream gradient exceeds the weighted average upstream gradient. With a one-hot a\mathbf{a}, the winner's term is 1⋅(gj⋆−gj⋆)=01\cdot(g_{j^\star} - g_{j^\star}) = 0 and every other term has weight 0, which is the punchline again, in one line.

Saturation, measured

Now we can measure what scaling buys. For each width, draw random queries and 32 random keys, compute the attention weights with and without the division by dk\sqrt{d_k}, and record the largest weight in each row and the trace of the softmax Jacobian (1−∥a∥21 - \lVert\mathbf{a}\rVert^2, which is 0 for one-hot rows).

Python · cell 2

Without scaling, the average largest weight climbs from 0.35 at dk=4d_k = 4 to 0.96 at dk=1024d_k = 1024, and the gradient capacity (the trace) falls more than tenfold. With scaling, both numbers stay put at every width, about 0.16 and 0.93. The head starts out soft whatever its size, and its sharpness becomes something it learns rather than an accident of dkd_k.

What happens to softmax as d_k grows, with and without the 1/√d_k?
Each query is scored against 16 random keys with unit-variance entries. Left, one query's weights, largest first. Right, averages over 64 queries for every width.
Loading interactive figure…

Saturation has a mirror image. If scores are tiny compared to 1, the weights are nearly uniform, aj≈1/Tka_j \approx 1/T_k, and by the formula ∂o/∂sj=aj(vj−o)\partial\mathbf{o}/\partial s_j = a_j(\mathbf{v}_j - \mathbf{o}) of §4.1 each score receives a gradient of order 1/Tk1/T_k. Unit-variance scores sit between the two extremes, soft enough for every key to receive gradient and sharp enough that the weights are not all the same.

The assumption behind the argument, and when it fails

The variance argument assumes that queries and keys are independent. That is true at initialization and false after training, because the whole point of learning WQ\mathbf{W}_Q and WK\mathbf{W}_K is to make the query of "it" align with the key of "animal". Suppose a key is correlated with its query, k=ρq+1−ρ2 z\mathbf{k} = \rho\mathbf{q} + \sqrt{1-\rho^2}\,\mathbf{z} with z\mathbf{z} independent noise. Then E[q⊤k]=ρ E∥q∥2=ρdk\mathbb{E}[\mathbf{q}^\top\mathbf{k}] = \rho\,\mathbb{E}\lVert\mathbf{q}\rVert^2 = \rho d_k, so the scaled score has mean ρdk\rho\sqrt{d_k}, which still grows with width (Exercise 4.3d derives the variance too). Aligned vectors have dot products that grow like dkd_k, by the law of large numbers, not like dk\sqrt{d_k}.

This is why the Maximal Update Parametrization (μ\muP) of Yang et al. (2022) scales attention scores by 1/dk1/d_k instead of 1/dk1/\sqrt{d_k}. Their analysis of how quantities evolve during training, as width grows, predicts that queries and keys become correlated, and 1/dk1/d_k is the scaling that keeps the logits of a trained model stable across widths, which is what makes hyperparameters transfer from small models to large ones (§9.5). Other practical answers to growing logits include normalizing queries and keys before the dot product, QK-norm (Henry et al. 2020). Dehghani et al. (2023) adopted it for their 22-billion-parameter ViT after finding that, already at about 8 billion parameters, attention logits grew to huge values, the weights became nearly one-hot, and training diverged after a few thousand steps (§5.7). And some implementations fold the 1/dk1/\sqrt{d_k} into the initialization of WQ\mathbf{W}_Q rather than into the forward pass. T5's is one. Its query weights are initialized with a standard deviation smaller by a factor of dk\sqrt{d_k} than its key weights, and the scores are never divided. At initialization the two choices are identical. During training they differ slightly, because an optimizer such as Adam takes steps of a similar size whatever the scale of a weight, so the effective learning rate of the folded-in version is different.

choicescores at initideaused by
no scalingstd dk\sqrt{d_k}none, saturates at large dkd_kearly dot-product attention (Luong et al. 2015)
1/dk1/\sqrt{d_k}std 1keep logits unit-variance at initthe original Transformer and nearly every LLM
1/dk1/d_kstd 1/dk1/\sqrt{d_k}keep trained, correlated logits stable across widthμ\muP
scale folded into WQ\mathbf{W}_Q initstd 1same as 1/dk1/\sqrt{d_k}, no division in the forward passT5
QK-normboundednormalize q\mathbf{q} and k\mathbf{k}, often with a learned gainViT-22B, several recent LLMs
Interview

Scaled dot-product attention with an optional mask

This is the most-asked coding question in the field. Implement scaled_dot_product_attention(Q, K, V, mask=None) for inputs of shape (..., T_q, d_k), (..., T_k, d_k), and (..., T_k, d_v) with any number of leading batch dimensions. mask, if given, is a boolean array broadcastable to (..., T_q, T_k) in which True means "may attend" (the PyTorch convention). Assume every query may attend to at least one key (§4.4 handles the other case). Return (O, A). It must be numerically stable and must give masked positions a weight of exactly zero.

Hidden tests, hints, and AI help, from $1.99 a month.

A vectorized implementation, and why stability is not optional

Here is the version we will use for the rest of the chapter. Every line is one equation from above.

Python · cell 3

The naive line fails in float16 for a score of only 12, because e12≈163,000e^{12} \approx 163{,}000 exceeds the largest float16 number, 65,504 (the cutoff is ln⁡65504≈11.09\ln 65504 \approx 11.09). In float32 the cutoff is about 88.7. Subtracting the row maximum fixes overflow completely, because the largest exponent becomes e0=1e^0 = 1 and the denominator is at least 1. Small exponents can still underflow to zero, but that is harmless, since those weights really are negligible. This is why production kernels subtract the maximum, and why mixed-precision training usually computes the softmax and its normalizer in float32 even when the matrix products run in bfloat16 or float16 (§8.5). FlashAttention goes one step further and computes the maximum and the normalizer incrementally, block by block, so the score matrix never has to exist in memory (§12.2).

The backward pass of attention

Now the derivation that separates people who have used attention from people who understand it. Given the upstream gradient dO=∂L/∂O∈RTq×dv\mathrm{d}\mathbf{O} = \partial\mathcal{L}/\partial\mathbf{O} \in \R^{T_q\times d_v}, we want dQ\mathrm{d}\mathbf{Q}, dK\mathrm{d}\mathbf{K}, and dV\mathrm{d}\mathbf{V}. (Here dX\mathrm{d}\mathbf{X} always means ∂L/∂X\partial\mathcal{L}/\partial\mathbf{X}, a matrix of the same shape as X\mathbf{X}, the convention of the FlashAttention papers.) Write c=1/dkc = 1/\sqrt{d_k} for the scale. The forward pass is three steps,

S=c QK⊤,A=softmax⁡rows(S),O=AV,\mathbf{S} = c\,\mathbf{Q}\mathbf{K}^\top, \qquad \mathbf{A} = \operatorname{softmax}_{\text{rows}}(\mathbf{S}), \qquad \mathbf{O} = \mathbf{A}\mathbf{V},

and we walk back through them in reverse, using index notation so that no step is a leap. Recall from §0.2 the rule for any product Y=XW\mathbf{Y} = \mathbf{X}\mathbf{W}, namely dX=dY W⊤\mathrm{d}\mathbf{X} = \mathrm{d}\mathbf{Y}\,\mathbf{W}^\top and dW=X⊤dY\mathrm{d}\mathbf{W} = \mathbf{X}^\top\mathrm{d}\mathbf{Y}. Each step below is that rule, checked by indices.

Step 1, through O=AV\mathbf{O} = \mathbf{A}\mathbf{V}. Entry by entry, Oik=∑jAijVjkO_{ik} = \sum_j A_{ij}V_{jk}. The entry VjkV_{jk} appears in OikO_{ik} for every query ii, with coefficient AijA_{ij}, so

∂L∂Vjk=∑idOik Aij⟹dV=A⊤dO  ∈  RTk×dv.\frac{\partial\mathcal{L}}{\partial V_{jk}} = \sum_i \mathrm{d}O_{ik}\,A_{ij} \quad\Longrightarrow\quad \mathrm{d}\mathbf{V} = \mathbf{A}^\top\mathrm{d}\mathbf{O} \;\in\; \R^{T_k\times d_v}.

The entry AijA_{ij} appears in OikO_{ik} for every kk, with coefficient VjkV_{jk}, so

∂L∂Aij=∑kdOik Vjk⟹dA=dO V⊤  ∈  RTq×Tk.\frac{\partial\mathcal{L}}{\partial A_{ij}} = \sum_k \mathrm{d}O_{ik}\,V_{jk} \quad\Longrightarrow\quad \mathrm{d}\mathbf{A} = \mathrm{d}\mathbf{O}\,\mathbf{V}^\top \;\in\; \R^{T_q\times T_k}.

Step 2, through the row-wise softmax. Each row of A\mathbf{A} depends only on the same row of S\mathbf{S}, so we apply the softmax vector-Jacobian product above to every row,

dSij=Aij(dAij−∑lAil dAil).\mathrm{d}S_{ij} = A_{ij}\Big(\mathrm{d}A_{ij} - \sum_l A_{il}\,\mathrm{d}A_{il}\Big).

The row sum simplifies nicely. Substituting dAil=∑kdOikVlk\mathrm{d}A_{il} = \sum_k \mathrm{d}O_{ik}V_{lk},

Di:=∑lAil dAil=∑kdOik∑lAilVlk=∑kdOik Oik,D_i := \sum_l A_{il}\,\mathrm{d}A_{il} = \sum_k \mathrm{d}O_{ik}\sum_l A_{il}V_{lk} = \sum_k \mathrm{d}O_{ik}\,O_{ik},

so DiD_i is just the dot product of row ii of dO\mathrm{d}\mathbf{O} with row ii of O\mathbf{O}, and

dS=A⊙(dA−D1⊤),D=rowsum⁡(dO⊙O)∈RTq.\mathrm{d}\mathbf{S} = \mathbf{A}\odot\big(\mathrm{d}\mathbf{A} - \mathbf{D}\mathbf{1}^\top\big), \qquad \mathbf{D} = \operatorname{rowsum}(\mathrm{d}\mathbf{O}\odot\mathbf{O}) \in \R^{T_q}.

Step 3, through S=c QK⊤\mathbf{S} = c\,\mathbf{Q}\mathbf{K}^\top. Entry by entry, Sij=c∑mQimKjmS_{ij} = c\sum_m Q_{im}K_{jm}. So QimQ_{im} appears in SijS_{ij} for every key jj, with coefficient cKjmcK_{jm}, and KjmK_{jm} appears for every query ii, with coefficient cQimcQ_{im},

dQ=c dS K  ∈  RTq×dk,dK=c dS⊤Q  ∈  RTk×dk.\mathrm{d}\mathbf{Q} = c\,\mathrm{d}\mathbf{S}\,\mathbf{K} \;\in\; \R^{T_q\times d_k}, \qquad \mathrm{d}\mathbf{K} = c\,\mathrm{d}\mathbf{S}^\top\mathbf{Q} \;\in\; \R^{T_k\times d_k}.

In plain words, the value gradient is the attention-weighted sum of output gradients, the score gradient is the softmax backward applied to dOV⊤\mathrm{d}\mathbf{O}\mathbf{V}^\top, and the query and key gradients come from the score gradient exactly as in any matrix product, times the scale.

Four observations make this derivation useful in practice.

  • Masks need no special handling. A masked entry has Aij=0A_{ij} = 0, so dSij=0\mathrm{d}S_{ij} = 0 automatically, and no gradient leaks through a masked connection.
  • The backward pass costs about twice the forward pass. The forward pass does two large matrix products (QK⊤\mathbf{Q}\mathbf{K}^\top and AV\mathbf{A}\mathbf{V}). The backward pass does four (dOV⊤\mathrm{d}\mathbf{O}\mathbf{V}^\top, A⊤dO\mathbf{A}^\top\mathrm{d}\mathbf{O}, dSK\mathrm{d}\mathbf{S}\mathbf{K}, dS⊤Q\mathrm{d}\mathbf{S}^\top\mathbf{Q}), each the same size. This is the attention version of the familiar rule that a backward pass costs twice a forward pass (§5.6).
  • The backward pass needs A\mathbf{A}, a Tq×TkT_q\times T_k matrix per head. Storing it for every layer is what makes naive attention memory-hungry (§4.7). FlashAttention instead stores only O\mathbf{O} and one number per row, the log-sum-exp of the scores, and recomputes A\mathbf{A} block by block during the backward pass (§12.3).
  • The identity Di=dOi⋅OiD_i = \mathrm{d}\mathbf{O}_i\cdot\mathbf{O}_i matters. Computing DiD_i from its definition needs a whole row of A\mathbf{A} and dA\mathrm{d}\mathbf{A} at once. Computing it from dO\mathrm{d}\mathbf{O} and O\mathbf{O} needs neither, which is exactly what lets FlashAttention's backward pass work one tile at a time.
Interview

The backward pass of attention, checked numerically

Implement attention_backward(Q, K, V, dO, mask=None) returning (dQ, dK, dV) for single-head scaled dot-product attention with Q of shape (T_q, d_k), K of shape (T_k, d_k), V of shape (T_k, d_v), upstream gradient dO of shape (T_q, d_v), and an optional boolean mask (True means attend, every row has at least one True). Recompute the forward pass inside the function. The tests compare your gradients with central finite differences of L=∑(dO⊙O)\mathcal{L} = \sum(\mathrm{d}\mathbf{O}\odot\mathbf{O}).

Hidden tests, hints, and AI help, from $1.99 a month.
Research

How big are the scores of aligned queries and keys?

Let q∼N(0,Idk)\mathbf{q} \sim \mathcal{N}(\mathbf{0}, \mathbf{I}_{d_k}), let z∼N(0,Idk)\mathbf{z} \sim \mathcal{N}(\mathbf{0}, \mathbf{I}_{d_k}) be independent of it, and let k=ρq+1−ρ2 z\mathbf{k} = \rho\mathbf{q} + \sqrt{1-\rho^2}\,\mathbf{z} for a correlation ρ∈[0,1]\rho\in[0,1]. Derive the mean and variance of the scaled score q⊤k/dk\mathbf{q}^\top\mathbf{k}/\sqrt{d_k} in closed form, and implement scaled_score_moments(d_k, rho) returning (mean, var). The tests check your formula against simulation. Then explain, in a comment, what your formula says about 1/dk1/\sqrt{d_k} versus 1/dk1/d_k scaling.

Hidden tests, hints, and AI help, from $1.99 a month.

In PyTorch

PyTorch's scaled_dot_product_attention computes exactly our formula, and dispatches to a fused FlashAttention or memory-efficient kernel when one is available. It also takes dropout_p, which during training zeroes attention weights at random and rescales the rest, as GPT-2 and BERT do at a rate of 0.1. Most recent large language models train with it set to zero. Below we check the function against our NumPy version, then check our hand-derived backward pass against autograd.

🔥 In PyTorchfor a machine with PyTorch

Read more

Watch next

🎬 Let's build GPT: from scratch, in code, spelled out. · Andrej Karpathy · starts at 76:56A two-minute demonstration of why the scores are divided by the square root of the head size, and what softmax does when they are not.
🎬 Attention is all you need (Transformer) - Model explanation (including math), Inference and Training · Umar JamilA careful whiteboard pass over the attention formula and its shapes, useful as a second explanation.