Efficient inference: KV cache, GQA, FlashAttention, speculative decoding, quantization
Decode is memory-bound — every trick here does more useful work per byte read
Training a model happens once; serving it happens billions of times, and serving is where most of the money and latency go. The techniques here — the KV cache, grouped-query attention, FlashAttention, continuous batching, speculative decoding and quantization — are why a 7B model runs on a laptop and why frontier APIs can stream hundreds of tokens per second. You will meet them again as 4-bit QLoRA (8.2 Fine-tuning and PEFT), as the latency and cost budgets of RAG and agent systems (9.9 Production: latency, cost, caching, guardrails, security and privacy, 10.11 Building production agents), and in every serving stack you deploy (8.13 Project: fine-tune a small LLM with LoRA and ship a chat app).
You'll be able to
- Explain why decoding is memory-bandwidth-bound and compute arithmetic intensity for a decode step
- Derive the KV-cache memory formula and apply it to real models with and without GQA
- Describe how FlashAttention computes exact attention in O(n) memory using the online softmax
- Explain speculative decoding's acceptance rule and expected speedup, and the basics of int8/int4 quantization
Key ideas
- Prefill is compute-bound and parallel; decode produces one token per step and is bound by memory bandwidth (reading weights + KV cache).
- KV cache per token = 2 · L · n_kv · d_head · bytes; Llama 2 7B needs 0.5 MB per token in fp16, Llama 3 8B (GQA, 8 KV heads) 128 KB.
- Arithmetic intensity of a decode step ≈ batch size, far below the GPU's ridge point at small batches — hence continuous batching and PagedAttention.
Show 4 more key ideas
- GQA shares K/V heads across groups of query heads, shrinking the cache by n_heads / n_kv with little quality loss.
- FlashAttention tiles Q, K, V through SRAM and uses the online softmax to compute exact attention with O(n) memory and 2–4× speed.
- Speculative decoding verifies γ draft tokens in one target pass; with acceptance rate α it yields (1 − α^(γ+1))/(1 − α) tokens per pass and the exact target distribution.
- Quantization to int8/int4 cuts weight bytes 2–4× with small perplexity cost; GPTQ, AWQ and NF4 are the common 4-bit schemes.
Suggested path through this lesson
Two phases, two bottlenecks
Generation (7.6 Decoder-only: GPT and autoregressive generation) has a prefill phase — the prompt's tokens run through the model in one parallel pass, a big matrix multiplication that keeps GPU compute busy — and a decode phase that produces one token per step. Decode is a different beast: for each token the model must read all its weights from GPU memory (and the whole KV cache) to do only a small amount of arithmetic. Decode is therefore memory-bandwidth-bound, not compute-bound, and most of inference engineering is about doing more useful work per byte read.
The KV cache
Without caching, step recomputes keys and values for all previous tokens — redundant work per step, over a generation. Caching every layer's and makes each step compute only the new token's projections and attend over the cache. The price is memory:
where the 2 counts keys and values, is the number of layers, the number of key/value heads, the head size and the bytes per element (2 for fp16/bf16).
Worked example. Llama 2 7B: , , , fp16 → bytes = 0.5 MB per token. A 4,096-token context costs 2 GB; a batch of 16 such sequences costs 32 GB — more than the 13.5 GB of weights. Llama 3 8B uses GQA with : 128 KB per token, 4× less, so a 128k-token context fits in 16 GB.
Arithmetic intensity: why batching matters
A decode step for a batch of sequences performs about FLOPs and reads about bytes of fp16 weights (plus the KV cache). Its arithmetic intensity — FLOPs per byte — is therefore about . An H100 can do roughly 990 TFLOP/s of dense bf16 math and move 3.35 TB/s from memory, a ridge point near 300 FLOPs per byte. Below that, the chip waits on memory: at batch size 1 you use well under 1% of its compute. Reading 14 GB of weights at 3.35 TB/s takes 4.2 ms, so a 7B fp16 model can produce at most about 240 tokens/s for a single user — and the same 4.2 ms could serve 200 users. Serving systems therefore batch aggressively, with continuous batching (admitting new requests at every step as others finish) and the PagedAttention scheme of vLLM, which stores the KV cache in fixed-size blocks like virtual-memory pages so that memory is not wasted on pre-allocated maximum lengths.
Shrinking the cache: MQA and GQA
Multi-query attention shares one key/value head across all query heads; grouped-query attention (GQA) is the middle ground, sharing each K/V head among a group of query heads (Llama 2 70B and all Llama 3 models: 8 KV heads for 32–128 query heads). The cache shrinks by with a small quality cost, and the K/V projection matrices shrink too. Checkpoints trained with full multi-head attention can be converted to GQA with brief "uptraining".
FlashAttention: exact attention without the matrix
Standard attention writes the score matrix to GPU memory, reads it back for the softmax, writes the probabilities, reads them again to multiply by — memory traffic in . FlashAttention computes the same result by tiling: it loads blocks of , and into fast on-chip SRAM and uses the online softmax trick — maintaining a running maximum and running sum so that partial results from different key blocks can be rescaled and combined exactly:
The full matrix is never materialized, memory becomes , and wall-clock speedups of 2–4× follow because attention is memory-bound. FlashAttention-2 improved parallelism and work partitioning; FlashAttention-3 exploits the asynchronous units of Hopper GPUs. It is an exact algorithm — no approximation — and it is what makes long contexts trainable at all.
Speculative decoding
Decode is bandwidth-bound, so verifying several tokens in one forward pass costs about the same as generating one. Speculative decoding uses a small draft model to propose tokens, then the target model scores all of them in a single pass. Each proposed token is accepted with probability , where is the target's distribution and the draft's; on the first rejection a replacement is sampled from the normalized . This procedure provably reproduces the target's exact output distribution. If each token is accepted with probability , the expected number of tokens produced per target pass is
so , gives tokens per pass — a 2–3× speedup with no change in output quality. Variants draft from the model's own early layers (Medusa, EAGLE) or from n-gram lookup in the prompt.
Quantization: fewer bytes per weight
If bandwidth is the bottleneck, halve the bytes. Quantization stores weights (and sometimes activations or the KV cache) in low precision. Uniform integer quantization maps a tensor with scale and zero point :
Per-channel or per-group scales (for example groups of 128 weights) keep the rounding error small. LLM.int8() handles the few outlier feature dimensions in fp16 and the rest in int8; GPTQ quantizes to 4 bits one column at a time while compensating the error using second-order (Hessian) information; AWQ rescales channels by activation statistics before rounding; NF4 is the 4-bit normal-float format used by QLoRA (8.2 Fine-tuning and PEFT). Memory for a 7B model: 14 GB in fp16, 7 GB in int8, about 3.5–4 GB in 4-bit — which is why a 7B model runs on a laptop. Perplexity typically rises very little at 8 bits and modestly at 4 bits; below 4 bits quality drops quickly, although ternary "1.58-bit" training is an active research line.
Putting it together
| technique | what it reduces | exact? | typical gain |
|---|---|---|---|
| KV cache | recomputation of K and V | yes | O(T²) → O(T) decode work |
| GQA / MQA | KV-cache size, K/V projections | no (small quality cost) | cache ÷ 4–16 |
| FlashAttention | memory traffic of the n×n matrix | yes | 2–4× attention speed, O(n) memory |
| continuous batching + PagedAttention | idle compute, cache fragmentation | yes | 2–20× throughput |
| speculative decoding | sequential target-model passes | yes (same distribution) | 2–3× tokens/s |
| int8 / int4 quantization | bytes per weight | no (small loss) | 2–4× memory, faster decode |
| sliding-window / sparse attention | attention cost | no | long-context feasibility |
A single-user latency estimate: time per token ≈ (weight bytes + KV bytes) / memory bandwidth. Every row of the table attacks one of those terms or the number of sequential steps.
Where this shows up later
- The 4-bit NF4 quantization is half of QLoRA — 8.2 Fine-tuning and PEFT; serving stacks (vLLM, TensorRT-LLM, llama.cpp) appear in the LLM project — 8.13 Project: fine-tune a small LLM with LoRA and ship a chat app.
- Latency and cost budgets for RAG and agent systems are set by these numbers — 9.9 Production: latency, cost, caching, guardrails, security and privacy, 10.11 Building production agents.
- Sliding-window and sub-quadratic attention are the subject of 7.12 Beyond vanilla attention: state space models, long context and hybrids; the hardware vocabulary (bandwidth, FLOP/s, memory hierarchy) is 4.12 Compute, hardware and scale basics.
Common pitfalls (5)
- Estimating decode latency from FLOPs — at small batch sizes it is set by bytes moved, not arithmetic.
- Thinking FlashAttention approximates attention; it is exact and changes only the memory access pattern.
- Assuming speculative decoding changes outputs or needs a special target model — the rejection-sampling rule preserves the target distribution exactly.
- Forgetting the KV cache when sizing a deployment: at long contexts and large batches it exceeds the weights.
- Comparing quantized models by file size alone — check perplexity or task metrics, since 2–3-bit schemes degrade sharply.
Recap: all 7 key points
- Prefill is compute-bound and parallel; decode produces one token per step and is bound by memory bandwidth (reading weights + KV cache).
- KV cache per token = 2 · L · n_kv · d_head · bytes; Llama 2 7B needs 0.5 MB per token in fp16, Llama 3 8B (GQA, 8 KV heads) 128 KB.
- Arithmetic intensity of a decode step ≈ batch size, far below the GPU's ridge point at small batches — hence continuous batching and PagedAttention.
- GQA shares K/V heads across groups of query heads, shrinking the cache by n_heads / n_kv with little quality loss.
- FlashAttention tiles Q, K, V through SRAM and uses the online softmax to compute exact attention with O(n) memory and 2–4× speed.
- Speculative decoding verifies γ draft tokens in one target pass; with acceptance rate α it yields (1 − α^(γ+1))/(1 − α) tokens per pass and the exact target distribution.
- Quantization to int8/int4 cuts weight bytes 2–4× with small perplexity cost; GPTQ, AWQ and NF4 are the common 4-bit schemes.
Watch
The KV-cache and grouped-query-attention segments with diagrams of what is cached and why.
Read
Try it live
Interactive demo
runs in your browserExercises
- Size a deployment
For Llama 3 70B (, 64 query heads, 8 KV heads, ) in bf16, compute weight memory and KV-cache memory per token, then the maximum batch size of 8k-token conversations on a 2×80 GB server. Expected: ≈140 GB of weights, 320 KB per token, and only a handful of concurrent 8k conversations — then recompute with int8 weights and an int8 KV cache.
- Measure the cache and quantization
With Hugging Face, generate 256 tokens from a 1–3B model with
use_cacheon and off, then load the model in 8-bit and 4-bit withbitsandbytes. Record tokens/s and GPU memory for each. Expected: the cache gives flat per-token latency; 4-bit roughly quarters memory with a small throughput change on consumer GPUs. - Simulate speculative decoding
Write a Python simulation where a draft distribution and target are small categorical distributions; implement the accept/reject rule, run 100,000 steps, and compare the empirical output distribution with . Then vary and and plot tokens per pass against the formula. Expected: the histogram matches , and the measured tokens per pass track .
Quiz
Flashcards
These cards are now in your spaced-repetition queue. Review all due cards →