Attention Mechanisms
- Bahdanau et al. (2014) introduced attention for machine translation as an alignment mechanism for seq2seq models
- Vaswani et al. (2017) generalized it to self-attention - the foundation of all modern LLMs
- Flash Attention (Dao et al. 2022) made attention memory-efficient for long sequences
Attention computes a weighted sum of values, where the weights are determined by compatibility between a query and a set of keys. Self-attention lets each token in a sequence attend to all other tokens, building context-aware representations.
- Self-attention is the core building block of the Transformer
- Cross-attention (queries from one sequence, keys/values from another) is used in encoder-decoder models and multimodal attention
- Connects to memory-augmented networks, retrieval augmentation (RAG), and graph attention networks
- Trace the lineage from Bahdanau additive attention through Luong multiplicative variants to scaled dot-product self-attention.
- Derive the scaled dot-product formula softmax(QK^T / sqrt(d_k)) V from a kernel-regression viewpoint and explain why the sqrt(d_k) factor matters.
- Define multi-head attention, count its parameters and FLOPs, and contrast self, cross, and causal masking.
- Explain the O(n^2 d) memory and compute wall, and describe how FlashAttention preserves exact attention while linear attention and Performers approximate it.
- Implement scaled dot-product attention from scratch in NumPy and compare with PyTorch nn.MultiheadAttention.
TL;DR
Attention is a learned soft lookup. Given a query , a set of keys and values , attention returns a convex combination where . Bahdanau [1] introduced this for translation in 2014; Luong [2] simplified it to a dot product; Vaswani [3] dropped recurrence entirely and built the Transformer out of scaled dot-product self-attention , with multiple heads operating in parallel. The factor keeps the softmax out of saturation. The whole thing is in compute and memory, which is both a strength (fully parallel across positions) and a weakness (long context is expensive). FlashAttention [4] recovers exact attention at near-linear memory by tiling the softmax through SRAM; linear attention [5] and Performers [6] approximate the softmax kernel for true scaling, at some accuracy cost surveyed in [7].
Intuition
A recurrent encoder reads a sentence and compresses everything it has seen into a single hidden state. By the end of a long sentence the early words are squeezed into a tiny corner of that vector. Attention asks a different question: “which of the encoder hidden states should I look at right now?” and answers it with a learned weighted average. Nothing is compressed; everything stays addressable.
The shape stays the same when self-attention swaps the encoder for the same sequence: every token is allowed to look at every other token, and the model learns who looks at whom. That single substitution removes the recurrence, makes training fully parallel across positions, and is the engineering reason Transformers displaced RNNs [3].
Memory in classical computing is address-based: you ask for slot 17, you get whatever is in slot 17. Attention is content-based: you ask “what’s similar to my query ?” and you get a soft weighted average of every slot, where slots that match get more weight. The softmax is the differentiable replacement for an argmax-style hard lookup. That makes attention a kind of differentiable hash table, and the gradient through it tells the network how to reshape its keys so that the right values surface for each kind of query.
A short chronology of how the idea matured before becoming the Transformer:
- 2014Bahdanau additive attentionpaper
Bahdanau, Cho, Bengio remove the seq2seq encoder bottleneck by letting the decoder attend over all encoder hidden states, with a small MLP scoring function.
- 2015Luong multiplicative attentionpaper
Luong, Pham, Manning simplify the score to a dot product (and a general bilinear form), trading expressivity for speed.
- 2017Vaswani: scaled dot-product self-attention + multi-headbreakthrough
Attention Is All You Need drops recurrence entirely. The Transformer is built from softmax(Q K^T / sqrt(d_k)) V with h parallel heads.
- 2020Linear attention (Katharopoulos et al.)efficient
Replace exp(q . k) with phi(q)^T phi(k) for a feature map phi, drop the explicit n x n matrix, get O(n d^2) compute and constant-memory autoregressive decoding.
- 2020Performers (Choromanski et al.)efficient
Random-feature approximation of the softmax kernel; provably unbiased, scales to long sequences, and remains drop-in for trained Transformers.
- 2022FlashAttention (Dao et al.)system
Exact attention with O(n) memory by tiling Q, K, V into SRAM blocks and recomputing the softmax on the fly. Practical 2-4x speedups on long sequences.
Math
Scaled dot-product attention from first principles
From a single query to the matrix form
Start with one query and a memory of key-value pairs with and . The attention output is a convex combination of values, weighted by a softmax over query-key compatibility:
The score function is what distinguishes attention variants. Bahdanau used (additive). Luong used (multiplicative bilinear). Vaswani used the simplest form, plain dot product, with a critical scale factor:
Stack queries into , keys into , and values into . The vectorized form is
with the softmax taken row-wise. Each row of the output is a per-query weighted average of value vectors.
Why divide by sqrt(d_k)? The variance argument
Suppose the entries of and are independent random variables with mean and variance . Then is a sum of independent products, each with mean and variance , so . As grows, the unscaled dot products spread over a range of .
A softmax fed inputs with variance saturates: one entry dominates, the others get nearly zero weight, and the gradient through the softmax collapses (the off-diagonal entries of the softmax Jacobian go to zero [8]). Dividing by brings the variance back to , which keeps the softmax in a regime where its gradient is informative. Empirically the un-scaled version is hard to train at greater than about [3].
Softmax row-wise gradient
Let for a single row. The Jacobian is
so . Two consequences. First, is at most rank (the all-ones vector is in its kernel, which is why softmax is shift-invariant). Second, when one is near and the rest are near , except for the dominant entry, so gradients vanish through saturated softmax: this is the engineering reason for the rescaling.
Kernel-regression view
Fix a bandwidth and consider Nadaraya-Watson kernel regression with a Gaussian kernel:
Expand the squared distance:
The term cancels in the row-wise softmax (it is constant in ). If we further assume is approximately constant across keys (true for layer-normalized inputs, true on average for random init), the terms are also approximately constant in and cancel. What remains is
Setting recovers exactly scaled dot-product attention. So softmax attention is kernel regression with a learned key/value memory and the bandwidth absorbed into the scale factor. This view also makes every approximation strategy a choice of kernel: linear attention picks , Performers pick a random-feature kernel, etc.
Multi-head attention
A single scaled dot-product attention head produces a -dim output per query. Multi-head attention [3] runs heads in parallel, each with its own , and concatenates their outputs:
with
If the model dimension is and there are heads, each head uses , so the total parameter count is the same as a single head with model dimension . The point of using heads is not capacity but diversity: each head can specialize on a different relation (positional, syntactic, content), and the concatenation followed by lets the network mix those specializations.
Self vs cross vs causal: the three attention modes
The same scaled dot-product formula is reused in three different roles by routing different tensors into , , , and by applying different masks to the score matrix.
- Self-attention. , , all come from the same sequence : , , . Used in encoder layers and inside masked decoder layers.
- Cross-attention. comes from the decoder, and from the encoder output. Used in encoder-decoder Transformers (the original NMT setup) and in the second sub-layer of every decoder block.
- Causal (masked) self-attention. Self-attention with a triangular mask that sets for . After softmax those positions get weight zero, so token only attends to tokens . Required for autoregressive language models so that prediction of token does not peek at token during training.
The mask is added pre-softmax, not post-softmax, so masked positions must use rather than . A common bug is to apply the mask after softmax and renormalize: this still works for forward pass but breaks the gradient because the renormalization is non-smooth across the mask boundary.
| Mode | Q from | K, V from | Mask | Typical use |
|---|---|---|---|---|
| Self | sequence | same sequence | none | encoder, BERT |
| Causal self | sequence | same sequence | upper triangular -inf | GPT, decoder pre-cross-attn |
| Cross | decoder | encoder output | none | NMT, encoder-decoder |
| Variant | Mask | Use case | Example architecture |
|---|---|---|---|
| Self-attention (no mask) | None | Bidirectional contextualization, full-sentence understanding | BERT encoder, ViT, T5 encoder |
| Causal self-attention | Upper-triangular -inf (token i can only see tokens 1..i) | Autoregressive language modelling, next-token prediction | GPT family, decoder-only LLMs |
| Cross-attention | None on K, V; sometimes a padding mask | Conditional generation: decoder Q reads encoder K, V | Original NMT Transformer, T5 decoder, Whisper, Flamingo |
Complexity: feature, then bug
For a sequence of length and head dimension , scaled dot-product attention does:
- Score matrix : shape , cost .
- Softmax: cost .
- Multiply by : cost .
Total: in compute and in attention-matrix memory. Per-head FLOPs across an entire sequence are roughly for one attention layer, dominated by the two matrix multiplies (one with , one with ).
The feature side: those matrix multiplies are the most parallel operation in the architecture. There is no time-step dependency to break, so a Transformer can train at full GPU utilization across the entire sequence dimension. RNNs cannot; that is why Transformers train an order of magnitude faster on the same hardware [3].
The bug side: memory means doubling sequence length quadruples the attention activation memory. At , attention is the dominant cost; at , it pushes most consumer GPUs out of memory. Long-context models cannot afford the naive implementation.
Pure self-attention with no positional encoding is permutation-equivariant: if you shuffle the input tokens by a permutation , the output rows are shuffled by the same but the values in each row are unchanged. The reason is that every operation in attention (matrix multiplies, row-wise softmax) treats the sequence dimension as a set: there is no convolution over time, no recurrence. Permuting rows of permutes rows of , , identically, permutes by on rows and columns, and the row-wise softmax sees the same multiset of scores.
This is why Transformers must inject positional information explicitly: sinusoidal encodings, learned embeddings, RoPE, ALiBi. Without them, the model genuinely cannot distinguish “the cat sat on the mat” from “mat the on sat cat the” [3].
Efficient variants
The wall has spawned a small zoo of “efficient transformers”, surveyed in detail by Tay et al. [7]. Three families are worth knowing.
FlashAttention: tiled exact softmax
FlashAttention [4] keeps exact attention (same outputs as naive scaled dot-product, bit for bit) but cuts the memory footprint from to . The key observations:
- GPUs are bandwidth-bound, not flop-bound, on attention. A modern GPU has TFLOPs of compute and TB/s of HBM bandwidth. Reading and writing the attention matrix is the bottleneck, not the matrix multiplies.
- The softmax is associative if you carry running statistics. For two blocks of scores with running max and running sum , you can update as you stream blocks through SRAM, and at the end produce the same softmax output as one giant softmax over the concatenation.
The algorithm splits into row blocks of size and into column blocks of size , both small enough to fit in on-chip SRAM. For each tile:
- Load from HBM into SRAM (one read each per tile).
- Compute the tile of scores in SRAM.
- Update running max .
- Rescale the running output and sum: , .
- After all tiles, .
The score matrix is never materialized in HBM. Memory drops from to , and wall-clock attention time drops 2-4x at in the original paper. The backward pass is the same idea: recompute the score tile on the fly during backward instead of storing it. FlashAttention-2 and FlashAttention-3 push this further but the algorithmic core is the tiled exact softmax above.
Linear attention and Performers
Linear attention [5] replaces with for some feature map . Because the kernel is now a dot product, you can rewrite
and the inner sum is independent of . Compute it once in , store an matrix, and then every query costs . Total: , linear in . Autoregressive decoding becomes a recurrence over a fixed-size state, recovering an RNN-like inference profile from a Transformer-like training profile.
The catch is that must approximate the softmax kernel well. Katharopoulos et al. use which is cheap but coarse; Performers [6] use random Fourier features for the Gaussian kernel and prove unbiasedness with controllable variance. Both lose accuracy on tasks where exact attention captures sharp lookups, but recover most of the quality on language modelling at long context.
Sparse and local attention
Another family restricts which pairs are computed at all: local windows around the diagonal, strided patterns, dilated windows, learned routing (Reformer, Longformer, BigBird). The Tay survey [7] tabulates dozens of variants; the unifying theme is “drop entries by hand or by hashing, keep the rest exact”. Modern long-context models (Llama 3, Mistral) typically combine local sliding-window attention with periodic global attention sinks for streaming long-context decoding, an interpolation between dense and sparse rather than a clean either-or.
Interactive: attention heatmap
The visual demo first. The heatmap shows three precomputed heads on the same 9-token sentence: a diagonal head (each token attends mostly to itself), a previous-token head (each token attends to its left neighbor, a real pattern observed in early-layer GPT heads), and a content-word head (every token attends to the content nouns and verbs in the sentence, a real pattern observed in middle-layer BERT heads). Hover or click any row to highlight that query’s distribution.
Implementations
A from-scratch NumPy implementation that mirrors the math 1:1, then PyTorch’s production-grade nn.MultiheadAttention.
import numpy as np
def softmax_rows(x):
"""Numerically stable row-wise softmax."""
x = x - x.max(axis=-1, keepdims=True)
e = np.exp(x)
return e / e.sum(axis=-1, keepdims=True)
def scaled_dot_product_attention(Q, K, V, mask=None):
"""Q: (n, d_k), K: (m, d_k), V: (m, d_v), mask: (n, m) of {0, -inf}."""
d_k = Q.shape[-1]
scores = Q @ K.T / np.sqrt(d_k) # (n, m)
if mask is not None:
scores = scores + mask # broadcast -inf into masked entries
weights = softmax_rows(scores) # (n, m)
return weights @ V, weights # (n, d_v), (n, m)
def multi_head_attention(X, W_q, W_k, W_v, W_o, num_heads, mask=None):
"""X: (n, d_model). W_*: (d_model, d_model). Returns (n, d_model)."""
n, d_model = X.shape
d_k = d_model // num_heads
Q = (X @ W_q).reshape(n, num_heads, d_k).transpose(1, 0, 2) # (h, n, d_k)
K = (X @ W_k).reshape(n, num_heads, d_k).transpose(1, 0, 2)
V = (X @ W_v).reshape(n, num_heads, d_k).transpose(1, 0, 2)
head_outs = []
for i in range(num_heads):
out, _ = scaled_dot_product_attention(Q[i], K[i], V[i], mask)
head_outs.append(out)
cat = np.concatenate(head_outs, axis=-1) # (n, d_model)
return cat @ W_o # (n, d_model)
# Sanity check on a tiny sequence.
np.random.seed(0)
n, d, h = 5, 16, 4
X = np.random.randn(n, d)
W_q = np.random.randn(d, d) / np.sqrt(d)
W_k = np.random.randn(d, d) / np.sqrt(d)
W_v = np.random.randn(d, d) / np.sqrt(d)
W_o = np.random.randn(d, d) / np.sqrt(d)
Y = multi_head_attention(X, W_q, W_k, W_v, W_o, num_heads=h)
print(Y.shape) # (5, 16)Run a tiny self-attention layer live in the browser:
(no output yet)
Pitfalls
If you forget the upper-triangular mask in a causal decoder, training looks fine: the model can peek at future tokens, so per-token loss drops fast. Inference quality, however, collapses: the model has never seen a context where the future was unavailable, and it produces fluent nonsense. Always build the causal mask once, cache it, and assert its shape on every batch. The mask must be added to the score logits before the softmax, with on masked positions.
The softmax overflows for above about in fp32 (). Standard fix: subtract the row max before exponentiating, . Every framework does this internally, but if you implement attention from scratch you must too. FlashAttention’s running-max state machine is exactly the streaming version of this fix.
The original Transformer applies dropout to the attention probabilities after the softmax, so each row is renormalized post-dropout (or not, depending on the implementation). This works but has a subtle bug: if you drop the highest-weight position, the gradient routes weirdly. Modern implementations (HuggingFace, FlashAttention) drop after the matmul with , which is equivalent in expectation and avoids the renormalization question. Pick one convention and stick with it across pretrain and fine-tune; mixing is a silent failure mode.
Mixed-precision training (bf16 / fp16) is standard, but the attention softmax should be done in fp32 because the exponentiation is sensitive to small differences between large logits. PyTorch’s scaled_dot_product_attention does this automatically. If you write attention by hand, cast scores to fp32 before the softmax and back to bf16 after.
Pop quiz
- 1. Why does scaled dot-product attention divide by sqrt(d_k)?
- 2. What does the causal mask in masked self-attention do?
- 3. What is the time and memory complexity of vanilla scaled dot-product attention for sequence length n and head dimension d?
- 4. Pure self-attention without positional encodings is:
- 5. What does FlashAttention achieve compared to naive softmax attention?
Interview Q&A
Derive softmax attention from kernel regression on a learned key-value memory.onsite
Start with Nadaraya-Watson kernel regression. Given a query and a memory and a kernel , the kernel regression estimate is
Pick the Gaussian kernel and expand the squared distance:
The term is constant in and cancels in the ratio (the row-wise softmax). If keys are layer-normalized so is approximately constant, the term also cancels. What remains is
Setting recovers scaled dot-product attention. So the formula is non-parametric kernel regression with a learned key-value memory and a temperature absorbed into the scale factor. This view makes the design knobs explicit: the kernel choice, the bandwidth, and the implicit assumption that keys are approximately normalized.
Why divide by sqrt(d_k)? Make the variance argument precise.phone
Suppose with independent components, each with mean and variance . Then
using independence of the products and for centered unit-variance factors. So the unscaled dot product has standard deviation .
A softmax fed inputs with this scale collapses: one entry dominates and the rest get exponentially small weight. The Jacobian of the softmax in saturated regimes is approximately rank-1, so gradients through every position except the dominant one vanish. Dividing by rescales to unit variance, putting the softmax back in a regime where its Jacobian is informative. Empirically this is the difference between a Transformer that trains and one that does not at above [3].
Prove that pure self-attention is permutation-equivariant, and explain why positional encodings are necessary.onsite
Let be a permutation matrix. Apply it to the input: . Self-attention computes , similarly , . The score matrix is
Row-wise softmax is permutation-equivariant on the rows and the values inside each row form the same multiset on both sides:
Multiply by :
since for any permutation. The output is permuted by the same , never reshuffled. So pure self-attention treats the sequence as a set: no operation distinguishes position from position .
This is fatal for any task where order matters (translation, language modelling). The fix is to add or fold in positional encodings at the input: sinusoidal (Vaswani 2017), learned absolute, RoPE (rotary), or ALiBi (linear bias). Each breaks permutation equivariance in a different way; see Transformers for the trade-offs.
Sketch the FlashAttention tiled-softmax algorithm and explain why memory drops from O(n^2) to O(n).research
Setup. Naive attention computes the full score matrix , materializes it in HBM, applies row-wise softmax, multiplies by . The matrix and the softmax probabilities each take memory.
Insight 1: GPUs are HBM-bandwidth-bound on attention. Reading and writing between HBM and the SM is the dominant cost. If we never materialize in HBM, we save both memory and time.
Insight 2: softmax has a streaming online form. For a sequence of score blocks , we can keep a running row-max and a running denominator . When a new block arrives with row-max , update
The rescale factor propagates into the running output too. After streaming all blocks, divide the accumulated -weighted sum by to recover the exact softmax-weighted average.
Algorithm. Split into row blocks of size and into column blocks of size , with chosen so all fit in SRAM. For each output tile :
- Initialize , , in SRAM.
- For each :
- Load from HBM to SRAM.
- Compute in SRAM.
- .
- .
- .
- .
- After all : , write back to HBM.
Complexity. The matrix is never written to HBM; only the output and the per-row running statistics ( scalars each for and ) leave the SM. Memory drops from to . Compute is the same FLOPs but with much better arithmetic intensity, giving 2-4x wall-clock speedup at in the original paper [4]. The backward pass uses the same streaming idea with extra storage (recompute on the fly during backward).
The result is bit-exact equivalence to naive attention, so FlashAttention is a drop-in replacement, no retraining needed. Modern PyTorch’s scaled_dot_product_attention dispatches to it automatically when shapes and dtypes are supported.
Linear attention promises O(n d^2) compute by replacing exp(q . k) with phi(q)^T phi(k). What does it lose, and when is the trade-off worth it?research
The trick. Replace with for some . Then
The inner sum is independent of . Compute it once in , store the resulting matrix, and answer each query in . Total cost over a sequence of length : , linear in [5].
For autoregressive decoding the inner sum becomes a running tensor that updates incrementally, giving constant-memory inference (RNN-style), unlike vanilla attention which grows the KV cache as .
What it loses.
- Sharpness. Softmax can produce near-one-hot distributions (“focus on this one token”). A polynomial has bounded entropy in its kernel and tends to produce smoother distributions. On tasks that need sharp lookup (named entity, copy, in-context retrieval), this hurts.
- Approximation error. has finite dimension, so it cannot exactly represent the softmax kernel. Performers [6] use random Fourier features so the approximation is unbiased with controllable variance, but at the cost of in practice.
- Optimization. Linear-attention models often need different learning-rate schedules, longer warmup, and special initialization. They are not drop-in for trained Transformer weights.
When it is worth it. Long-context tasks where is the binding constraint and exact softmax is unaffordable: long-document classification, very long retrieval-augmented contexts, streaming inference at constant memory. As of 2024, the practical landscape is that FlashAttention covers most of the gap up to without giving up exactness, so linear attention has been pushed to the very long-context regime () and to memory-constrained inference. State-space models (S4, Mamba) borrow the same constant-memory recurrence story and are arguably the more competitive long-context alternative today.
A weekend project that takes attention from formula to working LM head:
- Implement the NumPy
scaled_dot_product_attentionabove. Verify it matchestorch.nn.functional.scaled_dot_product_attentionto within fp32 noise on random inputs. - Build a single-layer Transformer encoder with heads on a tiny copy task: input is a random sequence of integers, target is the same sequence reversed. With and , training on samples reaches near-perfect copy in a minute on CPU.
- Replace the encoder with a causal decoder and train a character-level next-token predictor on the first 1000 lines of Hamlet. Read off the attention weights of head 0 layer 0; you will see something close to the previous-token head shown in
<AttentionViz />. - Stretch: swap your softmax for an
elu(.) + 1linear-attention kernel and observe the quality drop on copy. Then scale up to and observe the memory advantage.
References
- Bahdanau, D., Cho, K., and Bengio, Y. (2014). Neural Machine Translation by Jointly Learning to Align and Translate. ICLR 2015 (arXiv preprint 2014). arXiv:1409.0473
- Luong, M.-T., Pham, H., and Manning, C. D. (2015). Effective Approaches to Attention-based Neural Machine Translation. EMNLP 2015. arXiv:1508.04025
- Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., Kaiser, L., and Polosukhin, I. (2017). Attention Is All You Need. NeurIPS 2017. arXiv:1706.03762
- Dao, T., Fu, D. Y., Ermon, S., Rudra, A., and Re, C. (2022). FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness. NeurIPS 2022. arXiv:2205.14135
- Katharopoulos, A., Vyas, A., Pappas, N., and Fleuret, F. (2020). Transformers are RNNs: Fast Autoregressive Transformers with Linear Attention. ICML 2020. arXiv:2006.16236
- Choromanski, K., Likhosherstov, V., Dohan, D., Song, X., Gane, A., Sarlos, T., Hawkins, P., Davis, J., Mohiuddin, A., Kaiser, L., Belanger, D., Colwell, L., and Weller, A. (2020). Rethinking Attention with Performers. ICLR 2021 (arXiv preprint 2020). arXiv:2009.14794
- Tay, Y., Dehghani, M., Bahri, D., and Metzler, D. (2022). Efficient Transformers: A Survey. ACM Computing Surveys. arXiv:2009.06732
- Goodfellow, I., Bengio, Y., and Courville, A. (2016). Deep Learning. MIT Press. https://www.deeplearningbook.org