Scaled Dot-Product Attention

Imagine a translation model deciding which source words matter. It is generating the word "it" in a long sentence. It must compare a query against every candidate word. The comparison produces a soft weighting. The natural comparison operator is a dot product. It is cheap to compute. It measures alignment between vectors. But as the dimensionality of these vectors grows, raw dot products can explode in magnitude. This silently breaks the training dynamics of the network that computes them. Scaled dot-product attention is the fix. It made self-attention trainable at the scale used in modern transformers. It is a small but critical arithmetic correction. It divides the similarity scores by dk\sqrt{d_k} before applying softmax. Here dkd_k is the dimension of the key vectors. This single division keeps the softmax function operating in a useful regime. In this regime, gradients are informative rather than vanishing. The idea matters for a clear reason. It is the exact formula sitting inside every transformer layer. This includes GPT, BERT, T5, and virtually every large language model built since 2017. Understanding why the scale factor is dk\sqrt{d_k} requires some reasoning. It is not some other constant by chance. The reasoning involves variance under a simple statistical model of embeddings. This is a compact and beautiful piece of applied probability. It pays for itself in training stability. This article derives the formula from first principles. It walks through the algorithm step by step with pseudocode. It shows a full worked numerical trace. It explains precisely why the scaling term is necessary. The term is not a heuristic afterthought. This article sets up the machinery needed to understand Multi-Head Attention and Masked Self-Attention. Both of these build directly on this operation.

Key takeaways
  • Scaled dot-product attention computes softmax(QK⊤/dk)V\mathrm{softmax}(QK^\top/\sqrt{d_k})V, turning queries, keys, and values into a weighted mixture of values.
  • Dividing by dk\sqrt{d_k} counteracts the growth in variance of dot products as vector dimension increases.
  • Without scaling, softmax inputs can saturate, driving gradients toward zero and stalling learning.
  • The scale factor follows from a simple independence assumption: if components have unit variance, the dot product's variance grows linearly with dkd_k.
  • The operation costs O(n2d)O(n^2 d) time and O(n2)O(n^2) space for sequence length nn and dimension dd, dominating transformer compute.
  • It is the atomic operation inside every attention head, later composed into Multi-Head Attention and specialized with masks in Masked Self-Attention.
The core insight

Dividing attention scores by dk\sqrt{d_k} keeps softmax inputs in a numerically well-behaved range, preventing the vanishing-gradient collapse that unscaled dot products cause as dimension grows.

The idea

Scaled dot-product attention is a function that maps a set of queries QQ, keys KK, and values VV to a weighted combination of the values. Each query is compared against every key using a dot product, producing a raw similarity score. These scores are scaled, converted into a probability distribution via softmax, and used as weights to combine the value vectors. Formally, for query matrix Q∈Rn×dkQ \in \mathbb{R}^{n \times d_k}, key matrix K∈Rn×dkK \in \mathbb{R}^{n \times d_k}, and value matrix V∈Rn×dvV \in \mathbb{R}^{n \times d_v},

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

The term QK⊤QK^\top produces an n×nn \times n matrix of unnormalized similarity scores — one row per query, one column per key. The division by dk\sqrt{d_k} is the scaling step that gives this mechanism its name, distinguishing it from plain "dot-product attention," which omits the factor and was observed empirically to train worse for large dkd_k. The word "scaled" is not decorative. It encodes a specific engineering fix motivated by a variance argument: as the dimensionality dkd_k of query and key vectors increases, the magnitude of their dot product tends to increase as well, even when the vectors themselves are drawn from a fixed, dimension-independent distribution. Left unscaled, this growth pushes the softmax function into a regime with extremely peaked outputs and near-zero gradients almost everywhere — the same saturation phenomenon that plagues sigmoid units fed large inputs. The scale factor dk\sqrt{d_k} is chosen precisely to cancel this growth, restoring the softmax's input to an O(1)O(1) variance regime regardless of how large dkd_k becomes.

How it works

The mechanism proceeds in four steps: project inputs into queries, keys, and values (already assumed available from the Self-Attention Mechanism setup); compute pairwise similarity scores via matrix multiplication; scale and normalize those scores into attention weights with softmax; and use the weights to produce a weighted sum of the value vectors.

Step 1 — Score computation. For every query vector qiq_i and key vector kjk_j, compute the raw score sij=qi⋅kjs_{ij} = q_i \cdot k_j. Doing this for all pairs simultaneously is exactly the matrix product QK⊤QK^\top, an n×nn \times n matrix.

Step 2 — Scaling. Divide every entry by dk\sqrt{d_k}:

s~ij=sijdk.\tilde{s}_{ij} = \frac{s_{ij}}{\sqrt{d_k}}.

Step 3 — Normalization. Apply softmax row-wise so each query's scores become a probability distribution over keys:

αij=exp⁡(s~ij)∑l=1nexp⁡(s~il).\alpha_{ij} = \frac{\exp(\tilde{s}_{ij})}{\sum_{l=1}^{n} \exp(\tilde{s}_{il})}.

Step 4 — Weighted aggregation. Compute the output for query ii as the weighted sum of value vectors: oi=∑jαijvjo_i = \sum_j \alpha_{ij} v_j. In matrix form this is αV\alpha V. An optional mask step can be inserted between scaling and softmax to zero out (via −∞-\infty) forbidden connections — this is the hook that Masked Self-Attention uses to prevent a decoder from attending to future tokens. ``` function ScaledDotProductAttention(Q, K, V, mask = None):

# Q: n_q x d_k K: n_k x d_k V: n_k x d_v d_k := number_of_columns(K) S := MatMul(Q, Transpose(K)) # n_q x n_k raw similarity scores S := S / sqrt(d_k) # scale step — the crux of this article if mask is not None: for i in range(n_q): for j in range(n_k): if mask[i][j] == BLOCKED: S[i][j] := -infinity # forces softmax weight -> 0 A := SoftmaxRowwise(S) # n_q x n_k attention weights, rows sum to 1 O := MatMul(A, V) # n_q x d_v output return O, A # A often returned for interpretability/analysis

function SoftmaxRowwise(S): for each row r in S: m := max(r) # numerical stability: subtract row max exps := [exp(x - m) for x in r] total := sum(exps) r := [e / total for e in exps] return S ``` Two implementation details matter for correctness. First, the row-wise max subtraction inside softmax is a numerically stability trick (it does not change the mathematical result, since softmax is invariant to additive shifts per row) but it is essential in floating point, since exp⁡\exp overflows quickly. Second, masking is applied by additive −∞-\infty (or a very large negative number in practice, such as −109-10^9) before the exponential, so that masked positions vanish from the normalization rather than being clipped afterward, which would leave probability mass unaccounted for.

Figure
The scaled dot-product attention pipeline: from Q, K, V to a weighted output
Q (n×d_k) K (n×d_k) V (n×d_v) Q Kᵀ n × n scores ÷ √d_k variance fix mask (optional) softmax row-wise A · V weighted sum Output O peaked or flat weights ∑=1

Complexity & correctness

Time complexity. Computing QK⊤QK^\top multiplies an n×dkn \times d_k matrix by a dk×nd_k \times n matrix, costing O(n2dk)O(n^2 d_k) scalar multiply-adds. The scaling and masking steps touch every entry of an n×nn \times n matrix, costing O(n2)O(n^2). Row-wise softmax also costs O(n2)O(n^2) (each of nn rows requires O(n)O(n) work for max, exponentials, sum, and division). The final product AVAV multiplies an n×nn \times n matrix by an n×dvn \times d_v matrix, costing O(n2dv)O(n^2 d_v). Summing these, the total time is

O(n2dk+n2dv)=O(n2d)O(n^2 d_k + n^2 d_v) = O(n^2 d)

treating dk,dvd_k, d_v as a common order-of-magnitude dimension dd. This is the well-known quadratic-in-sequence-length cost of self-attention, and it is the reason long-context transformers require sparse or linear-attention approximations for very large nn.

Space complexity. The intermediate score matrix SS (and its softmax-normalized version AA) is n×nn \times n, so the mechanism requires O(n2)O(n^2) memory in addition to O(nd)O(nd) for the inputs and outputs. For a sequence of length n=2048n = 2048 this is over four million floats per attention head — the dominant memory cost in naive transformer implementations, and the motivation behind memory-efficient variants such as FlashAttention (which recomputes rather than materializes AA in full).

Correctness of the scaling constant. The choice of dk\sqrt{d_k} is not arbitrary; it follows from a variance calculation. Assume each component of qq and kk is drawn independently with mean 00 and variance 11 (a reasonable approximation immediately after typical weight initialization and layer normalization). Then the dot product is

q⋅k=∑i=1dkqiki.q \cdot k = \sum_{i=1}^{d_k} q_i k_i .

Each term qikiq_i k_i has mean E[qi]E[ki]=0\mathbb{E}[q_i]\mathbb{E}[k_i] = 0 (by independence of qi,kiq_i, k_i) and variance

Var(qiki)=E[qi2ki2]−(E[qiki])2=E[qi2] E[ki2]=1⋅1=1,\mathrm{Var}(q_i k_i) = \mathbb{E}[q_i^2 k_i^2] - (\mathbb{E}[q_i k_i])^2 = \mathbb{E}[q_i^2]\,\mathbb{E}[k_i^2] = 1 \cdot 1 = 1,

using independence of qiq_i and kik_i and E[qi2]=Var(qi)=1\mathbb{E}[q_i^2] = \mathrm{Var}(q_i) = 1. Since the dkd_k terms are independent, variances add:

Var(q⋅k)=∑i=1dkVar(qiki)=dk.\mathrm{Var}(q \cdot k) = \sum_{i=1}^{d_k} \mathrm{Var}(q_i k_i) = d_k .

So the standard deviation of the raw dot product grows as dk\sqrt{d_k}. Dividing by dk\sqrt{d_k} restores unit variance:

Var ⁣(q⋅kdk)=dkdk=1,\mathrm{Var}\!\left(\frac{q\cdot k}{\sqrt{d_k}}\right) = \frac{d_k}{d_k} = 1,

regardless of how large dkd_k is. This is exactly the guarantee needed: the input distribution to softmax stays at a fixed scale as the model's hidden dimension grows, instead of drifting toward extreme values that make softmax behave like a hard argmax.

Why unscaled scores hurt training. Softmax's Jacobian involves terms of the form αi(δij−αj)\alpha_i(\delta_{ij} - \alpha_j). When the input scores have large magnitude, softmax saturates: one score dominates, its weight approaches 11, all others approach 00, and αi(1−αi)→0\alpha_i(1-\alpha_i) \to 0 for the dominant index and αiαj→0\alpha_i \alpha_j \to 0 for the rest. Consequently gradients backpropagated through softmax shrink toward zero across almost the entire output — precisely the vanishing-gradient problem. Because Var(q⋅k)\mathrm{Var}(q\cdot k) scales linearly with dkd_k, larger head dimensions make this saturation more severe unless corrected; the dk\sqrt{d_k} divisor is the minimal correction that keeps the variance constant across all choices of dkd_k, which is why it appears as a square root rather than a linear or logarithmic factor.

Tradeoff. The scaling constant is derived under an idealized independence and unit-variance assumption that need not hold exactly once queries and keys are learned rather than random; in practice it is an approximation that works remarkably well empirically and is validated by every major transformer architecture, but it is not a proof that gradients remain healthy under all trained weight distributions — layer normalization elsewhere in the network is what keeps the assumption approximately true throughout training.

Worked example

Consider a toy setting with sequence length n=3n = 3 and key/query dimension dk=4d_k = 4. Suppose after the query and key projections we have:

Q=[101001011100],K=[110000111010]Q = \begin{bmatrix} 1 & 0 & 1 & 0 \\ 0 & 1 & 0 & 1 \\ 1 & 1 & 0 & 0 \end{bmatrix}, \qquad K = \begin{bmatrix} 1 & 1 & 0 & 0 \\ 0 & 0 & 1 & 1 \\ 1 & 0 & 1 & 0 \end{bmatrix}

Step 1: raw scores QK⊤QK^\top. Row 1 of QQ is (1,0,1,0)(1,0,1,0); dotting with each row of KK:

  • vs. K1=(1,1,0,0)K_1 = (1,1,0,0): 1⋅1+0⋅1+1⋅0+0⋅0=11\cdot1+0\cdot1+1\cdot0+0\cdot0 = 1
  • vs. K2=(0,0,1,1)K_2 = (0,0,1,1): 1⋅0+0⋅0+1⋅1+0⋅1=11\cdot0+0\cdot0+1\cdot1+0\cdot1 = 1
  • vs. K3=(1,0,1,0)K_3 = (1,0,1,0): 1⋅1+0⋅0+1⋅1+0⋅0=21\cdot1+0\cdot0+1\cdot1+0\cdot0 = 2

Repeating for rows 2 and 3 of QQ gives the full score matrix:

S=QK⊤=[112110101]S = QK^\top = \begin{bmatrix} 1 & 1 & 2 \\ 1 & 1 & 0 \\ 1 & 0 & 1 \end{bmatrix}

Step 2: scale. With dk=4d_k = 4, dk=2\sqrt{d_k} = 2:

S~=S/2=[0.50.51.00.50.50.00.50.00.5]\tilde{S} = S / 2 = \begin{bmatrix} 0.5 & 0.5 & 1.0 \\ 0.5 & 0.5 & 0.0 \\ 0.5 & 0.0 & 0.5 \end{bmatrix}

Step 3: softmax per row. For row 1, exp⁡(0.5)≈1.6487\exp(0.5) \approx 1.6487, exp⁡(1.0)≈2.7183\exp(1.0) \approx 2.7183. Sum =1.6487+1.6487+2.7183=6.0157= 1.6487+1.6487+2.7183 = 6.0157. Weights: 0.274,0.274,0.4520.274, 0.274, 0.452.

RowRaw scoresScaled scoresSoftmax weights
11,1,21,1,20.5,0.5,1.00.5,0.5,1.00.274,0.274,0.4520.274, 0.274, 0.452
21,1,01,1,00.5,0.5,0.00.5,0.5,0.00.422,0.422,0.1570.422, 0.422, 0.157
31,0,11,0,10.5,0.0,0.50.5,0.0,0.50.422,0.157,0.4220.422, 0.157, 0.422

Now compare against what happens without scaling (dividing by 11 instead of 22), using the raw scores directly in softmax for row 1: exp⁡(1)=2.718\exp(1)=2.718, exp⁡(1)=2.718\exp(1)=2.718, exp⁡(2)=7.389\exp(2)=7.389, sum =12.825=12.825, weights 0.212,0.212,0.5760.212, 0.212, 0.576. The unscaled distribution is already visibly more peaked on this tiny example (0.5760.576 vs. 0.4520.452 on the top choice). In a real transformer dkd_k is typically 6464 or larger, so raw scores have standard deviation around 64=8\sqrt{64}=8 rather than 22; feeding scores with standard deviation 88 into softmax produces near one-hot distributions almost everywhere, exactly the saturated regime that kills gradient flow. The scale-by-22 step above is a miniature version of the same correction that, at realistic dimensions, is the difference between a trainable and an untrainable network.

Step 4: weighted sum. Suppose

V=[100111].V = \begin{bmatrix} 1 & 0 \\ 0 & 1 \\ 1 & 1 \end{bmatrix}.

Output for row 1: 0.274 (1,0)+0.274 (0,1)+0.452 (1,1)=(0.726,0.726)0.274\,(1,0) + 0.274\,(0,1) + 0.452\,(1,1) = (0.726, 0.726). This vector is the attention-weighted blend of value vectors for the first query — a soft interpolation dominated by, but not exclusively determined by, the third key/value pair.

Common pitfalls & traps

PitfallWhy it happensConsequence
Forgetting the dk\sqrt{d_k} divisor entirelyCopying attention formula without the scale termSoftmax saturates for large dkd_k; gradients vanish, training stalls or diverges
Scaling by dkd_k instead of dk\sqrt{d_k}Confusing variance (dkd_k) with standard deviation (dk\sqrt{d_k})Over-scaling flattens attention weights toward uniform, discarding useful signal
Applying mask after softmax by zeroing weightsTreating mask as a post-hoc filterRows no longer sum to 1; probability mass leaks, breaking the weighted-average semantics
Not subtracting row max before exponentiatingAssuming softmax formula is "just" exp/sumFloating-point overflow for large scores, producing `NaN` outputs
Using different dkd_k for queries and keysMismatched projection dimensions in buggy implementationsMatrix multiplication QK⊤QK^\top is undefined or silently wrong if reshaped incorrectly
Assuming scaling fixes all training instabilityTreating dk\sqrt{d_k} as a universal cureLayer normalization, learning-rate warmup, and careful initialization are still required

Pioneers & history

The scaled dot-product formula was introduced as part of the original transformer architecture, designed to replace recurrent and convolutional sequence models entirely with attention-based computation. The scaling term was explicitly justified in that work by the variance argument reproduced above: for small dkd_k, additive and dot-product attention perform comparably, but for large dkd_k, dot-product attention underperforms unless the scores are scaled down, because unscaled dot products push softmax into regions with extremely small gradients.

Origins · 1 minAshish Vaswani and how this was discovered
AV
Ashish Vaswani
active from 2010s · lead author of the transformer architecture at Google Brain, 2017

Vaswani and collaborators proposed the transformer to eliminate recurrence from sequence modeling entirely, relying solely on attention to model dependencies between positions regardless of their distance. The scaled dot-product formula, together with multi-head attention, formed the computational core of that architecture and has since become the default building block of essentially all large-scale language and vision models.

History
1990
s: attention-like alignment models emerge in statistical machine translation research.
2014
neural attention mechanisms for sequence-to-sequence translation popularize soft alignment between encoder and decoder states.
2015
additive (Bahdanau-style) attention becomes standard for improving neural machine translation quality.
2017
the transformer architecture introduces scaled dot-product attention and multi-head attention, removing recurrence entirely.
2018
onward: scaled dot-product attention becomes the core operation inside BERT, GPT, and virtually all subsequent large language models.

Where this matters

Scaled dot-product attention is the innermost computational kernel of every transformer-based system in production today. Large language models such as GPT-family models, PaLM, and LLaMA compute this exact formula, many times per layer, across dozens of layers, for every token generated. Encoder-only models like BERT use it to build bidirectional contextual representations for classification and retrieval tasks. Vision transformers apply the identical formula to patches of an image instead of tokens of text, treating image regions as a sequence to be attended over. Speech models, protein-structure models such as AlphaFold's attention-based modules, and recommendation systems built on transformer encoders all reuse this same scaled dot-product core. Efficient-attention research — sparse attention, linear attention, FlashAttention-style memory-efficient kernels — is fundamentally about approximating or accelerating this exact computation without changing its mathematical semantics, which underscores how central the scaling correction is to making the base operation trainable in the first place. Understanding this formula precisely is the necessary foundation for understanding Multi-Head Attention, which runs several scaled dot-product attentions in parallel with different learned projections, and Masked Self-Attention, which reuses the identical formula with an added masking step to enforce causality in autoregressive generation.

Ask the tutor: Why does the variance of a sum of independent random variables add, and how does that fact justify the dk\sqrt{d_k} scale factor specifically?

Why can't we just skip scaling and use a smaller learning rate instead?

A smaller learning rate slows all weight updates uniformly, but it does not fix the underlying problem: softmax saturation caused by large-variance scores makes gradients vanish almost everywhere in the attention weights themselves, not just make them large. Shrinking the learning rate reduces how far parameters move per step, but if the gradient is already near zero due to saturation, there is essentially nothing to shrink — training stalls regardless of step size. The scale factor fixes the actual statistical cause (variance growing with dkd_k) rather than papering over its symptom, and it does so without requiring any extra tuning, since dk\sqrt{d_k} is a fixed, known constant computed directly from the architecture's own dimensions.

Does scaled dot-product attention require queries and keys to have the same dimension as values?

No. The formula requires QQ and KK to share dimension dkd_k, since a dot product q⋅kq \cdot k only makes sense between equal-length vectors, but the value dimension dvd_v can differ freely. The output inherits dimension dvd_v because it is a weighted sum of value vectors. In practice many implementations set dk=dvd_k = d_v for simplicity and to keep parameter counts symmetric across heads in Multi-Head Attention, but nothing in the mathematics of scaled dot-product attention forces this equality.

Is √d_k the only possible scaling choice, or could another constant work?

The variance argument shows dk\sqrt{d_k} is the constant that exactly cancels the linear growth of Var(q⋅k)\mathrm{Var}(q\cdot k) with dkd_k, restoring unit variance regardless of head size. Other constants could reduce variance too, but they would either over-scale (excessively flattening attention, discarding useful contrast between scores) or under-scale (leaving residual growth as dkd_k increases, so the saturation problem returns at large enough dimension). Empirically, alternative scalings have been tried in ablations, and dk\sqrt{d_k} remains the standard choice because it is the theoretically motivated one and matches observed training stability across architectures and dimension choices.

How does scaled dot-product attention relate to additive attention?

Additive attention, used in earlier sequence-to-sequence models, computes compatibility scores using a small feedforward network applied to the concatenation (or sum) of query and key vectors, rather than a dot product. It is theoretically similar in expressive power but computationally more expensive, since it requires a matrix multiply plus a nonlinearity per query-key pair rather than a single dot product. Scaled dot-product attention was introduced specifically because dot products can be computed with highly optimized matrix multiplication routines, making it dramatically faster on modern hardware, provided the scaling correction is applied to match additive attention's performance at large dimensions.

Does the scaling factor change during training, or is it fixed?

It is a fixed constant, 1/dk1/\sqrt{d_k}, determined entirely by the architecture's chosen head dimension and never learned or adjusted during training. This is deliberate: the goal is to normalize the statistical scale of the raw scores based on a property of the architecture (how many dimensions are summed over), not to let the model learn away a numerical instability. Because dkd_k is fixed once the model architecture is chosen, the scale factor is computed once and reused for every forward and backward pass.

Why does this matter more as models get larger?

Larger transformer variants often use larger per-head dimensions or more heads, and the variance argument shows that Var(q⋅k)\mathrm{Var}(q \cdot k) grows linearly with dkd_k regardless of model scale. Without the dk\sqrt{d_k} correction, larger head dimensions would make softmax saturation systematically worse, meaning the largest and most capable models would suffer the most severe gradient vanishing. The scaling factor is precisely what keeps the attention mechanism numerically well-conditioned at every scale, from small research prototypes to production-scale language models with hundreds of billions of parameters.

Does scaling interact with layer normalization elsewhere in the transformer?

Yes, and the two work together rather than independently. Layer normalization (typically applied before or after each sublayer) keeps the inputs to the attention projections at a roughly fixed scale, which makes the unit-variance assumption behind the dk\sqrt{d_k} derivation approximately valid throughout training, not just at initialization. Without layer normalization, learned query and key projections could drift to arbitrary scales over training, at which point no fixed constant like dk\sqrt{d_k} could reliably counteract the resulting score variance. The two mechanisms are complementary safeguards against the same underlying failure mode.

Before this

Where this leads