Speculative Decoding

AI & Machine Learning Foundations beginner How AI Works 12 min read

Overview

Speculative decoding is an inference optimization technique that accelerates large language model generation by 2–3× without changing the model’s output quality. It works by using a small, fast “draft” model to propose multiple tokens ahead, then having the large “target” model verify all proposed tokens in a single forward pass. Accepted tokens are kept; rejected tokens are resampled from the target model.

The key insight is that LLM inference is fundamentally memory-bandwidth-bound, not compute-bound. Modern GPUs have massive parallel compute capacity that sits idle during standard autoregressive generation because each token depends on the previous one. Speculative decoding exploits this idle compute by giving the target model multiple tokens to verify simultaneously, rather than generating them one at a time.

For AI engineers, speculative decoding is one of the most impactful inference optimizations available today. Unlike quantization or pruning, it provides speedups with mathematically guaranteed identical outputs — the final text is exactly what the target model would have produced on its own. It’s now a production-standard technique supported natively by vLLM, TensorRT-LLM, and other serving frameworks.

How It Works

The Memory-Bandwidth Bottleneck

To understand why speculative decoding works, you need to understand the inference bottleneck. During autoregressive generation, each token requires loading the model’s entire weight matrix from GPU memory (HBM) into the compute cores. For a 70B-parameter model in FP16, that’s ~140GB of memory reads per token. Even on an H100 GPU with 3.35 TB/s memory bandwidth, this takes ~42ms per token — and the GPU’s 990 TFLOPS of compute capacity is barely utilized during this time.

Speculative decoding doesn’t reduce the memory reads — instead, it makes each read count for more by verifying multiple tokens per target-model forward pass.

Key Concept: The Draft-Then-Verify Pattern

Speculative decoding pairs two models: a small, fast draft model (e.g., 1–7B parameters) that cheaply proposes K candidate tokens, and a large target model (e.g., 70B+ parameters) that verifies all K tokens in a single forward pass. Because the target model processes all candidates in parallel (similar to a prefill operation), the cost is roughly the same as generating just one token — but you potentially accept multiple tokens per step.

The Algorithm Step by Step

Here’s how one speculative decoding iteration works:

  1. Draft phase: The draft model autoregressively generates K tokens (typically K=3–8), producing both the tokens and their probability distributions q(x) at each position.
  2. Verify phase: The target model processes the entire sequence (prompt + all K draft tokens) in a single forward pass, computing its own probability distributions p(x) at each position.
  3. Accept/reject phase: For each draft token, from left to right, apply the rejection sampling criterion to decide whether to accept or reject it.
  4. Resample if needed: At the first rejected position, sample a new token from an adjusted distribution derived from the target model. All tokens after the rejection point are discarded.
  5. Guaranteed progress: Even if all K draft tokens are rejected, you still get at least one new token (the resampled one from the target model), so you never do worse than standard autoregressive decoding.

The Rejection Sampling Criterion

The acceptance logic is the mathematical core that guarantees output equivalence with the target model:

# For each draft token x_i at position i:
# q(x_i) = draft model's probability for token x_i
# p(x_i) = target model's probability for token x_i

# Accept with probability min(1, p(x_i) / q(x_i))
r = random.uniform(0, 1)
if r < min(1.0, p(x_i) / q(x_i)):
    accept(x_i)  # Token matches target model's distribution
else:
    # Reject and resample from adjusted distribution:
    # p_adjusted(x) = max(0, p(x) - q(x)) / sum(max(0, p(x') - q(x')))
    new_token = sample(adjusted_distribution)
    break  # Stop checking remaining draft tokens

This criterion has an elegant property: if the target model assigns equal or higher probability to a draft token than the draft model did, the token is always accepted. Tokens are only probabilistically rejected when the draft model was more confident than the target model, with the rejection probability proportional to the confidence gap.

Key Concept: Lossless Guarantee

The rejection sampling scheme is mathematically proven to produce output distributions identical to sampling directly from the target model. This is not an approximation — the final output is exactly the same distribution as standard autoregressive decoding from the target model. The speedup comes purely from batching the verification work, not from any quality tradeoff.

Acceptance Rate: The Key Metric

The effectiveness of speculative decoding depends on the acceptance rate (α) — the fraction of draft tokens that the target model accepts. Higher acceptance rates mean more tokens are produced per verification step:

The expected number of tokens generated per verification step is 1/(1-α) for geometric acceptance. With α=0.8, you get ~5 tokens per step on average.

Choosing a Draft Model

The draft model choice critically affects performance:

Practical Applications

Production Deployment

Speculative decoding has matured from a research technique to a production standard:

When Speculative Decoding Excels

Limitations and Considerations

Key Takeaways

Further Reading