03.02 · Concept · Free
What Is Actually Stored
Explain that the KV cache stores past keys and values --- not queries --- and why. Trace the projections through a single attention head and identify which tensors are saved and which are recomputed.
Curated for this lesson
The KV Cache
Attention in Transformers, Ch 6
Segment covering What Is Actually Stored from 3Blue1Brown.
The KV cache stores previous keys and values for each layer and sequence, not previous queries. A new token computes its own query, scores it against cached keys, mixes cached values, then discards the query. This is the storage boundary behind grouped-query attention, prefix reuse, paged caches and KV memory planning.
What this lesson answers
- why does KV cache not store queries
- what tensors are saved in transformer decoding
- how do keys values and queries differ
Notes
A KV cache is the per-layer, per-sequence store of the key and value vectors produced for tokens that have already been prefilling or decoded; it deliberately does not store queries. For one attention head at layer , with hidden state , the projections are , , and , and causal attention for the newly generated token is . During autoregressive decoding, and are reused for every future token, while is only needed to ask one question of the past at the current position. Thus the cache contains and indexed by layer, KV head, token position, and head dimension; the current token’s is recomputed from the current hidden state and discarded after the attention output is formed. FlashAttention, from Dao et al. 2022 and FlashAttention-2 in 2023, changes how this attention is tiled and accumulated, but not the semantic fact that the persistent autoregressive state is past keys and values, not past queries.
Tracing a single grouped-query attention layer makes the storage boundary explicit. Suppose a model has hidden size , query heads, KV heads, and head dimension , as in a realistic Llama-family 70B-style configuration. At position , the layer computes with shape , with shape , and with shape . The query heads are partitioned into groups sharing the KV heads; each query head attends to one of the KV heads’ history. The implementation appends only and to the cache, so the per-layer token addition is elements, not . On the next decode step, is newly projected from the new residual stream, while and are read from cache and concatenated logically with . PagedAttention in vLLM, from Kwon et al. 2023, virtualizes this exact append-and-read pattern into block tables rather than contiguous per-request tensors.
The arithmetic shows why engineers obsess over KV and not Q. For a 70B model in FP16 with decoder layers, KV heads, and , each token’s KV cache is bytes bytes, about KiB per token per sequence. A -token conversation therefore consumes bytes, about GiB, before allocator fragmentation and metadata. On an 80GB H100 with TB/s HBM bandwidth, reading the full KV history for one new token at length moves roughly GB, so the bandwidth lower bound is s, or ms per generated token for KV reads alone, ignoring matmuls, softmax, and interconnect. Storing past queries would add bytes per token, four times the KV footprint, yet those old queries are never multiplied by future keys in causal decoding.
Prefill and decode differ only in lifetime, not in projection identity. During prefill, the system processes many prompt tokens together, so it computes for all prompt positions and can use FlashAttention kernels to avoid materializing the full attention matrix. After the layer’s prefill attention is complete, the block has no future use and is freed, while the generated and blocks become the initial cache for decode. During decode, each step has a batch of one logical position per active sequence, so the kernel computes fresh , writes into the cache, and performs attention from over cached . TensorRT-LLM’s inflight batching and paged KV cache, SGLang’s RadixAttention for prefix reuse, NVIDIA Dynamo’s disaggregated serving runtime, and llm-d’s Kubernetes-native inference stack all build scheduling and memory movement around this invariant: the reusable state is KV pages or blocks. EAGLE, from Li et al. 2024, speculates future tokens with a draft mechanism, but accepted tokens still contribute only their keys and values to the target model’s cache.
The technique stops helping when the cost of preserving and fetching KV exceeds the cost it saves or when the cached tensors are not valid for the computation being requested. At extremely short contexts, say , cache management overhead, page-table indirection, and kernel launch structure can dominate the small avoided projection work, so a fused no-cache path may be faster in microbenchmarks. Under severe memory pressure, a k-token request for the same 70B example needs GB of KV for one sequence, so seven such sequences nearly fill an 80GB H100 before weights if weights are not tensor-parallel sharded elsewhere; paging to CPU or NVMe can make time-to-token worse than recomputing or truncating. The cache is also invalid across weight changes, LoRA adapter changes that affect or , different RoPE scaling, different prompt bytes, or different layer normalization states. Prefix caching in vLLM, SGLang, TensorRT-LLM, Dynamo, or llm-d is therefore exact-match or carefully hashed reuse, not semantic similarity reuse.
A correct mental model is that a cached token is represented in every layer by two projected memory vectors, not by its text embedding and not by its query. The next token’s hidden state flows through to form a query that scores all older keys, and the resulting probabilities mix older values; after that, the query has served its only causal purpose. This is why multi-query and grouped-query attention reduce serving memory by shrinking while leaving large for model quality, and why cache quantization targets tensors rather than . It is also why PagedAttention’s block allocator, FlashAttention’s IO-aware attention, TensorRT-LLM’s paged-context kernels, SGLang’s prefix-radix cache, Dynamo’s KV-routing work, llm-d’s distributed KV-aware deployment, and EAGLE’s speculative acceptance path all talk about KV residency, KV transfer, and KV reuse. If a trace shows old queries being stored persistently during standard causal decoding, that trace is either naming a temporary kernel tile “Q cache” imprecisely or implementing a different algorithm than ordinary transformer inference.
Common questions
- What is actually stored in a KV cache?
- A KV cache stores the key and value vectors produced for earlier tokens, organised by layer, sequence, token position and KV head. It does not store token text, embeddings, attention scores or old queries. Those cached keys and values are the reusable state needed when later tokens attend back over the existing context.
- Why are old queries not cached during causal decoding?
- A query is only useful for the token currently being processed. It asks which earlier keys matter for that current position, then the result is used to mix values. Future tokens will form their own new queries from their own hidden states, so old queries would consume memory without being used by standard causal attention.
- Does FlashAttention change what belongs in the KV cache?
- No. FlashAttention changes how attention is computed, tiled and accumulated so it uses memory bandwidth more efficiently. It does not change the model semantics. During autoregressive inference, the persistent state is still the previously computed keys and values, while queries remain temporary tensors for the current attention computation.
