Skip to content
The KV Cache

03.01 · Walkthrough · Free

Why Cache Anything

Measure the speedup from KV caching directly. Benchmark an uncached generation against a cached one on GPT-2, observe that speedup is a function of output length, and explain why a short generation shows almost nothing.

This video is hosted by Klay so it plays even when YouTube blocks embedding.

Curated for this lesson

The KV Cache

CS336 L10: Inference

Segment covering Why Cache Anything from Stanford Online.

KV caching speeds autoregressive decoding by storing previous key and value projections, so each new token avoids rerunning most work over the whole prefix. The visible gain depends strongly on generated length: tiny outputs are dominated by fixed overhead, while longer outputs expose the recomputation that caching removes.

What this lesson answers

  • why does KV cache speed up generation
  • how benchmark GPT-2 with and without KV cache
  • why short outputs show little KV cache speedup

Notes

KV caching is the inference-time memoization of the key and value projections for all previously generated tokens in an autoregressive Transformer, so step computes only for the new token and attends to cached instead of recomputing for the entire prefix. For one attention layer, uncached decoding repeatedly evaluates for all tokens seen so far and forms attention for the growing prefix; cached decoding updates and , then computes . The useful measurement is therefore not “tokens per second” in isolation, but for the same prompt and output length , because the avoided work grows with the decoded suffix. GPT-2 is a good lab model precisely because the difference is visible on a laptop GPU while still small enough that framework overhead can obscure the first few tokens.

For a walkthrough benchmark, run GPT-2 once with `use_cache=False` and once with `use_cache=True`, keeping greedy decoding, batch size , fixed prompt, identical max new tokens, warmed kernels, CUDA synchronization around the timed region, and no sampling overhead. If the prompt length is and the model emits tokens, a naive uncached loop feeds lengths through the full Transformer, so the repeated-sequence part scales roughly like . The cached loop pays one prefill over tokens and then single-token decode steps, with attention still reading a growing cache but MLP and projection work no longer repeated for old tokens. Thus a short generation such as often shows almost nothing: the one-time Python dispatch, tokenizer, CUDA graph warmup failure, and prefill dominate, while the avoided term token-equivalents is tiny. At , the avoided repeated suffix is token-equivalents, so the speedup becomes obvious even on GPT-2.

A concrete expectation check helps students avoid mystical explanations. GPT-2 small has layers, hidden size , heads, and FP16 KV entries of bytes; its KV cache footprint per token is , about KiB/token. For a run, the cache at the end is only B, about MiB, so caching is not memory-capacity limited. The uncached loop, however, reprocesses token positions, while the cached path processes a prefill of plus decode positions, or positions through the non-attention projections and MLPs. The ratio is an upper bound for the repeatable block work; measured end-to-end speedup will be far lower because single-token decode has poor matmul occupancy and still streams weights every token, but it explains why looks qualitatively different from .

On production-sized models, the same mechanism trades compute recomputation for KV memory bandwidth and capacity. For a B decoder in FP16 with grouped-query attention using KV heads, head dimension , and say layers, the KV footprint per token is B, about KiB/token. An 80GB H100 has about TB/s HBM bandwidth, so a single request at context length must read roughly GB of KV per generated token, giving a bandwidth lower bound of ms/token just to stream cached KV, before weights and logits. Without a cache, the model would instead redo all layers for thousands of old tokens every step, which is catastrophically worse; with the cache, decode becomes memory-bandwidth dominated rather than FLOP dominated. This is why FlashAttention from Dao et al. attacks attention IO, PagedAttention from the vLLM paper attacks KV allocation and fragmentation, and TensorRT-LLM’s in-flight batching plus paged KV cache try to keep the H100 busy despite single-token decode.

The technique stops helping when the saved recomputation is smaller than the cost of maintaining and reading the cache, or when the cache forces a worse execution regime. Concretely, for GPT-2 with and a short prompt, `use_cache=True` can benchmark equal or slower because `past_key_values` object handling, extra memory writes, and less favorable kernel shapes exceed the avoided work. For large models, very long contexts or large batch sizes can make KV cache bandwidth and capacity the bottleneck: the B example at tokens already reads gigabytes of KV per token per sequence, and multiplying by dozens of active sequences can hit HBM bandwidth or evict blocks, causing scheduler stalls. Caching also interacts badly with training-style full-sequence kernels: FlashAttention is excellent for prefill because it tiles the computation without materializing the attention matrix, but decode with one query per sequence is a different low-arithmetic-intensity kernel. Prefixes that are never reused, speculative branches that are rejected, or beam searches with aggressive branching can store KV that is soon discarded.

The real systems students will see are engineering around this exact cache, not replacing it. Hugging Face exposes the basic `past_key_values` switch used in a GPT-2 lab; vLLM’s 2023 PagedAttention paper virtualizes KV blocks so continuous batching does not require contiguous per-request allocations; SGLang’s RadixAttention paper/release reuses KV across shared prompt prefixes in structured serving programs; TensorRT-LLM’s 2023-2024 releases implement paged KV cache, inflight batching, and quantized KV paths; NVIDIA Dynamo is the 2025 disaggregated serving stack that separates prefill and decode workers because their cache and compute profiles differ; llm-d is the Kubernetes-native distributed inference project that routes and schedules around KV locality; FlashAttention’s papers define the IO-aware attention kernels used heavily in prefill; and EAGLE is speculative decoding, where draft tokens only become useful if their KV survives verification. In the GPT-2 exercise, the student should report a table of versus , , and , then explain the curve by the arithmetic above: near-flat at tiny , rising once repeated old-token work dominates, and eventually limited by memory traffic and decode overhead rather than recomputation.

Common questions

What does a KV cache store during Transformer inference?
It stores the key and value tensors produced for earlier tokens in each attention layer. During decoding, the model computes the query, key and value for the new token, then attends the new query over the stored keys and values instead of rebuilding them for the whole prefix.
Why can KV caching show no improvement for short generations?
For a very small number of generated tokens, the avoided recomputation is also small. Fixed costs such as framework dispatch, tokenisation, kernel warmup, synchronisation and cache object handling can dominate the timed region, so the cached and uncached paths may look similar, or the cached path may even appear slower.
What should a fair KV cache benchmark control?
Compare the same model, prompt, decoding policy, batch size and output length with caching enabled and disabled. Warm the kernels, avoid sampling overhead if measuring the cache itself, and synchronise GPU work around timing. Report the ratio between uncached and cached time rather than only raw tokens per second.