TAI BUI
Back to curriculum
BuildPython

Speculative Decoding — Draft, Verify, Repeat

Speculative decoding lets a cheap draft model propose N tokens that the expensive verifier checks in one forward pass. Autoregressive decoding is serial, with each token waiting on the one before it, so when the draft is right you pay for one big forward and get N generations.

TIME: ~60 minutesPREREQUISITES: Phase 7 · 07 (GPT Causal LM), Phase 7 · 12 (KV Cache & Flash Attention)

Learning Objectives

  • Explain how a cheap draft model and an expensive verifier combine to produce several tokens per big-model forward pass.
  • Apply the accept rule min(1, q/p) and the residual distribution (q - p)_+ to show why the output matches the verifier's own distribution.
  • Estimate expected tokens per verifier call from the acceptance rate and draft length, and name what drives the acceptance rate.
  • Choose between vanilla, Medusa, EAGLE and lookahead for a workload, and describe the KV-cache rollback needed after a rejection.

The Problem

Speculative decoding is a way to generate tokens from a large model faster: a small draft model proposes several tokens ahead, and the large model, called the verifier, checks all of them in a single forward pass.

The arithmetic: a 70B LLM sampling one token takes ~30 ms on an H100, and a 3B draft model takes ~3 ms. If the 3B drafts 5 tokens ahead and the 70B runs once to verify all 5, the total is 5×3 + 30 = 45 ms for up to 5 accepted tokens, versus 5×30 = 150 ms for straight-line generation. That is the whole pitch: spend a little extra GPU memory on the draft model and get 2–4× lower decode latency.

The trick has to preserve the distribution. Speculative sampling, introduced by Leviathan et al. (2023) and by Chen et al. concurrently, guarantees that the output sequence is identically distributed to what the big model would have produced on its own. No quality tradeoff. Just faster.

Four families of draft-verifier pairs dominate 2026 inference:

  1. Vanilla speculative (Leviathan 2023). A separate draft model (e.g., Llama 3 1B) plus a verifier (e.g., Llama 3 70B).
  2. Medusa (Cai 2024). Multiple decoding heads on the verifier predict positions t+1..t+k in parallel. No separate draft model.
  3. EAGLE family (Li 2024, 2025). A lightweight draft that reuses the verifier's hidden states. Its acceptance rate is higher than vanilla's, and a 3–4× speedup is typical.
  4. Lookahead decoding (Fu 2024). Jacobi iteration with no draft model at all. This is self-speculation: niche, but dependency-free.

Production inference stacks ship speculative decoding by default in 2026. vLLM, TensorRT-LLM, SGLang, and llama.cpp all support at least vanilla and EAGLE-2.

Warm-up0/3
1. Why is generating text from a large causal language model slow, token by token?Warm-up
Three rows showing a short reply growing one word at a time: one word after one step, two after two steps, three after three steps. Later slots are empty dashed boxes.
Typed, illustrative reply; not captured from a model.
2. In a decoder with a KV cache, what does the cache hold between decoding steps?Warm-up
Four tokens (The, cat, sat, on) marked as already processed, a new token the arriving in this step, and a dashed box asking what is saved in memory between decoding steps.
Typed, illustrative tokens.
3. When a causal LM runs one forward pass over a sequence of several tokens, what does it output?Warm-up
Four input tokens (The, cat, sat, on) feed a causal language model in one pass. An arrow leads to a dashed box asking what comes out of the pass.
Typed, illustrative tokens.
Check: The Problem0/6
1. What is the draft model in speculative decoding?Define
A terminal showing a vllm serve command for Llama-3.1-70B-Instruct with a speculative-model option naming Llama-3.2-1B-Instruct and 5 speculative tokens.
Command copied from the lesson's Use It section; not run here.
2. What is the verifier in speculative decoding?Define
Two boxes. Model A has 3B parameters and takes about 3 ms per token. Model B has 70B parameters and takes about 30 ms per token.
Both models are used in each speculative step.
3. What is lookahead decoding?Define
A numbered list of four families with their papers: 1 Vanilla speculative (Leviathan 2023), 2 Medusa (Cai 2024), 3 EAGLE family (Li 2024, 2025), 4 Lookahead decoding (Fu 2024), the last highlighted.
Names and papers from the lesson's Problem section.
4. The Problem section's arithmetic has a ~3 ms draft and a ~30 ms verifier. Why does drafting 5 tokens and verifying once beat plain generation?Explain
Two timelines drawn to scale. Plain generation shows five 30 ms blocks, total unknown. Speculative shows five thin 3 ms draft slivers followed by one 30 ms verify block, total unknown.
Block lengths proportional to the 3 ms and 30 ms figures in the Problem section.
5. What does speculative sampling guarantee about its output?Explain
Grouped bars over token ids 0 to 7: verifier q falls from 0.35 to 0.02, draft p is a noisy version of it. Text asks what distribution the speculative output follows.
q is from code/main.py; p is its draft with noise 0.25, seed 7.
6. Using the Problem section's timings (3 ms per draft token, 30 ms per verifier pass), what is the best-case time for 8 drafted tokens that are all accepted, and for 8 plain steps?Apply
Two timelines to scale. Plain generation shows eight 30 ms blocks, total unknown. Speculative shows eight thin 3 ms draft slivers then one 30 ms verify block, total unknown.
Block lengths proportional to 3 ms per draft token and 30 ms per verifier pass.

The Concept

The core algorithm

Given a verifier M_q and a cheaper draft M_p:

  1. Let x_1..x_k be the prefix already decoded.
  2. Draft: use M_p to autoregressively propose d_{k+1}, d_{k+2}, ..., d_{k+N} with draft probabilities p_1..p_N.
  3. Verify in parallel: run M_q once on x_1..x_k, d_{k+1}, ..., d_{k+N}, getting verifier probabilities q_1..q_{N+1} for positions k+1..k+N+1.
  4. Accept or reject each draft token left to right: for each i, accept with probability min(1, q_i(d_i) / p_i(d_i)).
  5. On the first rejection at position j: sample t_j from the "residual" distribution (q_j - p_j)_+, normalized. All drafts after j are discarded.
  6. If all N are accepted: sample one extra token t_{N+1} from q_{N+1} (the free bonus token).

The residual distribution is the mathematical insight that keeps the output distributed exactly as if M_q had sampled from scratch.

What determines speedup

Let α be the expected acceptance rate per draft token and c the draft-to-verifier cost ratio. Per step, naive generation makes 1 big-model call per token. Speculative decoding makes 1 big-model call per (1 - α^{N+1}) / (1 - α) ≈ 1/(1-α) tokens when α is high.

A rule of thumb at α = 0.75 and N = 5: 3× fewer big-model calls. The draft costs 5× less per call, and total wall-clock drops ~2.5×.

α depends on:

  • How well the draft approximates the verifier. Same family or same training data raises α significantly.
  • Decoding strategy. A greedy draft against a greedy verifier gives high α. Temperature sampling is harder to match, and acceptance drops.
  • Task type. Code and structured output accept more because they are predictable. Free-form creative writing accepts less.

Medusa: drafts without a draft model

Medusa replaces the draft model with extra output heads on the verifier. At position t:

shared trunk → hidden h_t
    ├── head_0: predict token at t+1  (standard LM head)
    ├── head_1: predict token at t+2
    ├── head_2: predict token at t+3
    ├── head_3: predict token at t+4

Each head outputs its own logits. At inference you sample from each head to get a candidate sequence, then verify with one forward pass using a tree-attention scheme that considers all candidate continuations at once.

The upside is that there is no second model to host. The cost is extra trainable parameters and a supervised fine-tuning stage (~1B tokens), and the acceptance rate runs a bit lower than vanilla speculative decoding with a good draft.

EAGLE: a better draft from reused hidden states

EAGLE-1/2/3 (Li et al., 2024–2025) makes the draft model a tiny transformer (typically 1 layer) that ingests the verifier's last-layer hidden states. Because the draft sees the verifier's feature representation, its predictions correlate strongly with the verifier's output distribution. Acceptance rates climb from ~0.6 (vanilla) to 0.85+.

EAGLE-3 (2025) added tree search over candidate continuations. vLLM and SGLang ship EAGLE-2/3 as the default spec pathway for Llama 3/4 and Qwen 3.

The KV cache dance

Verification feeds N draft tokens into the verifier in one forward pass, which extends the verifier's KV cache by N entries. If some drafts are rejected, you must roll the cache back to the accepted prefix length.

Production implementations (vLLM's --speculative-model, TensorRT-LLM's LookaheadDecoder) handle this with scratch KV buffers: write first, commit on acceptance. The idea is not conceptually hard, but the bookkeeping is fiddly.

Check: The Concept0/19
1. What does the acceptance rate α measure?Define
Terminal output from main.py with two columns, KL(q||p) and acceptance alpha, over six rows with acceptance values 0.980, 0.915, 0.878, 0.798, 0.485 and 0.478.
Real output of code/main.py, seed 7, one run.
2. On a rejection, what is the residual distribution?Define
Grouped bars over tokens A, B and C. Verifier q: 0.50, 0.35, 0.15. Draft p: 0.20, 0.30, 0.50. Text says the rejected draft token is C and the replacement token is unknown.
Illustrative numbers, typed.
3. All N drafted tokens are accepted. What is the bonus token?Define
A prefix box, three drafted tokens d1 to d3 each with a green check mark, and a dashed box with a question mark for an extra token that follows.
N = 3 chosen for illustration.
4. What is Medusa, and how does it differ from vanilla speculative decoding?Define
Two panels. Vanilla speculative decoding shows a draft model feeding a verifier. Medusa shows a dashed question-mark box feeding a verifier, captioned with a question about where the proposals come from.
5. What is the draft in EAGLE?Define
A terminal showing a vllm serve command for Llama-3.1-70B-Instruct with a speculative-model path /models/llama-3.1-eagle-70b, draft tensor parallel size 1 and 5 speculative tokens.
Command copied from the lesson's Use It section; not run here.
6. What is tree attention used for in Medusa-style verification?Define
Three Medusa heads head_1 to head_3, each with one proposed token (cat, sat, on), next to a dashed box asking what tree attention is used for.
Candidate words typed, illustrative.
7. Some drafted tokens are rejected during verification. What is KV rollback?Define
A row of 15 cache cells: 10 prefix entries numbered 1 to 10 and 5 draft entries d1 to d5. Under d1 and d2 are green check marks and under d3 a red cross. A dashed box asks what cache the next step should start from.
Prefix length 10 and rejection at draft 3 follow the lesson's Exercise 4.
8. At position j a draft token is rejected. What does the algorithm do next?Explain
Four drafted tokens d1 to d4. A green check under d1, a red cross under d2 labelled position j, and a dashed box asking what happens next.
N = 4 and j = 2 chosen for illustration.
9. Which three factors does the acceptance rate α depend on?Explain
Three dashed boxes labelled factor 1, factor 2 and factor 3, each with a question mark, point to a box for the acceptance rate alpha, which points to a box for tokens per verifier call.
10. Why does a draft from the same family as the verifier usually raise the acceptance rate?Explain
A table with two rows. Draft Llama-3.2-1B, same family as the verifier, alpha unknown. Draft another model, different family, alpha unknown.
Model names from the lesson's vLLM example; the second row is a generic placeholder.
11. Why does EAGLE reach acceptance of 0.85+ where vanilla sits near 0.6?Explain
Two bars of acceptance rate alpha: vanilla near 0.6 and EAGLE at 0.85 or more, with a note asking what explains the gap.
Figures from the question stem and the lesson's EAGLE section; bar heights are approximate.
12. What does Medusa cost in exchange for dropping the separate draft model?Explain
A table comparing vanilla and Medusa. A separate draft model is hosted for vanilla and not for Medusa. The Medusa cell for what it costs instead is a question mark.
13. Why do production systems write drafted tokens into scratch KV buffers and commit only on acceptance?Explain
A KV cache row of 10 entries and, below it, a dashed scratch buffer with five entries d1 to d5. An arrow points to the text write first, commit on acceptance.
Layout is a schematic of the lesson's description.
14. At α = 0.75 and N = 5, what does the Concept section's rule of thumb say about verifier calls?Apply
Five drafted tokens d1 to d5 feed one verifier call. Two dashed boxes ask how many tokens are kept per call and how many times fewer big-model calls than plain decoding.
15. Using (1 - α^{N+1}) / (1 - α), about how many tokens per verifier call at α = 0.5 and N = 3?Apply
Three drafted tokens d1 to d3, each labelled accepted with probability 0.5, a dashed bonus token box, and a dashed box asking for expected tokens per verifier call.
16. With N = 5, the verifier accepts drafts 1 and 2 and rejects draft 3. How many new tokens does this step produce?Apply
Five drafted tokens d1 to d5. Green checks under d1 and d2, a red cross under d3, no verdict under d4 and d5. A dashed box asks how many new tokens this step produces.
17. Your team serves a chat product at temperature 1.5 for creative writing, and speculative decoding barely helps. What is the likely cause?Analyze
A report card: product is chat, workload is creative writing, temperature 1.5, speculative decoding is on, and the speed gain barely helps.
Typed from the question stem; not a real log.
18. After a rejection, the next decoding step produces text that seems to attend to tokens that were discarded. Which piece is missing?Analyze
Five numbered steps: draft 5 tokens; one verifier pass over the 5 drafts; reject at position 3 and sample a replacement; step 4 unknown, dashed; next decode step attends to discarded tokens.
19. A deployment sees about 3× fewer verifier calls but only about 2.5× lower wall-clock latency. What explains the gap?Analyze
Two bars: verifier calls 3x lower and wall-clock latency 2.5x lower, with text asking why the gap exists.
Figures are from the question stem.

Build It

See code/main.py. It implements the core speculative-sampling algorithm (rejection step plus residual distribution) with:

  • A "big model" that is a deterministic softmax over a hand-coded distribution, so the acceptance math can be checked analytically.
  • A "draft model" that is a perturbation of the big model.
  • An acceptance and rejection loop that produces the same marginal distribution as direct sampling.

The snippets below are illustrative. In main.py the accept test is inline, and the functions are residual(q, p), spec_step_one_token(q, p, rng) and spec_step_n(q, p, N, rng). They take fixed q and p probability vectors per call, so there is no prefix, no model callables, and no KV cache.

Step 1: the rejection step

python
def accept_or_reject(q_prob, p_prob, draft_token, u):
    ratio = q_prob / p_prob if p_prob > 0 else float("inf")
    return u < min(1.0, ratio)

u is a uniform random number. q_prob is the verifier's probability for the drafted token and p_prob is the draft model's. The Leviathan theorem says this Bernoulli decision, followed by sampling from the residual on rejection, preserves the verifier's distribution exactly.

Step 2: residual distribution

python
def residual_dist(q, p):
    raw = [max(0.0, qi - pi) for qi, pi in zip(q, p)]
    s = sum(raw)
    return [r / s for r in raw]

Subtract p from q element-wise, clamp negative values to zero, and renormalize. On a rejection, sample from this. main.py's residual(q, p) returns list(q) when the clamped sum is 0 (which only happens when q == p), where the snippet above would divide by zero.

Step 3: one speculative step

python
def spec_step(prefix, q_model, p_model, N, rng):
    drafts = []
    p_probs = []
    ctx = list(prefix)
    for _ in range(N):
        p_dist = p_model(ctx)
        d = sample(p_dist, rng)
        drafts.append(d)
        p_probs.append(p_dist[d])
        ctx.append(d)
 
    q_dists = [q_model(prefix + drafts[:i]) for i in range(N + 1)]
 
    for i, d in enumerate(drafts):
        u = rng.random()
        q_prob = q_dists[i][d]
        p_prob = p_probs[i]
        if u < min(1.0, q_prob / p_prob if p_prob > 0 else float("inf")):
            prefix = prefix + [d]
        else:
            res = residual_dist(q_dists[i], p_model(prefix))
            prefix = prefix + [sample(res, rng)]
            return prefix
    prefix = prefix + [sample(q_dists[N], rng)]
    return prefix

Five accepted → one bonus → six tokens produced in one verifier pass.

This snippet is a sketch of the full algorithm with model callables, not code from main.py; the file's spec_step_n(q, p, N, rng) runs the same accept loop on fixed vectors. One detail worth getting right: on rejection at position i, the p in the residual must be the draft distribution that produced the rejected draft, which is the draft's distribution at context prefix + drafts[:i]. Here that works because prefix has already been extended by each accepted draft by the time the rejection branch runs, but storing the draft distributions from the drafting loop and reusing p_dists[i] is clearer and harder to break.

Step 4: measure acceptance rate

main.py runs 5,000 one-token speculative steps at each of six draft-noise levels and prints a table of acceptance rate next to the KL divergence between verifier and draft distributions. It prints a table rather than a plot, so plot it yourself if you want the curve. The relationship comes out monotone: more KL, lower acceptance. It then prints expected tokens per verifier call for N of 1, 3, 5, 7 and 10 at five values of α, and its takeaway line (α = 0.85, N = 5 gives about 4.1 tokens per call) is a count of verifier calls. It measures no wall-clock time, so the rule of thumb in The Concept (α = 0.75, N = 5, about 3× fewer calls and ~2.5× wall-clock) is a figure to check on your own workload.

Step 5: verify distribution equivalence

The histogram of tokens produced by the speculative loop should match the histogram from sampling directly from the verifier. This is the Leviathan theorem in practice. main.py draws 50,000 tokens each way using spec_step_one_token (not the N-token path), computes a chi-square statistic, and prints PASS when it is under 30 on 7 degrees of freedom. It does not compute a p-value.

Check: Build It0/5
1. A drafted token has verifier probability q(d) = 0.2 and draft probability p(d) = 0.4. What is the chance it is accepted?Apply
Two horizontal bars on a 0 to 1 scale: draft p(d) of 0.4 and verifier q(d) of 0.2. Text asks for the chance this token is accepted.
2. In accept_or_reject, the drafted token has q_prob = 0.3 and p_prob = 0.4, and u = 0.8. What does it return?Apply
A Python call accept_or_reject with q_prob 0.3, p_prob 0.4 and u 0.8, whose result is a question mark, above a 0 to 1 number line with u marked at 0.8.
Call typed from the stem; draft_token is written as d because the function never uses it.
3. With q = [0.5, 0.4, 0.1] and p = [0.3, 0.3, 0.4], what does residual_dist(q, p) return, to two decimals?Apply
A Python call residual_dist with q = [0.5, 0.4, 0.1] and p = [0.3, 0.3, 0.4], result unknown, above grouped bars of q and p over tokens A, B, C.
Call typed from the stem.
4. Using the formula (1 - α^{N+1}) / (1 - α), about how many tokens does `main.py`'s table show per verifier call at α = 0.85 and N = 5?Apply
Header lines of the theory table from main.py with columns N = 1, 3, 5, 7 and 10 and a row for alpha 0.85 whose values are all question marks.
Layout copied from main.py's output; values hidden.
5. A speculative loop's output histogram no longer matches direct sampling from the verifier. Its rejection branch builds the residual from the draft distribution at the original prefix, even after earlier drafts were accepted. What is wrong?Analyze
A prefix box, drafts d1 and d2 with checks and d3 with a cross. Text says the residual is built from q and p_model(prefix), and the output histogram differs from direct sampling.
Setup typed from the stem.

Use It

In production you launch a server with the speculative settings:

bash
# vLLM with EAGLE
vllm serve meta-llama/Llama-3.1-70B-Instruct \
    --speculative-model /models/llama-3.1-eagle-70b \
    --speculative-draft-tensor-parallel-size 1 \
    --num-speculative-tokens 5
 
# vLLM with vanilla draft model
vllm serve meta-llama/Llama-3.1-70B-Instruct \
    --speculative-model meta-llama/Llama-3.2-1B-Instruct \
    --num-speculative-tokens 5

TensorRT-LLM has the fastest Medusa path as of mid-2026. faster-whisper wraps speculative decoding for Whisper-large with a small draft.

Picking a draft:

StrategyWhen to pickSpeedup
Vanilla draft (1B/3B Llama family)Fast prototype, no training1.8–2.3×
Medusa headsYou can fine-tune the verifier2–3×
EAGLE-2 / 3Production, max speed3–4×
LookaheadNo draft, no training, no extra params1.3–1.6×

When NOT to spec-decode:

  • Single-sequence generation of 1–5 tokens. Overhead dominates.
  • Wildly creative or high-temperature sampling (α drops).
  • Memory-constrained deployments (the draft model adds VRAM).
Check: Use It0/3
1. A workload returns 3-token replies on a memory-tight GPU. What does the Use It section advise?Design
A card saying reply length is 3 tokens and the GPU is memory-tight, with three token boxes tok 1 to tok 3 below.
Typed from the question stem.
2. You serve a 70B model in production, max speed is the priority, and you can train a lightweight one-layer draft. Which strategy fits?Design
A card: verifier 70B, setting production, priority max speed, can train a lightweight one-layer draft. A line lists the strategies vanilla, Medusa, EAGLE and lookahead.
Typed from the question stem.
3. You cannot fine-tune the verifier and want no extra model or parameters. Which strategy fits the Use It table?Design
A constraints card: cannot fine-tune the verifier, no extra model to host, no extra parameters. A line lists vanilla, Medusa, EAGLE and lookahead as the strategies to choose from.
Typed from the question stem.

Ship It

The skill in outputs/skill-spec-decode-picker.md picks a speculative decoding strategy (vanilla / Medusa / EAGLE / lookahead) and tuning parameters (N, draft temperature) for a new inference workload.

Check: Ship It0/1
1. What does this lesson's Ship It skill, spec-decode-picker, produce?Explain
A workload box feeds the spec-decode-picker skill file, which feeds a dashed box labelled produces, question mark.
Author's Note

Before I trust a speedup number, I want the distribution check in main.py to pass. It samples 50,000 tokens both ways and prints PASS when chi^2 is under 30 on 7 degrees of freedom. It doesn't compute a p-value, so for Exercise 1 I work out the p > 0.05 test myself instead of leaning on that threshold.

The number I'd carry away is how α moves with draft quality. main.py sweeps six noise levels and prints acceptance rate next to KL(q || p), then prints expected tokens per verifier call for N of 1, 3, 5, 7, and 10 at five values of α. That table counts verifier calls, not milliseconds, and its own takeaway line says "minus draft-model overhead." The speedup figures in the Use It table are claims to measure on your own workload.

The script also leaves something out. Its q and p are fixed distributions per call, so it has no prefix and no KV cache, and the rollback problem doesn't come up. Exercise 4 is where it does, and I'd do it before putting any of this near a serving stack.

Exercises

  1. Easy. Run code/main.py. Confirm the speculative token distribution matches the verifier's direct-sample distribution on 50,000 tokens. main.py prints the chi-square statistic and PASS under 30; to test p > 0.05 yourself, compare the statistic against the 7-degree-of-freedom critical value of 14.07.
  2. Medium. Plot speedup (tokens per big-model forward) as a function of N for α = 0.5, 0.7, 0.85. Identify the optimal N for each α. (Hint: expected tokens per verify call = (1 - α^{N+1}) / (1 - α).)
  3. Hard. Implement a tiny Medusa: take the capstone GPT from Lesson 14, add 3 extra LM heads that predict positions t+2, t+3, t+4. Train on tinyshakespeare with a joint multi-head loss. Compare acceptance rates vs a vanilla draft made by truncating the same model.
  4. Hard. Implement rollback: start with a 10-token prefix KV cache, feed 5 draft tokens, simulate a rejection at position 3. Verify your cache reads correctly match "prefix + first 2 accepted drafts" at the next iteration.

Key Terms

TermWhat people sayWhat it actually means
Draft model"The cheap one"A smaller model that proposes candidate tokens; usually 10–50× cheaper than the verifier.
Verifier"The big one"The target model whose distribution we preserve; runs once per speculative step.
Acceptance rate (α)"How often the draft is right"Per-token probability that the verifier accepts the draft. 0.7–0.9 typical.
Residual distribution"The rejection fallback"(q - p)_+ normalized; sampling from this on rejection preserves the verifier's distribution.
Bonus token"The free one"When all N drafts accepted, sample one more from the verifier's next-step distribution.
Medusa"Draft-less speculative"Multiple LM heads on the verifier predict positions t+1..t+k in parallel.
EAGLE"Hidden-state draft"Tiny transformer draft conditioned on the verifier's last-layer hidden states.
Lookahead decoding"Jacobi iteration"Self-speculation using a fixed-point iteration; no draft model.
Tree attention"Verify many candidates at once"Branching verification that considers several draft continuations simultaneously.
KV rollback"Undo rejected drafts"Scratch KV buffer; commit on acceptance, discard on reject.

Further Reading

Code

Ships With