Deep Learning
Attention Mechanisms
Turn compatibility scores into attention weights, then combine values. Explore the geometry, normalization, and limits of the mechanism.
Jump to a section
Why this matters
Attention lets each position combine information from other positions using learned compatibility scores. A query is compared with keys, softmax turns the scores into weights, and those weights combine the value vectors.
Think of it as a soft key-value lookup. The useful questions are what gets scored, which positions are allowed to contribute, and how the resulting values are mixed.
Build the mental model
Think of a soft key-value store. Each token emits three vectors:
- a query (
q): "what am I looking for?" - a key (
k): "what do I offer?" - a value (
v): "what I'll hand over if you attend to me."
For a given query, you score it against every key (dot product = similarity), turn those scores into a probability distribution with softmax, and return the weighted sum of the values. A hard dictionary returns exactly one value for an exact key match; attention returns a blend, weighted by match strength, which is what makes it differentiable and trainable.
How scores become attention weights
Lower temperature to concentrate the weights. Raise it to distribute them more evenly. Which token keeps the largest share?
The visual loads as you reach this section.
"Self-attention" just means Q, K, and V are all projected from the same sequence: each token attends to the whole sequence, including itself.
Work through the math
Scaled dot-product attention, for queries , keys , and values :
The softmax is taken row-wise, so each query's attention weights sum to 1. Why divide by ? If the components of and are independent with mean 0 and variance 1, their dot product has variance . For large , the raw scores grow large in magnitude, pushing softmax into regions where its gradient is almost zero (it saturates toward a one-hot vector). Scaling by normalizes the variance back to ~1, keeping gradients healthy.
Key takeaway: Attention is a soft, differentiable dictionary lookup; the divisor exists purely to keep the variance of the scores near 1 so softmax doesn't saturate and kill gradients.
Multi-head attention runs attention operations in parallel on lower-dimensional projections, then concatenates:
Each head can specialize (one tracks syntax, another coreference, etc.). With , multi-head costs roughly the same as single-head of full width.
| Variant | Key idea | Tradeoff |
|---|---|---|
| Single-head scaled dot-product | One softmax weighting per query | Simple; can only express one relation at a time |
| Multi-head (MHA) | parallel heads on low-dim projections, concatenated | More expressive relations per layer; ~same FLOPs, more parameters |
| Multi-query / grouped-query (MQA/GQA) | Share K/V heads across query heads | Much smaller KV cache at inference; slight quality cost |
| FlashAttention | Exact attention, tiled to avoid materializing the matrix | Same math, far less memory traffic, not an approximation |
Read the implementation
1import torch
2import torch.nn.functional as F
3from torch import Tensor, nn
4
5
6def scaled_dot_product_attention(
7 q: Tensor, k: Tensor, v: Tensor, mask: Tensor | None = None
8) -> Tensor:
9 # q,k,v: (batch, heads, seq, d_k)
10 d_k = q.size(-1)
11 scores = (q @ k.transpose(-2, -1)) / d_k**0.5 # (b, h, seq, seq)
12 if mask is not None:
13 scores = scores.masked_fill(mask == 0, float("-inf")) # causal / padding
14 weights = F.softmax(scores, dim=-1)
15 return weights @ v # (b, h, seq, d_k)
16
17
18class MultiHeadAttention(nn.Module):
19 def __init__(self, d_model: int, n_heads: int) -> None:
20 super().__init__()
21 assert d_model % n_heads == 0, "d_model must be divisible by n_heads"
22 self.n_heads, self.d_k = n_heads, d_model // n_heads
23 self.qkv = nn.Linear(d_model, 3 * d_model) # fused Q,K,V projection
24 self.out = nn.Linear(d_model, d_model)
25
26 def forward(self, x: Tensor, mask: Tensor | None = None) -> Tensor:
27 b, seq, _ = x.shape
28 qkv = self.qkv(x).view(b, seq, 3, self.n_heads, self.d_k)
29 q, k, v = qkv.permute(2, 0, 3, 1, 4) # each: (b, heads, seq, d_k)
30 out = scaled_dot_product_attention(q, k, v, mask)
31 out = out.transpose(1, 2).reshape(b, seq, -1) # recombine heads
32 return self.out(out)
33
34
35# quick shape test
36mha = MultiHeadAttention(d_model=512, n_heads=8)
37x = torch.randn(2, 10, 512)
38assert mha(x).shape == (2, 10, 512)Questions and trade-offs
- Conceptual: Why does attention scale scores by , and what fails if you don't? (Variance of the dot product grows with ; unscaled scores saturate softmax and kill gradients.)
- Implementation: How do you implement a causal mask, and where in the computation does it go? (Set future positions to in the score matrix before softmax, so their weights become 0.)
- Applied: What's the time and memory complexity of self-attention in sequence length , and why is that a problem for long contexts? ( time and memory from the score matrix: the motivation for FlashAttention, sparse, and linear-attention variants.)
- Systems-level: What does the KV cache do at inference, and why does it make autoregressive decoding far cheaper? (Caches past keys/values so each new token attends to stored K/V instead of recomputing them: turns per-token cost from quadratic-recompute into linear.)
- Failure modes: Why use multiple heads instead of one wide head? (Separate subspaces let heads attend to different relations simultaneously; a single softmax can only express one weighting per query.)
Check your understanding
Close this page. Derive scaled dot-product attention from scratch: write the formula, state the shapes of , , , explain the term, and describe in one sentence how multi-head differs. Then check what you missed against Stage 3.
Oliver Perrin
Machine Learning Engineer · Founder, LiminalML
LiminalML brings together concept explanations, mathematical examples, and working visuals. Find more writing by Oliver on the LiminalML Substack.
Keep exploring the idea.
Ask a follow-up in a guided session, work through the self-check, or open the visual in Studio to build on it.
Related concepts
Deep Learning
Transformer Architecture
Follow attention, feed-forward layers, normalization, and residual connections through a Transformer block.
LLMs
KV Cache
See which token projections caching saves, what attention must still read, and how memory use grows with context.
Deep Learning
Batch Normalization
Normalize activations across a batch, apply a learned scale and shift, and understand why training and evaluation behave differently.