6.1.13 · D2Scaling & Efficient Architectures

Visual walkthrough — KV-cache optimization

1,815 words8 min readBack to topic

Before we start, three words we will use over and over. We define them once, in plain language, and never before:


Step 1 — One word at a time (what "autoregressive" means)

WHAT. A model like GPT writes text one token at a time. To write token 4 it must first have written tokens 1, 2, 3. It cannot skip ahead.

WHY. This left-to-right rule is called causality: a word may only look at words before it, never after. That single restriction is the seed of everything on this page — it is exactly what makes past work reusable.

PICTURE. Each new step adds one square on the right. The arrows show that a new word looks backward only — never forward.

Figure — KV-cache optimization
  • — the embedding (a list of numbers) of the word at position .
  • The arrows mean "generated after," strictly left to right.

Step 2 — What each new word must compute

WHAT. When word arrives, the model multiplies it by three fixed weight-matrices to make its three characters:

  • fixed number-tables (learned during training, frozen now). "Fixed" is the key word.
  • — the incoming word vector, length .
  • — the three output vectors, each also length .

WHY. Because and never change during generation, the key and value a word produces are stamped once and stay forever. This is the deep reason caching is even possible — nothing about depends on how many words come later.

PICTURE. The word enters the box on the left; three arrows leave with . Notice and carry a little padlock 🔒 — once made, they are frozen.

Figure — KV-cache optimization

Step 3 — The naive way: recompute everything (the growing staircase)

WHAT. Suppose we do not cache. To generate token , a plain transformer treats the whole prefix as a brand-new sequence and recomputes from scratch — even though was already computed times before.

WHY. A raw forward pass has no memory between steps. It only knows "here is a sequence of tokens, produce their projections." So the work per step grows with .

PICTURE. Each step is a bar; step is blocks tall. Together they form a triangle — a staircase that keeps getting taller.

Figure — KV-cache optimization

Cost of one word's projection is roughly multiply-adds (a length- vector times a table). At step we redo this for words:

Add up every step from to :

  • — "1 + 2 + 3 + … + L," the area of the triangle, equal to .
  • The is the quadratic curse: double the text, quadruple the wasted work.

Step 4 — The cached way: compute once, remember (the flat road)

WHAT. Keep a notebook — the KV-cache. When word arrives, compute only its own (one word's worth), then glue them onto the notebook:

  • The semicolon means "stack a new row underneath." The notebook grows by exactly one row per step.
  • Old rows are never touched — they are the frozen 🔒 keys/values from Step 2.

WHY. Because those old rows can never change (frozen weights, past words fixed), re-deriving them is pure waste. We pay the cost once per word, ever.

PICTURE. Now every step is the same height (one block). The staircase collapses into a flat road of length .

Figure — KV-cache optimization
  • The inner count is now , not — that is the whole trick.

Step 5 — Where the factor is born (triangle ÷ rectangle)

WHAT. Divide the two totals.

WHY. The saving is exactly the sequence length. Write 2048 tokens → about 2048× less projection work. This is not an approximation trick; it is the ratio of a triangle's area to a rectangle's.

PICTURE. Overlay the tall triangle (naive) on the flat bar (cached). The triangle's area over the bar's area is the ratio — the factor made visible.

Figure — KV-cache optimization

Step 6 — Attention still needs a Query (why is NOT cached)

WHAT. We cache and . We do not cache . At step we still compute a fresh and score it against all cached keys:

  • — the one fresh query for the new word (its curiosity is unique to it).
  • — every cached key, lined up as columns to compare against.
  • — a shrink factor that keeps the numbers from blowing up ( = size of one head); it does not affect the counting argument.

WHY. A Key/Value is "what a word offers" — that never changes, so cache it. A Query is "what the current word is asking" — a brand-new question every step, so it cannot be reused. Caching would answer the wrong question.

PICTURE. One glowing new query arrow fires backward across all the padlocked keys. The query is new; the keys are all old-and-frozen.

Figure — KV-cache optimization

Step 7 — Edge cases: the corners where things could break

WHAT. Check the boundaries so no reader ever hits an unshown case.

Case A — the very first token (). The notebook starts empty. We compute , the cache becomes one row, and attends to just itself. No division problem, no "attend to nothing" — the flat road has length 1.

Case B — the causal mask must still apply. Even with a cache, a word may only look at rows . Since we append only when word arrives, the cache physically cannot contain future keys — the append order enforces the mask for free. (During prefill of a given prompt, an explicit mask is still applied.)

Case C — the sliding window (bounded memory). If we only ever keep the last rows, memory stops growing: instead of . The road becomes not just flat but of fixed length. Cost: words older than steps are forgotten. See sparse attention.

Case D — memory, the price we pay. Speed is free of extra memory per step, but the notebook itself grows linearly: . This is the trade explored in inference optimization and shrunk further by quantization and multi-/grouped-query attention.

PICTURE. A single strip: an empty box (t=1), a triangle grayed-out above the diagonal (mask blocks the future), and a fixed-width window sliding along a long ribbon.

Figure — KV-cache optimization

The one-picture summary

Figure — KV-cache optimization

The tall triangle (recompute-everything) versus the flat road (compute-once), with the padlocked notebook feeding the fresh query — the whole derivation in a single frame.

Recall Feynman retelling — say it back in plain words

Imagine writing an essay where, before adding each new sentence, you re-read the entire essay from the start. Sentence 100 makes you re-read 99 sentences you already know. That re-reading is the naive cost — the growing staircase, .

Now imagine you keep a notebook of one summary line per sentence you've written. To add a new sentence you glance at the notebook (already there) and jot one new line. Same story, but your work per sentence is now constant — the flat road, .

Two facts make the notebook trustworthy: (1) the model's weights are frozen, so a past word's Key/Value can never change — safe to store; (2) you only ever write forward, so the notebook can never leak a future word — the causal rule holds for free. Divide the staircase by the road and out pops the speedup: exactly the sequence length . The one thing you can't store is the Query, because every new word asks a brand-new question.

Recall Quick self-check

Why is the naive projection cost ? ::: Each step recomputes words' projections at each; summing gives . Why exactly speedup and not something else? ::: It's the ratio of the triangle area to the flat road , which equals . Why cache but never ? ::: = "what a past word offers," frozen and reusable; = "what the current word asks," new every step. What enforces the causal mask automatically in cached generation? ::: We only append when word arrives, so future keys are never physically present in the cache.


See also: Transformer architecture · Beam search (multiplies cache by beam width) · LLM deployment.