Before you can understand why we cache K and V (and not Q), you must know what every letter and picture in the parent note actually means. This page builds them in order, each one leaning on the previous. Nothing is assumed.
The picture: imagine a row of boxes, one per word: "The cat sat". Each box is replaced by an arrow of numbers pointing in "meaning space". Position t=1 is "The", t=2 is "cat", and so on.
Why the topic needs it: the whole cost story is "what happens per token". If you don't know that each token becomes a vector xt, you can't count what gets computed for it.
Figure 1 — three word-boxes "The", "cat", "sat" at positions t=1,2,3, each with a downward arrow into a bracketed list of numbers: the embedding vector xt of length d.
The number of components in one embedding arrow is the model dimension d. Big models use d=768 (GPT-2 small) up to thousands. That single number d shows up everywhere in the cost formulas, so pin it down now.
Notation
xt is the embedding vector for the token at position t; d is how many numbers it holds.
Attention (built in 6.1.4-multi-head-attention) turns each token's embedding xt into three new vectors by multiplying it by three fixed number-grids (matrices) called WQ, WK, WV.
The picture — a library: every past book has a spine label (its Key) and contents (its Value). The new token walks in with a search slip (its Query). It compares its slip against every spine label, then pulls contents from the books that match best.
Figure 2 — two past-token "books" each showing a green Key label and a blue Value content, plus one orange new-token "search slip" Qt with dashed red arrows comparing it against each Key.
Why the topic needs it — and this is the heart of caching: a past token's label Ki and contents Vinever change once written. But every new token brings a fresh search slip Qt. That asymmetry is exactly why we cache K and V but recompute Q.
Recall Why can't we cache Q?
Because Q is the new token's question, which is different for every step. K and V are old tokens' fixed answers. ::: Correct.
What is WK?
A fixed matrix of shape dk×d (learned in training, frozen during generation) that maps an embedding xt to its Key vector Kt.
To measure how well a search slip matches a spine label, attention uses the dot product: multiply matching components and add them up. A big dot product = strong match.
Pinning down the shapes (this is where novices get lost): at generation step t there is one new query, a row vector
Qt∈R1×dk
and there are t cached keys stacked into a matrix, one key per row:
K=K1K2⋮Kt∈Rt×dk.
To dot the query against every key at once, we need each key laid out as a column. The transpose KT does exactly that — it turns the t×dk stack of rows into a dk×t block of columns:
KT∈Rdk×t.
Now the shapes line up for a matrix multiply:
1×dkQtdk×tKT=1×tscores,
one score per past token. The inner dk dimensions must match and cancel — that is the whole reason we transpose.
The picture: the query arrow's shadow cast onto each key arrow — the longer the shadow, the higher the score.
Figure 3 — an orange query vector Q and three key vectors K1,K2,K3 from the origin; dotted projection lines show K3 (green) aligns most with Q, giving the highest dot-product score.
In the parent note's single-layer worked example (generating the 3rd token, 4 heads, dk=64), Q3(K1,K2,K3)T produces exactly 3 scores — one per past position — matching the row of length t=3 we derived above.
Why divide by dk?
To keep the scores from growing huge as dk grows, which would make the next step (softmax) too spiky. It's a stabiliser.
The picture — a pie chart of attention: bigger raw score → bigger slice, and all slices sum to one whole pie. The exponential es exaggerates the leader so the strongest match dominates but nothing is fully ignored.
Figure 4 — left: a bar chart of three raw scores; right: the same scores after softmax shown as a pie whose three slices sum to 1, the largest score taking the biggest slice.
Why the topic needs it — and where V's shape enters: these weights multiply the cached Values to blend them into one output. Stack the t Value vectors the same way we stacked Keys:
V=V1V2⋮Vt∈Rt×dk.
The softmax output is a row of t weights, shape 1×t. Multiplying shapes:
1×tsoftmax scorest×dkV=1×dkoutput.
The inner t cancels, so a 1×t weight row times the t×dk Value stack yields one length-dk output vector — a weighted blend of all the Values. So the full attention formula
Attention(Q,K,V)=softmax(dkQKT)V
reads left-to-right as: score the labels → turn into a pie → mix the contents.
One attention isn't enough, so the model runs several in parallel — each is a head.
What counts as a "layer"? A transformer stacks identical blocks on top of each other; each block is a layer (6.1.1-transformer-architecture builds these). One layer contains its own attention (with its own WQ,WK,WV) plus a feed-forward network. GPT-2 small has 12 such layers; a GPT-3-style model has 96. Let N = number of layers. Every layer keeps its own separate KV-cache, which is why full-model memory multiplies by N.
Why the topic needs it: cache memory is counted per head, per layer, per token. Now that h, dk and p are all defined, the memory formula reads:
Memory (per layer, per token)=2×h×dk×p
The 2 is because we store two things: the Key stack and the Value stack.
Standard cache per tokenMQA cache per token=2×h×dk2×dk=h1.
With h=12 heads, MQA stores 12× less KV-cache, because K and V are each stored once (at length dk) instead of h times. Quality typically drops only 1–2%.
The picture — a lower-triangular grid: row i (the attending token) can fill in columns j≤i (itself and the past) but the upper-right triangle (the future) is blacked out.
Figure 5 — an L×L grid indexed by attending position i (rows) and key position j (columns); green cells j≤i hold 0 (allowed), red upper-right cells j>i hold −∞ (future blocked).
Why the topic needs it: because the mask guarantees a token only ever attends to positions ≤t, and those past K,V are frozen — that is the exact license to cache them. Even with a cache you must still add the mask, or the model would illegally read future positions.
Why the topic needs it: the entire motivation is a cost comparison. The projection cost per token is O(d2) per layer (a dk×d matrix times a length-d vector, summed over h heads gives hdkd=d⋅d=d2). Big-O hides the constant factors N (layers) and the per-head split, so the clean formulas below are per-layer projection costs; multiply by N layers for the full model:
Without cache (per layer): With cache (per layer): Speedup: t=1∑LO(td2)=O(L2d2)t=1∑LO(d2)=O(Ld2)Ld2L2d2=L.
For a 100-token sequence, that's roughly 100× less projection work. The parent note's GPT-2-small worked example (which does include the N=12 layer factor on both sides, so it cancels) measures a ≈50× real speedup for L=100 — a bit under the ideal L because attention itself still costs a little each step, but the same order of magnitude.
Meaning of O(L2d2) vs O(Ld2)?
Per-layer projection cost: the first is quadratic in length (naive), the second linear (cached). Their ratio is L, the speedup. Multiply either by N layers for the whole model.
Each foundation feeds the next; together they justify why caching K and V (not Q) is safe and cheap. Deeper follow-ups: 6.2.3-inference-optimization, 6.1.11-sparse-attention, 6.3.1-model-quantization, 7.2.1-llm-deployment, 5.4.2-beam-search.