6.14 — KV cache (preview for inference)
Goal: Derive why keys and values for past tokens do not change during autoregressive decoding; quantify the per-step compute and memory savings from caching them; preview GQA/MQA as a KV-cache shrink; place the KV cache as the dominant memory cost of long-context inference.
1. Why this session exists
A Transformer generates text one token at a time. To produce token it must run the model on the sequence and project the last output position onto vocabulary logits. To then produce token it must... run the model again on ? Re-doing tokens of forward computation for each single new token would be quadratic-cumulative — generating tokens after a -token prompt would cost in FFN alone, which is roughly the same as one giant forward pass over the full context.
The fix is a structural observation that follows from the causal mask of 6.5: for any past position , the keys and values do not change when a new token is appended. They depend only on the embedding of and the model weights — neither of which moves. Cache them once; reuse them for every subsequent generation step.
The result is the KV cache: a per-layer per-head store of all previously-seen matrices, accumulated as generation proceeds. Compute per new token drops from to for the FFN and from to for attention — both linear in the cache size. The KV cache is the enabling optimisation of fast autoregressive inference.
This session derives the cache, counts its size, and previews the architectural variants (GQA/MQA — full treatment in Cap 8.3 — and MLA — full treatment in Cap 8.5) that shrink it for very long contexts.
2. Why and don't change
Recall the forward pass of one Transformer block on input . Inside multi-head attention (6.4) we compute, per head:
each in (with separate per head). Then , apply the causal mask, softmax row-wise, multiply by .
When we append a new token at position :
- The new embedding is computed (token + RoPE applied per-head).
- New entries are derived from alone: , similarly .
- The old rows and are unchanged. They depend on and on — neither has moved.
The causal mask of 6.5 further guarantees that position 's output depends only on and on — never on any future .
So the right computation for one new token is:
- Read cached .
- Compute fresh (each in ) from the new token's embedding.
- Append: , .
- Compute the single-row attention , softmax-mix with to get the output.
- Store as the cache for the next step.
No quadratic work over the past tokens. The "expensive" matmul collapses to one query vector against the full matrix, per head.
3. Compute count per generated token
Per block, per generated token, the cost decomposes as:
| Op | FLOPs (1 batch, 1 step) | |---|---| | Project new token to output | | | Attention scores (per head) | | | Mix (per head) | | | FFN | | | Total/block | |
Multiply by blocks. Compare to prefill (one forward pass over a length- prompt, 6.12 §2.3):
Setting in the prefill formula recovers the per-step count, confirming the cache is mathematically equivalent to "one forward pass over a 1-token sequence with a longer K, V context."
Generating tokens after a -token prompt: prefill cost once, then steps of each. For :
- Prefill: FLOPs per block.
- Per generation step: per block — three orders of magnitude smaller.
This is why "first token is slow, subsequent tokens are fast" is the dominant latency profile of LLM inference.
4. Memory: the KV cache size
The cache stores all and entries for every layer, every head, for the entire decoded sequence. Total size, in elements:
(The 2 is for and together; .) In bytes, multiply by the bytes-per-element of the storage dtype (fp16: 2 bytes; fp8: 1 byte; int8: 1 byte).
Numerical examples (single batch, fp16):
| Model | | | | | | |---|---:|---:|---:|---:|---:| | GPT-2 small | 12 | 768 | 0.15 GB | 1.2 GB | 4.7 GB | | LLaMA-7B | 32 | 4096 | 2.1 GB | 17 GB | 67 GB | | LLaMA-70B | 80 | 8192 | 11 GB | 86 GB | 336 GB | | GPT-3 (175B) | 96 | 12288 | 19 GB | 154 GB | 605 GB |
At , the KV cache for LLaMA-70B is larger than 4× H100 80GB GPUs combined. This is the structural reason long-context inference is hard, and the motivation for everything in §5–§6.
5. Architectural variants that shrink the cache
The bytes-per-token of the KV cache is in fp16 — the cache size of one token across all layers. Cutting this number is the central design lever of modern LLMs.
5.1 GQA: Grouped-Query Attention
Ainslie, Shazeer, et al., 2023[2], GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints (arXiv:2305.13245). Idea: keep query heads, but share across groups. With groups, you have K-heads and V-heads:
For LLaMA-70B with : cache is reduced by . The 86 GB cache at 32k context drops to GB.
GQA is the dominant variant in modern open LLMs (LLaMA-2-70B, LLaMA-3, Mistral, Qwen). The extreme case — every head shares one set of K, V — is MQA (Multi-Query Attention, Shazeer 2019)[1]. MQA cuts the cache to but loses some quality; GQA's "small " recovers most of MHA's quality at a small fraction of the cache.
Full treatment in Cap 8.3; the right place to learn it is after this session, because the motivation is purely the cache size.
5.2 MLA: Multi-head Latent Attention
DeepSeek-V2 (DeepSeek-AI, 2024, arXiv:2405.04434)[3]. A further compression: instead of storing directly, store a latent with per token; reconstruct via learned projections at attention time. The cache reduces from per token to per token, a shrink at iso-quality.
MLA powers DeepSeek-V2, V3, and R1. We will derive it in Cap 8.5; place it mentally as "the next step beyond GQA when the cache is still the bottleneck."
5.3 Quantising the cache
A blunter but effective tool: store the cache in fp8 or int8 instead of fp16 — half the memory, with measurable but tolerable quality loss. Modern inference servers (vLLM, TensorRT-LLM) implement this. We discuss it in Cap 10.6 (Quantization).
5.4 Sliding-window inference
If the model uses sliding-window attention (6.13 §2), the KV cache only needs to hold the last tokens. The cache becomes a rolling buffer of constant size — constant memory streaming generation. Mistral 7B's 4k window cache, used at 32k context, occupies the same memory as the prompt-prefix cache: of the full cache.
6. PagedAttention and continuous batching
Two further optimisations specific to serving LLMs to many users:
PagedAttention (Kwon et al., 2023[4], Efficient Memory Management for Large Language Model Serving with PagedAttention, arXiv:2309.06180). Standard inference allocates the KV cache as one contiguous chunk per request — wasteful when requests have different lengths (you pre-allocate for the max). PagedAttention divides the cache into fixed-size "pages" (e.g., 16 tokens each) and a per-request page table, like an OS virtual-memory subsystem. Memory fragmentation drops by ~10×, allowing 2–4× more concurrent requests on the same hardware. This is the foundation of vLLM and most modern LLM-serving stacks. Full treatment in Cap 10.8.
Continuous batching (Yu et al., 2022, Orca)[5]. Group requests with different ages into the same batch dynamically — when one request finishes, immediately add a new one without waiting for the whole batch to complete. Doubles throughput on real workloads. Also Cap 10.8.
Both rely on the KV cache existing as a separable per-request memory unit. The KV cache is the per-request state; everything else (model weights, activations during prefill) is shared.
7. Practical takeaways
Three things to remember:
- The KV cache is the dominant memory cost of long-context inference. bytes in fp16. For k on a 70B-scale model, this hits hundreds of GB.
- The cache compute saving is large. Per-token attention cost drops from to ; per-token FFN cost drops from to . Generation is ~ cheaper per token than prefill.
- Modern architectures (GQA, MLA) target the cache directly. The formula has only as a fixed user-controlled term; cutting at iso-quality is the central inference-side engineering challenge of 2024–2026.
Next session implements scaled dot-product attention by hand in numpy — verifying every shape and the softmax-rows-sum-to-1 invariant on a small example.
(a) Argue why, with causal attention, the keys and values at position do not change when a new token is appended at position . What would change in a bidirectional model (BERT-style)?
(b) Compute the KV-cache size in GB for LLaMA-7B at , , (single batch, fp16, ). Verify against §4's table.
(c) Derive the per-block FLOP count for one generation step: in §3. Why does the attention term scale linearly with here, but quadratically with during prefill?
(d) For GQA with query heads and groups, write the K-head count and V-head count. Compute the KV-cache size of LLaMA-70B-with-GQA at and compare to plain MHA at the same context.
(e) A request to a vLLM server has a 2k prompt and asks for 200 generated tokens. State (i) the prefill compute, (ii) the per-step generation compute, (iii) the total generated tokens' attention compute. Express each in terms of and . Which dominates the total latency?
References
- [1]
Shazeer, N. (2019). "Fast transformer decoding: One write-head is all you need" (Multi-Query Attention). arXiv:1911.02150 — MQA: share K, V across heads to shrink the KV cache (6.14 §5.1).
↩ - [2]
Ainslie, J., Lee-Thorp, J., de Jong, M., et al. (2023). "GQA: Training generalized multi-query transformer models from multi-head checkpoints". arXiv:2305.13245 — Grouped-query attention; the modern default in LLaMA-2-70B, LLaMA-3, Mistral, Qwen (6.14 §5.1; full treatment Cap 8.3).
↩ - [3]
DeepSeek-AI (2024). "DeepSeek-V2: A strong, economical, and efficient mixture-of-experts language model" (MLA). arXiv:2405.04434 — Multi-head latent attention; low-rank K, V compression (6.14 §5.2; full treatment Cap 8.5).
↩ - [4]
Kwon, W., Li, Z., Zhuang, S., et al. (2023). "Efficient memory management for large language model serving with PagedAttention" (vLLM). arXiv:2309.06180 — OS-style paging for the KV cache (6.14 §6; full treatment Cap 10.8).
↩ - [5]
Yu, G.-I., Jeong, J. S., Kim, G.-W., Kim, S., & Chun, B.-G. (2022). "Orca: A distributed serving system for transformer-based generative models". OSDI. — Continuous batching (6.14 §6).
↩