LLM Inference Engineer · Day 28
Day 28 · Week 4 · Optimization & Capstone

Capstone Part 2: KV Cache, Masks, and Sampling Loop

A single forward pass becomes an inference engine when it can prefill once, decode one token at a time from cache, sample controllably, and stop correctly.

Time~230 min
DifficultyHard
PrerequisiteDays 15, 20, 27
Notebookday-28-capstone-pt2
Why This Lesson

Why this optimization matters.

Day 27 proved the model can run. Day 28 makes it usable. KV cache is the difference between recomputing the whole prefix every token and appending only the new key/value rows. Sampling turns raw logits into product behavior.

Learning Objectives

What you should be able to do today.

  1. Add optional per-layer KV cache to attention.
  2. Distinguish prefill causal masks from decode masks.
  3. Implement generate(prompt, max_new_tokens, sampling_params).
  4. Support greedy, temperature, top-k, and top-p sampling.
  5. Benchmark no-cache versus cached decode.
Notation Cheatsheet

Decode the symbols before using them.

  • prefill is the full prompt forward that initializes cache.
  • decode is one new-token step using existing cache.
  • cache_len is the number of valid cached positions.
  • position_offset is the RoPE position where the new token starts.
  • eos_token_id stops generation.
Cache API

Attention must accept reusable state.

Update attention to accept cache state. Prefill appends many positions at once. Decode appends one. The cache object should track valid length so uninitialized preallocated memory is never attended to.

Prefill to Decode prompt tokens prefill full T cache K/V decode one token append Prefill initializes the cache; decode extends it one position at a time.
Prefill initializes the cache; decode extends it one position at a time.
Masks Change Shape

Prefill and decode masks are different objects.

Prefill for a prompt length T uses a causal [T, T] mask. Decode for one new token uses a single query row against all valid cached keys, usually all zeros over [1, cache_len + 1]. Most KV-cache bugs are off-by-one mask or RoPE offset bugs.

Prefill Causal Mask visible 10/16 active future masked 6/16 active decode row 16/16 active Prefill needs triangular masking; decode has one current query.
Prefill needs triangular masking; decode has one current query.
Generation Loop

Prefill once, then decode from state.

The loop is tokenize, prefill prompt and store K/V, sample first next token, then repeatedly run one-token decode, sample, append, and stop on EOS or max_new_tokens.

Cache Growth Over Decode K cache prompt V cache prompt Every generated token appends one K row and one V row per layer.
Every generated token appends one K row and one V row per layer.
Sampling Contract

Sampling is part of the engine contract.

Greedy decode is deterministic. Temperature divides logits before softmax. Top-k removes all but the largest k logits. Top-p sorts probabilities and keeps the smallest set whose cumulative mass is at least p. For reference matching, start with greedy.

Sampling Pipeline logits penalties temperature top-k/top-p sample token Sampling controls happen after logits and before token selection.
Sampling controls happen after logits and before token selection.
Benchmark Shape

Benchmark the exact shape split.

Measure prompt lengths [32, 128, 512] and output lengths [32, 128, 256]. Compare no-cache and cached generation. Expect cache speedup to grow as context length grows.

Common Divergence Causes wrong mask future leakage wrong RoPE offset position drift wrong cache length attend garbage RNG mismatch different samples Token mismatches are symptoms; these are common root causes.
Token mismatches are symptoms; these are common root causes.
Did You Know?

A detail worth remembering.

KV cache improves latency but not mathematical output. With the same weights, positions, and masks, cached and uncached logits should match up to floating-point noise.
Exercise

Build the habit with code.

  1. Add cache state to attention and verify cached logits match uncached logits on a toy sequence.
  2. Implement greedy and temperature/top-k/top-p sampling.
  3. Generate 100 greedy tokens twice and verify determinism.
  4. Benchmark no-cache versus cache for the prompt/output grid.
Self-Check

Answer these from memory.

  1. Why no triangular mask for one-token decode? The single new query can see all valid past keys; there are no future query positions in that row.
  2. What does cache_len protect against? Attending to uninitialized or stale cache slots.
  3. Why compare greedy first? It removes sampling randomness from correctness tests.
  4. What causes RoPE drift? Using position 0 for every decode step instead of the absolute token position.
  5. What is the speedup source? Avoiding repeated K/V projection and prefix computation during decode.

"KV cache turns generation from replaying history into extending state."

Day 28 · Week 4
Further Reading

Go deeper.

Primary references and the companion notebook for today's exercise.

Source

HuggingFace GenerationMixin

Reference generation behavior.

Open
Lesson

Day 20 KV cache

Memory math and cache layout.

Open notebook
Lesson

Day 15 sampling

Sampling foundations.

Open notebook
Notebook

Day 28 notebook

Runnable companion notebook for the lesson.

Open notebook