Speculative Decoding: Fast LLM Inference Without Quality Loss › The Verification Procedure
Language AI HandbookAll chapters Speculative Decoding: Fast LLM Inference Without Quality Loss › The Verification ProcedureOne section · Sections in this chapter6 / 14 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
The verification procedure is the mathematical heart of speculative decoding. It determines which draft tokens to accept and how to generate corrections when tokens are rejected. We can construct an acceptance criterion that exactly preserves the target model's output distribution while maximizing the number of accepted tokens. This is not an approximation or heuristic: it is a mathematically guaranteed property that makes speculative decoding a lossless acceleration technique.
The mathematical result that makes speculative decoding work is called the acceptance-rejection sampling theorem. In classical statistics, acceptance-rejection sampling is a technique for drawing samples from a target distribution when you can only sample easily from a proposal distribution . You draw a sample from , then accept it with probability proportional to . The accepted samples are guaranteed to be distributed according to . Speculative decoding applies this classical idea to language model token generation, with the draft model as the proposal distribution and the target model as the target distribution.
Acceptance Criterion
For each draft token, we compare the draft model's probability with the target model's probability . We want to accept as many draft tokens as possible while ensuring the accepted tokens are distributed according to , not . The acceptance probability that achieves this is:
where:
- : the probability of accepting candidate token as a valid sample from the target distribution
- : the probability assigned to token by the target model given the current context
- : the probability assigned to token by the draft model given the same context
- The minimum ensures the acceptance probability never exceeds 1, since probabilities must be at most certain
This formula has an elegant interpretation. When (the target model likes this token at least as much as the draft model), we always accept. This makes sense: the target model considers this token at least as likely as the draft model proposed, so accepting it only makes our output distribution more aligned with the target. When (the draft model overestimated this token's likelihood), we accept with probability equal to how much it overestimated. The more the draft model overestimated a token, the lower our acceptance probability, preventing us from biasing our output toward tokens the draft model unfairly favored.
def compute_acceptance_probability(p_target, q_draft):
"""
Compute acceptance probability for a draft token.
p_target: probability under target model
q_draft: probability under draft model
"""
return min(1.0, p_target / q_draft)
# Example: target and draft agree closely
p_target_agree = 0.15
q_draft_agree = 0.18
accept_prob_agree = compute_acceptance_probability(
p_target_agree, q_draft_agree
)
# Example: target strongly prefers this token
p_target_prefer = 0.25
q_draft_prefer = 0.10
accept_prob_prefer = compute_acceptance_probability(
p_target_prefer, q_draft_prefer
)
# Example: draft overestimates significantly
p_target_over = 0.05
q_draft_over = 0.20
accept_prob_over = compute_acceptance_probability(p_target_over, q_draft_over)Acceptance probabilities for different agreement levels: Scenario p(target) q(draft) Accept prob ------------------------------------------------------------ Close agreement 0.15 0.18 0.83 Target prefers more 0.25 0.10 1.00 Draft overestimates 0.05 0.20 0.25
The results show that we accept with certainty when the target model prefers a token more than the draft model does (probability 1.00), but only probabilistically when the draft model is overconfident. The "Draft overestimates" scenario, where the draft gives 20% probability but the target gives only 5%, yields a 25% acceptance probability. This means the draft model proposed this token 4x more often than the target would have wanted, so we discard it 75% of the time to prevent it from appearing 4x too frequently in our output.
Rejection and Correction
When a draft token is rejected, we need to sample a correction token. Simply sampling from the target model's distribution at that position would bias the output: we would undersample tokens that were already accepted under the acceptance criterion and oversample tokens that were never drafted. The correction distribution must account precisely for the tokens that have already been "covered" by the acceptance procedure.
To understand why, think about what the acceptance step has already done. Imagine the target distribution assigns 30% probability to token A and 20% to token B. The draft distribution assigns 10% to A and 25% to B. In the acceptance step, token A (if drafted) would be accepted with probability 1.0 (since ), and token B would be accepted with probability . So token A is well-covered, but token B is slightly over-proposed. If we reject and then sample from directly, we would add another 30% chance of token A on top of the already-accepted A, distorting the distribution.
The correction distribution adjusts for the tokens that would have been accepted through drafting, sampling only the "residual" probability mass:
where:
- : the adjusted probability of sampling token as a correction after a rejection
- : the difference between target and draft probabilities for token
- : selects only tokens where the target assigns more probability than the draft (the "under-sampled" tokens)
- : the normalization constant ensuring the correction distribution sums to 1
This distribution has a clear interpretation. It samples only from tokens where the target model assigns more probability than the draft model proposed. These are precisely the tokens that the draft model under-represented. By sampling from this residual distribution, we fill in the probability mass that was missed by the draft model's proposal. This keeps the combined output of accepted drafts and corrections matches the target distribution exactly. The formal proof of this property shows that the marginal distribution of each generated token equals , even after the acceptance-rejection process.
import numpy as np
def compute_correction_distribution(p_target, q_draft, vocab_size):
"""
Compute the correction distribution for rejected tokens.
p_target: array of target model probabilities over vocabulary
q_draft: array of draft model probabilities over vocabulary
"""
# Compute max(0, p - q) for each token
residual = np.maximum(0, p_target - q_draft)
# Normalize to get valid distribution
total = np.sum(residual)
if total > 0:
correction_dist = residual / total
else:
# Fallback: use target distribution (happens when q >= p everywhere)
correction_dist = p_target
return correction_dist
# Create example distributions over small vocabulary
vocab_size = 10
# Target model distribution
p_target_dist = np.array(
[0.3, 0.2, 0.15, 0.1, 0.08, 0.07, 0.05, 0.03, 0.01, 0.01]
)
# Draft model distribution (slightly different)
q_draft_dist = np.array(
[0.25, 0.25, 0.12, 0.12, 0.08, 0.06, 0.05, 0.04, 0.02, 0.01]
)
correction_dist = compute_correction_distribution(
p_target_dist, q_draft_dist, vocab_size
)Distribution comparison and correction: Token p(target) q(draft) p - q Correction -------------------------------------------------------- 0 0.300 0.250 0.050 0.556 1 0.200 0.250 -0.050 0.000 2 0.150 0.120 0.030 0.333 3 0.100 0.120 -0.020 0.000 4 0.080 0.080 0.000 0.000 5 0.070 0.060 0.010 0.111 6 0.050 0.050 0.000 0.000 7 0.030 0.040 -0.010 0.000 8 0.010 0.020 -0.010 0.000 9 0.010 0.010 0.000 0.000

Notice how the correction distribution emphasizes token 0 and token 2, where the target model assigns more probability than the draft. Token 1 and token 3 receive zero correction probability because the draft model already over-sampled them. By combining accepted draft tokens with correction samples, we ensure the overall distribution perfectly matches what the target model would have produced through standard autoregressive generation. This is not approximately right: it is mathematically exact.
Sequential Acceptance
During verification, we process draft tokens sequentially and stop at the first rejection. If draft token 3 is rejected, we do not verify tokens 4 and beyond. This is because the correction at position 3 changes the context, invalidating the draft model's predictions for subsequent positions. The draft model generated tokens 4 and beyond assuming token 3 would be accepted as-is. Once we substitute a correction token, those subsequent predictions become irrelevant because they were conditioned on a different context.
This sequential processing means the number of accepted tokens follows a geometric-like distribution. With acceptance rate per token, the expected total number of tokens generated per round combines the always-present correction token with the expected accepted drafts:
where:
- : the expected number of tokens produced per round (drafts plus correction)
- : the correction token, which is always generated regardless of how many drafts are accepted
- : the expected number of accepted draft tokens, summed over each position
- : the probability of accepting a single draft token (the acceptance rate)
- : the number of draft tokens attempted per round
This formula sums the always-present correction token with the geometric series of accepted drafts. The geometric series arises because each subsequent draft token can only be accepted if all previous draft tokens were also accepted. The probability of accepting the first two drafts is , the first three is , and so on. This cumulative structure explains why acceptance rate has such a dramatic effect on speedup: small improvements in compound across multiple positions. Moving from to with increases expected tokens from 3.08 to 3.93, a 28% improvement in throughput from a 14% improvement in acceptance rate.