The main question of this lecture: remember the “impossible” \(2P/\beta\)
ceiling from Lecture 1? How do we buy several accepted tokens for one read of the
weights, and why is it not cheating?
The “Impossible” Ceiling, Revisited
We ended Lecture 1 with a hard floor. One decode step must read all \(P\) weights once, so a
single-request step cannot take less than
\[ T_{step} \ge \frac{2P}{\beta} \approx \frac{140\ \text{GB}}{3.35\ \text{TB/s}} \approx 41.8\ \text{ms} \]
for a 70B model in FP16 on an H100. That is a ceiling of about 24 tok/s, at \(I \approx 1\) FLOP/byte,
300× below the ridge. Everything since (paging, batching, disaggregation, parallelism,
kernel fusion) has lived above that line, trying to amortize the weight read across more
requests or more work. None of it touched the wall itself.
☺
TA says: and then production 2026 happened. Kimi K3 decoding on GB300,
batch 1: 111–118 tok/s plain, which is already 86–92% of its (much lower, MoE) roofline,
and 331–370 tok/s with speculation on. Remember the lever list from Lecture 1: shrink
the bytes, buy more bandwidth, or produce several tokens per weight read. This lecture is
the third lever. The wall was only ever a wall for sequential one-token-per-read decode.
Today we walk straight through it, legally.
Main idea:
Verification is free in a memory-bound decode: one read of the weights can score many
candidate tokens in one parallel pass. So let something cheapdraft \(k\) candidates, let the target modelverify
them all at once, accept the longest prefix that matches its own distribution, and roll
the KV back over the rest. Every emitted token still comes from the target's distributions. That
is why it is not cheating, and this lecture proves it.
Why Verification Is (Exactly) Free
Here is the one fact the whole module rests on. A forward pass over \(k\) tokens reads each
weight matrix once and does \(k\) times the arithmetic: verification converts a GEMV into a
GEMM with \(M = k\) rows for the same memory traffic. As long as the \(k\times\) extra compute fits
inside the idle compute budget (recall that the compute utilization of single-request decode is
\(\beta/\pi \approx 1/295 \approx 0.34\%\)), the step time does not move. Formally:
\[ T_{verify}(k) = \max\!\Big( \underbrace{\frac{2P + B \cdot kv}{\beta \cdot MBU}}_{\text{memory: unchanged}},\;
\underbrace{\frac{k \cdot 2P \cdot B}{\pi \cdot MFU}}_{\text{compute: grows linearly}} \Big)
\quad\Longrightarrow\quad
k \le \frac{\pi}{\beta}\cdot\frac{MFU}{MBU}\cdot\frac{2P + B \cdot kv}{2P\,B}. \]
At \(B = 1\) and \(kv \cdot L \ll 2P\) (70B at \(L\) = 4K: the KV read is \(320\ \text{KB} \times
4096 \approx 1.3\) GB vs 140 GB of weights), the last factor is \(\approx 1\), and the ceiling
collapses to \(k^* \approx \text{ridge} \times MFU/MBU\).
Worked example (do it with me):
70B on H100, \(B=1\), \(\pi = 990\) TFLOPS BF16, \(\beta = 3.35\) TB/s, \(2P = 1.4\times 10^{11}\)
FLOPs/token.
Compute time for \(k\) tokens at a realistic \(MFU = 0.5\) for small GEMMs:
\(k \cdot 1.4\times 10^{11} / (0.5 \times 9.9\times 10^{14}) = 0.283\,k\) ms.
Sweep it: \(k{=}1 \Rightarrow 0.28\) ms of compute (step ratio 1.00×); \(k{=}8 \Rightarrow
2.3\) ms (1.00×); \(k{=}64 \Rightarrow 18.1\) ms (1.00×); \(k{=}148 \Rightarrow 41.9\)
ms, the break-even; \(k{=}300 \Rightarrow 84.9\) ms, now compute-bound and 2.03×
slower. Under ideal \(MFU = MBU = 1\), \(k^* \approx 295\), exactly the ridge point; even
at pessimistic \(MFU = 0.3\), \(k^* \approx 89\). Practical speculative decoding uses
\(k \in [1, 16]\), one to two orders of magnitude below the ceiling. Verification is not
approximately free at realistic \(k\); it is exactly free.
Engineering takeaway:
the free-verification zone ends where the product \(B \cdot (k+1)\) approaches the ridge.
The threshold is \(B \cdot (k+1) \gtrsim \pi\, MFU / (\beta\, MBU) \approx 150\text{–}300\) tokens
per step. At \(k{+}1 = 5\), that is only \(B^* \approx 30\text{–}60\) concurrent requests, well
inside production batch sizes. The same math that makes speculation free at \(B=1\) makes it
expensive at serving scale. Sleep with that thought; we meet it again below.
The Framework: Draft → Verify → Accept
So: if verifying \(k\) tokens costs one decode step, can we find tokens worth verifying? Each
speculative round goes:
Draft. A cheap mechanism proposes \(k\) candidate
continuations \(\hat{x}_{t+1}, \dots, \hat{x}_{t+k}\), as a chain or a candidate tree.
Verify. One forward pass of the target model yields its
next-token distributions at all \(k\) positions simultaneously,
\(p(\cdot \mid x_{\le t}), p(\cdot \mid x_{\le t}, \hat{x}_{t+1}), \dots\) This is the same
causal-mask trick as prefill, legal by the cache-legality induction of Lecture 1.
Accept. Position by position, accept a candidate if it passes a test against the
target distribution; truncate at the first failure. The verify pass at the failure position still
yields the target's own distribution there, so every round emits at least 1 and
at most \(k+1\) tokens. The “+1” is the bonus token computed for free by the
same pass.
How to: follow one round left to right, top to bottom. Dashed boxes are guesses;
green is what the target itself would have said; the amber bonus is why even a total rejection
costs nothing in tokens: the verify pass always leaves one freshly computed target distribution
behind.?The draft is garbage and proposes four tokens the target hates. How many tokens does the
round emit? Zero? Think for a minute before you open this; the answer is the key to why
speculation can never make you slower in token count.
Possible answer
One. Always. Truncation happens at the first rejection, but the verify pass computed
the target's own distribution at that position, so you emit the target's correct token
there. A round commits \(r \in \{1, \dots, k{+}1\}\) tokens, never zero. The worst case is not
lost work; it is the \(c_{draft}\) time you paid for the useless draft, plus a recoverable KV
write.
The whole thing now rests on two questions: is the acceptance test exact, and how many
tokens does a round yield on average? The next two sections answer them in order.
Not Cheating: Speculative Decoding Is Exact
This is the mathematical heart of the lecture, and the property that sets speculative decoding
apart from every approximate acceleration (quantization, distillation, pruning): the output
distribution is strictly identical to decoding with the target model alone. We prove it
twice, because greedy and sampling need different tests.
Greedy: induction over rounds
Target greedy decoding is a deterministic function \(g(\text{prefix}) = \arg\max_x p(x \mid
\text{prefix})\). A round drafts \(k\) tokens and the verify pass hands us
\(g_i = g(\text{prefix}, \hat{x}_1, \dots, \hat{x}_{i-1})\) for all \(i = 1..k{+}1\) at once. The
rule: accept \(\hat{x}_i\) iff \(\hat{x}_i = g_i\); stop at the first mismatch \(j\) and emit
\(g_j\); if all \(k\) match, also emit the bonus \(g_{k+1}\).
Claim. The emitted sequence equals the target-greedy sequence exactly. Proof
(sketch). Invariant: at the start of every round, the committed prefix equals the target-greedy
prefix. Base: the shared prompt. Step: for every \(i < j\), the accepted \(\hat{x}_i\) equals
\(g(\text{committed prefix}, \hat{x}_{<i})\), which by the invariant is the next greedy
token; at position \(j\) we emit \(g_j\), the target's greedy token given the (now correct) prefix.
Invariant restored, and \(1 \le r \le k{+}1\). ∎ Note the structural reason even total rejection is
free: the verify forward wastes nothing.
Sampling: a rejection test that repairs the gap
Greedy comparison fails when we sample \(x \sim p\). The correct test, due to Leviathan,
Kalman, and Matias, and independently Chen et al. (2023), is rejection sampling against the draft
distribution. The draft drew \(x \sim q\); both \(p\) (from the verify pass) and \(q\) (from the
draft) are known exactly:
Accept \(x\) with probability \(\min\!\big(1,\; p(x)/q(x)\big)\).
On rejection, resample from the residual and truncate the round:
\[ \tilde{p}(x) = \frac{\max\big(0,\; p(x) - q(x)\big)}{Z}, \qquad
Z = \sum_{x'} \max\big(0,\; p(x') - q(x')\big). \]
Two one-line identities make it exact. Watch. First, the normalizer is the rejection
probability:
\[ Z = 1 - \sum_x \min(p(x), q(x)) = \tfrac{1}{2}\lVert p - q \rVert_1 = \Pr[\text{reject}], \]
because \(\sum_x q(x)\min(1, p(x)/q(x)) = \sum_x \min(p(x), q(x))\), and \(\sum \max(0, p-q) =
\sum p - \sum\min(p,q)\) pointwise (the two positive parts of \(p - q\) have equal mass, hence the
\(\tfrac12\lVert p - q\rVert_1\) form). Second, the emitted token's law:
\[ \Pr[\text{final} = x]
= \underbrace{q(x)\min\!\big(1,\; p(x)/q(x)\big)}_{\text{accepted draft}}
+ \underbrace{Z\,\tilde{p}(x)}_{\text{rejection} \times \text{residual}}
= \min(p, q) + \max(0, p - q) = p(x). \]
Worked example (one position, three tokens, real numbers):
\(p = (0.5, 0.3, 0.2)\), \(q = (0.4, 0.4, 0.2)\).
Per-token acceptance \(\min(1, p/q)\): tokens 1..3 get \((1.0,\ 0.75,\ 1.0)\).
Read the story, not just the arithmetic: the draft overproposes token 2 (0.4 vs 0.3), so
we reject it 25% of the time; it underproposes token 1, and residual resampling repairs
exactly that deficit.
Sanity checks (the two limits). If \(q = p\): acceptance is 1 everywhere, \(Z = 0\), never
reject: pure speedup. If \(q\) and \(p\) have disjoint support: acceptance is 0 everywhere,
\(Z = 1\), the residual \(\tilde{p} = p\), and every round degenerates to sampling from the target
directly. Still correct, just no gain. The scheme interpolates between “free tokens”
and “ordinary decode” as a function of draft quality \(\tfrac12\lVert p -
q\rVert_1\). Lifting one position to whole sequences is an induction over committed positions:
the invariant (the committed prefix has exactly the target's law) makes the chain-rule product
telescope to the target's sequence distribution.
Note: temperature and top-\(p\) compose cleanly: apply the warper to
both \(p\) and \(q\) before the test, and the identical algebra goes through.
Engineering takeaway:
losslessness is a theorem about distributions, not floating-point bit-exactness: the
verify forward runs at a different GEMM \(M\) than plain decode, so kernels may differ in the last
ulp (Lecture-7 deterministic-kernel discipline if you need reproducibility). And the acceptance
test costs one comparison per position, so never skip it “because acceptance is
high”: an untested draft silently changes the output distribution.
The Speedup Law: τ Over (1 + cdraft)
Exactness settled. Now, how fast is it? Model acceptance as i.i.d. per position with probability
\(\alpha\) (a first-order approximation; real acceptance correlates through the prefix, and we will
honour that later). A round with \(k\) draft positions accepts a geometric run up to the first
rejection, plus the bonus token:
\[ \tau = \sum_{i=0}^{k} \alpha^i = \frac{1 - \alpha^{k+1}}{1 - \alpha}
\quad \xrightarrow[k \to \infty]{} \quad \frac{1}{1 - \alpha}. \]
The asymptote is the field's fundamental tension: for \(\alpha = 0.85\) it caps at 6.67, and
no chain length escapes it. Raising \(k\) buys less and less, while (for autoregressive
drafters) costing more and more.
Per round, time is \(T_{tgt} \cdot (1 + c_{draft})\): the target step plus the draft cost in
units of a target step, verification free inside the ceiling. Tokens per round: \(\tau\). Baseline:
\(\tau\) tokens cost \(\tau\,T_{tgt}\). Hence the course's canonical formula:
\[ \text{speedup} \approx \frac{\tau}{1 + c_{draft}}, \]
with exactly two levers that organize everything that follows: raise \(\tau\)
(draft quality and alignment) and lower \(c_{draft}\) (draft efficiency, especially its scaling in
\(k\)).
Worked example (three tables an engineer reads daily):τ(k; α) from the geometric sum:
\(\alpha\)
k=1
k=2
k=3
k=4
k=6
k=8
k→∞
0.70
1.700
2.190
2.533
2.773
3.059
3.199
3.33
0.85
1.850
2.573
3.187
3.709
4.529
5.123
6.67
0.95
1.950
2.853
3.710
4.524
6.033
7.395
20.0
Check one cell yourself: MTP at \(\alpha = 0.85,\ k = 1\) gives \(\tau = 1 + 0.85 = 1.85\) ✓,
matching DeepSeek-V3's reported 85–90% second-token acceptance, i.e. \(\tau \in [1.85, 1.90]\).
Optimal \(k\) under an autoregressive draft, \(c_{draft} = k\,c_1\), maximizing
\(\tau(k)/(1 + k c_1)\) numerically over \(k \in [1, 40]\):
\(\alpha\)
\(c_1 = 0.02\)
\(c_1 = 0.05\)
\(c_1 = 0.10\)
0.70
k* = 8, 2.76×
k* = 6, 2.35×
k* = 4, 1.98×
0.85
k* = 14, 4.75×
k* = 10, 3.70×
k* = 7, 2.85×
0.95
k* = 31, 9.95×
k* = 21, 6.60×
k* = 15, 4.48×
Two readings: (i) the optimum is an interior point, because \(\tau\)'s concave growth
eventually loses to \(c_{draft}\)'s linear growth; (ii) it shifts right as acceptance improves and left as
the draft gets expensive. This is why DeepSeek's production choice \(k = 1\) for MTP is rational
(per-step draft cost is not negligible and acceptance is already high), while EAGLE deployments
tune \(k \approx 4\text{–}8\).
Parallel draft (DFlash-style), \(c_{draft} \approx 0.15\) independent of \(k\):
\(\alpha\)
k=4
k=8
k=12
k=16
0.85
3.22×
4.45×
5.10×
5.43×
0.95
3.93×
6.43×
8.46×
10.12×
With seriality removed, the speedup keeps climbing with block length toward the \(\tau\)-asymptote
\(\div 1.15\). The ceiling on \(\tau\) itself becomes the binding constraint.
How to: pick \(k\) on the x-axis and read both curves. Green is how many tokens a
round yields: concave, doomed to saturate. Blue is the actual speedup once the draft costs
\(0.05k\) per round: it peaks at an interior point and declines. The amber marker is the
whole design problem: k* lives between the two shapes, and it moves with \(\alpha\), \(c_1\), and
(as we will see) the current batch size.
Draft Trees: Spend the Budget Where Uncertainty Is
A chain has a concrete flaw: it commits the draft budget to one guess per position. But
language is not equally predictable everywhere. When the target distribution is peaked, one
candidate suffices; when it is spread over a few plausible continuations, no single one is likely
to match. A tree draft keeps several candidates per position and lets
verification pick the longest passing branch.
How to: the root is the last committed token; each level is one position of the
future; every node gets its own target distribution in one verify pass under a tree-shaped
causal mask. The longest green path commits; dashed grey branches existed only to be scored, then
are discarded.
The math generalizes the chain: writing \(a(v)\) for the acceptance probability of node \(v\)
given its parent is accepted, at most one node per level can continue the committed sequence, so
the level events are disjoint and
\[ \mathbb{E}[\tau_{tree}] - 1 = \sum_{v \ne root} \prod_{u \in path(root, v)} a(u)
\xrightarrow{\text{i.i.d. } \alpha} \sum_{v \ne root} \alpha^{\,\text{depth}(v)}. \]
Note the honesty constraint: sibling acceptance events are (nearly) disjoint, so children of a node
sum to \(\lesssim 1\). A branching node helps only to the extent its children partition
probability mass. Trees pay precisely when the distribution is entropic.
Worked example (same budget of 4 draft tokens, two architectures):Chain at \(\alpha = 0.55\): \(\mathbb{E} = \sum_{i=1}^{4} 0.55^i = 1.11\).
Tree with two children at depth 1 covering 0.9 of the mass (\(\gamma_1 = 0.9\)) and one
child each at depth 2 with \(\gamma_2 = 0.55\):
\(\mathbb{E} = \gamma_1 + \gamma_1\gamma_2 = 0.9 + 0.495 = 1.40\).
The tree wins, because depth-1 uncertainty was the bottleneck. On a peaked
distribution the same budget in a chain wins; it depends on where entropy sits.
And the cost side argues back. A tree of \(n\) nodes is verified in one forward over \(n{+}1\)
tokens, so the ceiling binds when \(B \cdot (n{+}1) \approx 150\text{–}300\) tokens per step. At
\(B = 32\) that is a budget of 5–9 tokens per request: a chain of \(k \le 4\text{–}8\), or only
a small tree. Production systems choose chain vs small tree as a function of current load,
and EAGLE-2's confidence-based dynamic trees (expand branches exactly where the draft itself is
uncertain) are as much a load-management feature as an accuracy feature.
Four Generations of Drafts: the Road to Alignment
The speedup law said \(\tau\) and \(c_{draft}\) are everything; the field's history is a
four-generation push on both axes at once. Walk it the way the flaws dictate.
Gen 1: an independent small model (a 1B of the same family drafts for 70B). The easiest
thing you can do... and you probably can guess the flaws: a second model to train and
deploy, \(k\) serial autoregressive draft steps, and a softmax geometry never aligned with the
target's. Poor \(\tau\), real \(c_{draft}\). Largely obsolete.
Gen 2: Medusa deletes the second model: \(k\) lightweight heads sit on the target's last
hidden state, head \(i\) predicting token \(t{+}i\). Extremely cheap. But now the flaw is
coordination: all heads condition on the same hidden state and predict independently, so the
joint plausibility of the \(k\)-gram suffers. Alignment, not speed, is the bottleneck.
Gen 3: EAGLE fixes the conditioning: a single small transformer layer runs
autoregressively over the target's features: (last-layer hidden state, embedding of last
token) in, next feature out, the target's own LM head on top. The move from token-level to
feature-level autoregression is the single biggest alignment jump: the hidden state is a sufficient
statistic of the prefix; a sampled token is a lossy projection of it. One small-layer step per
candidate, dynamic trees (EAGLE-2), multi-layer feature fusion (EAGLE-3). This is the widely
deployed baseline in vLLM and SGLang.
Gen 4: MTP (DeepSeek-V3) asks: why should the draft be learned outside the
default?
Training: MTP module \(i\) takes the current feature plus the next token's embedding,
runs one transformer layer, predicts the second future token. So every position supervises two (or
more) targets, a denser signal the V3 report credits as a quality gain in its own right.
Inference: the same module is structurally isomorphic to an EAGLE draft head, so it is
directly the speculative draft: 85–90% second-token acceptance,
\(\tau \in [1.85, 1.90]\) at \(k = 1\), one small layer per extra token of \(c_{draft}\), zero
separate training or deployment, because the weights ship inside the checkpoint. Speculation stops being
an optimization the deployer performs and becomes a capability built into the model;
DeepSeek enables it by default, deliberately conservatively at \(k = 1\).
DFlash: deleting the draft's for-loop
Every draft so far is autoregressive: \(k\) candidates cost \(k\) sequential draft forwards, so
\(c_{draft}\) grows linearly in \(k\) and caps how far \(\tau\) can be pushed (the interior optima
above). DFlash attacks the seriality itself: the draft is a lightweight block-diffusion model
that processes one anchor token plus several mask tokens and fills in the whole block of
typically 8–16 candidates in parallel, the way masked-diffusion LMs denoise a block at once.
Conditioning on the target's multi-layer features keeps alignment high; outputs are projected
through the target's LM head, as in EAGLE/MTP. Reported (DFlash paper, ICML 2026): lossless
speedups of 6× or more across models and tasks, up to 2.5× over EAGLE-3; NVIDIA's
Blackwell evaluation reports up to 15× throughput at equal interactivity on gpt-oss-120b vs
EAGLE-3; integrations in SGLang, vLLM, TensorRT-LLM; official draft checkpoints for mainstream
open-model families; a UCSD team completed a TPU implementation.
Important: losslessness survives untouched. The diffusion parallelization
is confined to proposing candidates; any shortfall in draft quality only lowers
\(\alpha\), and verify/accept backstops correctness exactly as before. Parallel drafting trades
acceptance probability for draft latency; it can never trade correctness. With
\(c_{draft}\) decoupled from \(k\), the block length becomes a free variable and the ceiling
reverts to the \(\tau\)-asymptote \(1/(1-\alpha)\), now attacked through alignment rather than
draft latency. That is the precise sense in which DFlash “opens up the ceiling of
\(\tau\)”.
☺
TA says: the 2026 canonical deployment is DSpark, Kimi K3's
production drafter. It is the DFlash recipe made MLA-native: it conditions on the target's
compressed MLA latent rather than full per-head K/V, so the drafter never materializes
the cache the architecture was designed to eliminate. Measured on GB300 at batch 1:
111 → 331 tok/s at TP8 (2.98×), 118 → 370 tok/s at TP16 (3.14×); SGLang
reports 113 → 423 tok/s (3.74×). Run our consistency checks. (1) Against the
Lecture-1 floor: K3 activates ≈26 GB of weights per step, so
\(2P/\beta \approx 7.8\) ms, a ≈129 tok/s ceiling. Plain decode at 111–118 tok/s is already
86–92% of roofline, so speculation was the only remaining lever. (2) Against the
speedup law: reading it backwards, \(\tau = 4.73\) with a realized 3.14× implies
\(c_{draft} \approx \tau/\text{speedup} - 1 \approx 0.51\). So one diffusion pass plus round
overhead costs about half a target step, exactly the DFlash prediction. (3) Against the \(\tau\)
model: accepted tokens per round are 4.73 on coding workloads vs 2.61 on creative ones.
Solving \((1-\alpha^{k+1})/(1-\alpha) = 4.73\): at \(k = 4\), \(\alpha \approx 0.97\); at \(k =
8\), \(\alpha \approx 0.83\); in the large-block limit \(\alpha \to 1 - 1/\tau \approx 0.79\)
(creative: \(0.62\text{–}0.67\)). So the implied per-position acceptance moves ≈ 0.17 between task
mixes (it is not a property of the drafter!), and inside a diffusion block later candidates
condition on drafted, not committed, tokens. The i.i.d. formula is a calibration device,
not a mechanism model. Report \(\tau\) and \(c_{draft}\) both, or report neither.
Engineering takeaway:
choose the draft source by where your bottleneck sits in \(\tau/(1 + c_{draft})\). Checkpoint
ships MTP weights (DeepSeek-V3 family)? Enable it; the decision is made. No built-in
speculation? EAGLE-3 is the mature baseline. Single-stream latency dominates and you can host a
block-diffusion drafter? DFlash is the frontier. The obsolete option, self-hosting an independent
small model, survives only as the teaching example.
Speculation Meets the Rest of the System
Speculative decoding is not a kernel you bolt on; it changes the shape of decode
(rounds commit a random \(r \in \{1, \dots, k{+}1\}\) tokens), and every layer of Lectures
2–7 feels it. Walk the stack with me.
Batching: the gain inverts with load
Free verification presumes spare compute, and spare compute is a small-batch luxury. Small batch:
\(I \approx 1\), 300× under the ridge, speculation pays up to the full
\(\tau/(1+c_{draft})\). Large batch: verify multiplies tokens per step by \(k{+}1\), and once
\(B(k{+}1) \gtrsim 150\text{–}300\), decode crosses the ridge and goes compute-bound. The extra
verify FLOPs crowd out paying work they would otherwise have served \(k\times\) over.
Break-even batch (70B on H100, \(L\) = 4K, \(MFU = 0.5\), \(MBU = 1\)):
\(k\)
1
2
4
8
\(B^*\) (verify becomes compute-bound)
≈ 253
≈ 93
≈ 41
≈ 19
Production consequence: engines continuously estimate batch size and realized acceptance, and
adjust \(k\), or switch speculation off entirely when loaded. A static \(k\) is a
bug under drifting load. And one more hygiene rule: an acceptance number without a task
distribution is uninterpretable. DSpark's \(\tau\) moved from 4.73 to 2.61 between coding and
creative traffic.
KV management: reserve for the worst case, roll back the rest
Reservation. Before a round, the pager reserves worst-case capacity: \(k{+}1\) extra
tokens per request. 70B: \((k{+}1) \times 320\) KB, i.e. 1.6 MB at \(k = 4\) and 3.0 MB at
\(k = 8\), at most one extra 5.2 MB block under 16-token paging. DeepSeek-V3's MLA cache makes
this nearly free: \(k = 1\) reserves \(2 \times 34\) KB \(= 70\) KB per request.
Rollback. Rejected positions had KV written during verify; roll it back:
truncate the logical length, release blocks that become empty. Expected rollback per round is
\(k - (\tau - 1)\) tokens. At \(k = 4,\ \alpha = 0.85\): \(4 - 2.71 = 1.29\) tokens ≈ 423 KB.
Forgetting rollback does not corrupt output (rejected KV is never attended to after
truncation). It leaks blocks silently and shrinks your capacity.
Streaming: ITL becomes bimodal
A worked micro-example on our running 70B (MTP, \(k = 1\), \(\alpha = 0.85\), \(c_{draft} =
0.10\)): a round takes \(41.8 \times 1.1 = 46.0\) ms and emits 1 token with probability 0.15 or 2
tokens with probability 0.85. Per-token inter-arrival times are bimodal: ≈ 46 ms within a round,
≈ 0 ms for the second token of a 2-token round. Meanwhile the mean ITL drops to
\(46.0/1.85 = 24.9\) ms from 41.8 ms. Remember Lecture 1: TPOT is a mean, ITL is a distribution.
Mean-only monitoring misreads speculative systems twice: it hides the bursts from users watching
the stream, and the per-round granularity from capacity planners.
CUDA graphs and EP: multipliers everywhere
CUDA graphs: the draft forward (\(M = B\)) and the verify forward (\(M = B(k{+}1)\), plus
tree-mask variety) have different shapes, each needing its own captured buckets. The forward
inventory doubles, and a variable \(k\) multiplies it again. Practical systems capture a small fixed
set of \(k\) values, or run the (small) draft eagerly and capture only verify.
Expert parallelism: per-step all-to-all volume scales with tokens in the step, so
\[ V^{spec}_{a2a} = (k{+}1)\cdot V^{plain}_{a2a}. \]
For DeepSeek-V3 (top-8 of 256 routed experts, \(d_{model} = 7168\)): ≈ 57 KB FP8 dispatch plus
≈ 115 KB BF16 combine ≈ 172 KB per token, and MTP at \(k = 1\) doubles it. This lands on links
3.7–67× narrower than HBM (900 GB/s NVLink down to 50 GB/s IB, vs \(\beta = 3.35\)
TB/s). DeepSeek's production \(k = 1\) is exactly this three-way trade: high acceptance, minimal
verify compute, only 2× communication, instead of chasing \(\tau\)-gains paid in all-to-all
volume. (Larger expert batches partly self-correct GEMM efficiency; the network does not.)
Engineering takeaway:
budget speculation end-to-end, not per component. Compute three numbers at your operating
point: (i) \(B(k{+}1)\) vs the ≈ 150–300 tokens/step ridge budget (compute); (ii)
\((k{+}1)\times\) the Lecture-6 all-to-all volume vs link bandwidth (EP); (iii) \((k{+}1) \times
kv\) reservation vs free blocks (KV). The binding constraint is whichever you are closest to. It
moves with load, so re-evaluate continuously.
Rollback without a KV: speculation on linear attention
Everything above assumed per-token KV: rejected positions own identifiable entries, and rollback
is truncation. The 2026 hybrid models break that assumption structurally. Kimi K3's 69 KDA layers
carry a rolling recurrent state \(S \in \mathbb{R}^{128 \times 128}\) per head: 3.0 MiB BF16 per
layer, ≈ 0.2 GiB per request across all KDA layers, fixed regardless of context length. It is
updated in place by the gated delta rule:
\[ S_t = (I - \beta\, k k^\top)\, \mathrm{Diag}(\alpha)\, S_{t-1} + \beta\, k v^\top. \]
There is no per-token entry to free: processing \(k\) draft tokens overwrites the committed
state, diffusing the draft's contribution into every element of \(S\). Rejecting a suffix requires a
state rewind, not a pointer truncation. It is the same logical requirement as KV rollback,
with different mechanics and a different cost model.
Note (notation collision, inherited from the Kimi Linear paper): in the
delta rule, \(\alpha\) is a per-channel decay gate, \(\beta\) a write strength, \(k, v\) the
key/value vectors. These collide with this course's \(\alpha\) = acceptance rate, \(\beta\) = HBM
bandwidth, \(k\) = draft length. Context disambiguates; the equation above is KDA-internal.
The 2026 solution space:
Snapshot + replay (SGLang ReplaySSM). Snapshot the state at the round boundary; on
rejection, restore and replay the accepted raw inputs to advance \(S\). This is legal because \(S\)
is a deterministic function of the input sequence (cache legality, recurrence edition). ReplaySSM
further compresses the draft-window working state from 512 KB to 16 KB (≈ 32×), so
speculative scratch stops competing with the KV pool.
Feature-level drafting upstreamed (vLLM EAGLE3-on-KimiLinear, v0.28.0). The EAGLE-3
recipe on KimiLinear-family hybrids, the engine owning draft/verify state. Speculation on a
hybrid becomes a config flag, not a research project.
Trees without snapshots (TreeWY, Aug 2026). Restructures tree verification for
GDN-family linear layers so branches never materialize per-branch state snapshots, removing the
\(O(\text{tree size})\) snapshot cost that made trees unattractive on hybrids.
The MTP path on a hybrid (GLM-5.3-Flash). Zhipu's hybrid (34 KDA + 11 sparse-MLA
layers) ships 1 MTP layer in the checkpoint, which vLLM unfolds into 5 speculative tokens;
≈ 25–30 tok/s on 2× DGX Spark with MTP-5. Sanity check in Lecture-1 terms: 18B
activated params in FP8 ≈ 18 GB at ≈ 273 GB/s unified bandwidth ⇒ ≈ 15 tok/s plain ceiling; a
\(\tau \approx 2\) MTP-5 round lands at ≈ 30. That is the speedup law operating right at the
memory floor, exactly as the free-verification argument predicts.
Engineering takeaway:
on hybrid linear-attention models, budget rollback in state bytes and replay time, not KV
blocks: snapshot cost is (KDA state per request) × (snapshot frequency), about 0.2 GiB per
snapshot for K3, and replay cost is one recurrent pass over the accepted window. An engine that
treats recurrent state like paged KV (truncate-and-free) is silently wrong; one that snapshots per
round without compressing the draft window pays the full state size as a per-round tax.
Common Pitfalls
Watch out:
Reporting \(\tau\) without a task distribution. Code/math vs open-ended dialogue can
differ by multiples. Name the task mix, temperature, and draft configuration.
Leaving speculation on at large batch. Past \(B(k{+}1) \approx\) the ridge budget,
verify compute displaces paying work; the “speedup” becomes a throughput loss. You
need a load-aware kill switch, not just an on flag.
Forgetting KV rollback. Truncate rejected KV and release the blocks. Output stays
correct if you forget; the leak is silent, and capacity accounting drifts.
Static \(k\) under drifting load. The optimum moves with \(\alpha\), \(c_{draft}\),
and \(B\); fix \(k\) at an offline optimum and you are mis-tuned most of the day.
Believing “lossless” means bit-identical logits. Losslessness is
distributional; GEMM-shape nondeterminism can perturb the last ulp. Pair with deterministic
kernels if reproducibility is a hard requirement.
Counting the draft as free. \(c_{draft}\) includes extra kernel launches and host
round-trips; measured values are routinely 2–3× the FLOP estimate. Profile before
you project.
Research Thinking
How to: read the starting point; read the question and think, for a minute, a day, a
week... and only then open the answers. You are not supposed to reinvent several months of someone's
research; each of these was someone's paper. It's the habit of thinking that counts: you have
ideas, you try; if they don't work, you think again.
?Card 1, why this test? Starting point: the rule \(\min(1, p(x)/q(x))\) plus residual
\(\tilde{p} \propto \max(0, p-q)\) is provably exact. Question: could we save a resample
with a simpler rule: accept the draft token whenever the target likes it at least as much as the
draft did (\(p(x) \ge q(x)\)), reject otherwise? Compute what distribution that rule emits on
\(p = (0.5, 0.3, 0.2)\), \(q = (0.4, 0.4, 0.2)\). Think first.
Possible answer
Under the candidate rule: token 1 accepted (\(0.5 \ge 0.4\)), token 2 rejected (\(0.3 < 0.4\)),
token 3 accepted. So we emit token 1 with probability 0.4 (short of 0.5), token 3 with 0.2, and
with probability 0.4 we reject and must draw... from what? Any resampling that is not
\(\tilde{p} = (1,0,0)\) fails to restore the missing 0.1 of mass on token 1. The emitted law ≠
\(p\): simpler tests leak bias.
The recipe generalizes: any exact scheme must accept with probability at most
\(\min(1, p/q)\) pointwise and route the rejection mass exactly into \(\max(0, p-q)/Z\). That is
why the test has this shape: the min handles over-proposal, the residual repairs
under-proposal.
Existing solutions: this is exactly the Leviathan–Kalman–Matias /
Chen et al. (2023) construction. The two independent original speculative-decoding papers both
arrived at rejection sampling, because exactness is forced, not found.
?Card 2, “invent” dynamic tree drafting. Starting point: a chain wastes its
budget when entropy concentrates at one level (chain 1.11 vs tree 1.40 for the same 4 draft
tokens); a fat tree wastes it back on peaked distributions; and \(B \cdot (n{+}1)\) must fit the
≈ 150–300 token/step ridge budget. Question: what signal, available online and for
free from the draft itself, should decide where (and whether) to branch?
Possible answers
The draft's own confidence: where its distribution is peaked, commit a chain; where
it spreads, branch the top candidates. The draft distribution is computed anyway.
The current load: tree size \(n\) must shrink as \(B\) grows, so tree shape is partly
a scheduler decision, not only a modeling one.
Honesty check: sibling acceptance events are nearly disjoint, so branching helps only when
the children partition real probability mass; no tree can manufacture acceptance the target
doesn't have.
Existing attempts: EAGLE-2's confidence-based dynamic trees do the first;
production deployments switching chain ↔ small tree on batch telemetry do the second; and on
hybrid linear models, TreeWY removes the per-branch snapshot cost that made trees painful there.
The combination of the two signals is, as of 2026, still an active design space.
?Card 3, design the dynamic-\(k\) controller. Starting point: \(k^*\) is an interior point
of \(\tau(k)/(1 + c_{draft}(k))\), shifting with \(\alpha\) (workload), \(c_1\) (draft), and
\(B\) (load, via the ridge budget: \(B^* \approx 41\) at \(k=4\) on our 70B example). A static
\(k\) is a bug under drifting load. Question: sketch the control loop: what do you
measure, what do you recompute, how often, and where is the kill switch? Which signal saturates
first as \(B\) grows?
Possible answer
Measure online: realized acceptance \(\hat{\alpha}\) (rolling; per workload class if
you can tag it), realized draft latency \(\hat{c}_{draft}\) (measured is routinely 2–3×
the FLOP estimate), and current batch \(B\).
Recompute: \(k^* = \arg\max_k \tau(k; \hat\alpha)/(1 + \hat{c}_1 k)\), then clamp to
the per-request share of the ≈ 150–300 token/step budget; the compute term converts \(B\)
into a hard cap.
Kill switch: when \(B\) alone exhausts the budget, the clamp hits \(k = 0\):
speculation is throughput-negative; turn it off, not down.
Existing attempts: this is the production behavior the literature describes.
Engines adjust \(k\) from real-time acceptance and batch telemetry or disable speculation when
loaded; DeepSeek's fixed \(k = 1\) is the conservative limit of the same policy at very high
acceptance. Your Lab 8 curve (speedup peaking at small \(B\) and crossing 1.0 where the intensity
argument predicts) is the measurement version of this card.
?Card 4, roll back what you cannot truncate. Starting point: paged KV admits rollback by
truncation; a rolling recurrent state
\(S_t = (I - \beta kk^\top)\,\mathrm{Diag}(\alpha)\,S_{t-1} + \beta kv^\top\) admits none, because
the draft's contribution diffuses into every element of \(S\). Question: enumerate the
logically possible rollback mechanisms for such a state, price each in state bytes and replay
time, and say what makes tree drafting specially painful here.
Possible answers
Snapshot at the round boundary + replay the accepted suffix. Cost: one state copy
(≈ 0.2 GiB/request for K3) per round, plus a recurrent pass over the accepted window. Fully
general; legal because \(S\) is a deterministic function of the inputs.
Compress the draft window so the per-round tax shrinks: ReplaySSM's 512 KB → 16
KB working state.
Restructure to avoid snapshots. This is needed most for trees, where a naive design
pays \(O(\text{tree size})\) snapshots.
Existing attempts, all 2026: SGLang ReplaySSM (snapshot+replay with the
32× window compression), TreeWY (snapshot-free tree verification for GDN-family linear
layers), vLLM EAGLE3-on-KimiLinear (engine-owned hybrid draft/verify state), GLM-5.3-Flash's
1-MTP-layer checkpoint unfolded to MTP-5. Keep the lecture point: on hybrids, rollback is budgeted
in state bytes × frequency, and an engine that treats recurrent state like paged KV is
silently wrong.
Have Fun! Be the Verifier
Enough theory. Now you run some rounds. Set an acceptance probability \(\alpha\), a draft
length \(k\), and a draft cost \(c_1\) per token, watch the theoretical numbers, then press the
button to simulate real rounds: green bars are accepted draft tokens, the amber ★ is the bonus,
red ✗ are the aborted tail. Can you make the empirical speedup beat theory? (It happens; small
samples are generous.)
Playground physics: τ is the geometric sum \(\sum_{i=0}^{k}\alpha^i\); the round
simulator samples the geometric run honestly, redundancy and all.
Seminar & Homework
Take Lab 8: Speculative Decoding from the hands-on pack. One GPU, three server configs:
baseline (no speculation), prompt-lookup n-gram
(--speculative-config '{"method":"ngram","num_speculative_tokens":5,"prompt_lookup_max":4}'),
and an EAGLE head
(--speculative-config '{"model":"<eagle-head-repo>","num_speculative_tokens":5}';
SGLang equivalent: --speculative-algorithm EAGLE --speculative-draft-model-path ...
--speculative-num-steps 5 --speculative-eagle-topk 4 --speculative-num-draft-tokens 8). Two
datasets: code completion (near-deterministic boilerplate) and open-domain chat; fix
ignore_eos, 256 outputs, seed 0.
Measure throughput/TPOT at \(B \in \{1, 8, 32, 64\}\) for all three configs; read
acceptance stats from engine logs and compute your measured \(\tau\).
Overlay the canonical law: e.g. \(\tau = 2.5,\ c_{draft} = 0.1 \Rightarrow
2.27\times\); \(\tau = 3.5 \Rightarrow 3.18\times\); a weak draft (\(\tau = 2.0,\ c_{draft} = 0.3\))
only 1.54×. Expect code ≫ chat in \(\tau\), and map the gap to task entropy.
Find the inversion: effective intensity
\(I_{spec} = \frac{2P\,B(k{+}1)}{2P + B L\, kv}\) reaches 104 FLOP/byte at \(B=32, k=4\) and 204
at \(B=128\) (\(L = 2048\)), closing on ridge 295, where speculative tokens stop being free. Your
speedup curve should peak at small \(B\) and cross 1.0.
Answer the analysis questions: back out \(c_{draft}\) from measured \(\tau\) and
speedup: does it match the draft's standalone step time? Why does \(\tau\), not draft speed,
dominate on code? Where does your curve invert, and does the intensity argument predict it? Write
the dynamic-\(k\) rule; which signal saturates first? Does ITL P99 show the verify-burst
spikes?
Lab pitfalls to self-audit: benchmarking on unpredictable prompts and crediting the engine;
comparing spec-on vs spec-off across engines and calling it an engine comparison; ignoring
the draft model's VRAM (it eats cache capacity); and reporting a \(B = 1\) speedup as a serving
result. In the seminar, present your τ-table next to the theory table and defend one dynamic-\(k\)
rule on your own telemetry.
Summary
One parallel verify pass reads the weights once for \(k\) candidates: free while
\(B(k{+}1) \lesssim \text{ridge} \times MFU/MBU \approx 150\text{–}300\) tokens/step
(\(k^* \approx 148\) at batch 1 for 70B/H100; systems use \(k \in [1, 16]\)).
Draft → verify → accept emits \(r \in \{1, \dots, k{+}1\}\) tokens per round; even total
rejection yields the bonus token. Wastes nothing, risks nothing.
Exactness is a theorem, twice. Greedy: induction over rounds. Sampling: accept with
\(\min(1, p(x)/q(x))\), resample the residual \(\tilde{p} \propto \max(0, p-q)\), and
\(Z = \tfrac12\lVert p-q\rVert_1\) is the rejection probability. The emitted law is exactly
\(p\). Lossless means distributional, not bit-exact; never skip the test.
Speedup \(\approx \tau/(1+c_{draft})\), \(\tau = (1-\alpha^{k+1})/(1-\alpha)\): two levers
(alignment, draft cost), an interior optimum in \(k\), and a \(\tau\)-asymptote \(1/(1-\alpha)\)
no chain escapes. Trees spend the budget where entropy lives (1.11 vs 1.40 at the same 4-token
budget).
Draft sources evolved by flaw: independent small model (misaligned, second deployment) →
Medusa (heads can't coordinate) → EAGLE (feature-level autoregression; the deployed baseline) →
MTP (draft trained into the checkpoint; 85–90% acceptance, \(k=1\) by default) →
DFlash/DSpark (block diffusion removes seriality; K3: 118 → 370 tok/s at TP16, a lossless
3.14×).
Every system layer pays a share: gain inversion past \(B(k{+}1) \approx 150\text{–}300\); KV
reservation \((k{+}1)\times kv\) and paged rollback of \(k-(\tau-1)\) tokens; bimodal ITL; doubled
CUDA-graph inventory; EP all-to-all volume ×\((k{+}1)\); state rewind, not truncation, on
hybrid linear-attention models.
Report \(\tau\) with its task distribution, temperature, and \(c_{draft}\), or don't report
it at all. Your move :)