M7.7 - Draft Sources, Dependent Heads, and Hardware-Aware Trees
M7.7 - Draft Sources, Dependent Heads, and Hardware-Aware Trees
0x00 Overview And Background
M7.1 derived exact draft-and-verify sampling. M7.2 built a tree from same-model prediction heads. M7.5 moved drafting into feature space, and M7.6 followed a causal MTP module chain.
Those mechanisms leave a broader systems question unanswered:
Which proposal source and candidate topology should a runtime use once draft latency, proposal dependence, tree verification, exactness, cache state, batch size, and the target hardware are all counted?
A speculative decoder has five separable design decisions:
proposal source:
where candidate tokens, scores, and provisional state come from
candidate topology:
sequence, one-position set, prefix tree, or metadata graph
probability contract:
normalized conditional q, frequency, ranking score, or absent
target selection contract:
greedy match, target-sample membership, rejection sampling,
multi-candidate coupling, or another proved verifier
publication contract:
which output tokens and target-computed state become authoritative
Changing the proposal source does not automatically change the target distribution. Changing the tree does not automatically improve wall-clock time. A larger acceptance length is useful only when the proposal, packing, verification, selection, and temporary-state costs remain below the target steps it replaces.
The proposer does not publish output. It emits typed evidence that a compatible target verifier may consume. Only the publication step advances the authoritative prefix and target cache.
Background knowledge: a proposal is not yet a decoded token
A proposed token is provisional. It may come from a small language model, a suffix match, an early layer, an auxiliary head, or a feature drafter. The target model still owns the output contract.
proposal quality decides:
how often useful candidate paths exist
proposal topology decides:
how many alternatives fit in one verification pass
verification decides:
which output distribution is actually sampled
cache commit decides:
which target-computed states survive into the next round
This distinction matters for retrieval. A retrieved continuation can be an excellent candidate without defining a normalized token distribution . It can be verified by sampling from the target and testing tree membership, but it cannot be silently substituted into the one-draft acceptance formula.
Historical lineage and owner contract
The methods in this article did not appear as one architecture family. They answer different bottlenecks that became visible after basic speculative decoding existed:
| Lineage | Question introduced | Contract M7.7 keeps |
|---|---|---|
| Blockwise and one-draft speculation | Can one target pass validate several positions? | Proposal is provisional; target verification owns output. |
| Prompt lookup and REST | Can repetition replace neural drafting? | A useful candidate need not provide normalized . |
| Draft & Verify and Kangaroo | Can the target itself provide a cheaper proposal path? | Shared weights do not make shallow state authoritative. |
| Medusa, Hydra, and Clover | Should future heads be independent or consume earlier proposals? | Head dependence changes training tensors and proposal critical path. |
| SpecTr and SpecInfer | How can several candidates be verified without shifting the target distribution? | Exactness belongs to a joint coupling or residual-update algorithm. |
| Sequoia | Which exact tree should run on this hardware? | Topology and runtime profile form one versioned artifact. |
This article owns the interfaces among those choices. M7.1 owns the one-sequence acceptance derivation; M7.2 owns tree attention; M7.5 and M7.6 own feature and integrated-MTP drafters; M7.8 owns multi-request scheduling, release, and rollback. M7.7 consumes those mechanisms without thinning or duplicating them.
0x01 Claim Status And Scope
| Claim | Status | Evidence | Safe interpretation |
|---|---|---|---|
| A speculative proposal can come from a model, the target itself, auxiliary heads, features, prompt repetition, or an external datastore. | Source-local and externally verified | A30-A33; Draft & Verify; Kangaroo; REST; Transformers docs | These sources expose different cost, state, and training contracts. |
| Standard Medusa-style future heads are conditionally independent of one another. | Externally verified | Hydra | They share a target hidden state but do not consume earlier drafted tokens. |
| Hydra and Clover introduce dependence on preceding drafted tokens. | Externally verified | Hydra; Clover | Better proposal consistency adds a sequential path inside drafting. |
| More candidate nodes always increase speedup. | False | Hydra; Sequoia; systems cost derivation below | Acceptance can improve while target verification becomes slower. |
| Repeating the one-draft acceptance test independently over candidates preserves the target distribution. | False | SpecTr | Repeated tests can over-allocate probability mass to duplicated candidates. |
| SpecInfer and Sequoia provide target-distribution-preserving stochastic tree verification under their stated algorithms. | Externally verified | SpecInfer; Sequoia | Exactness belongs to the complete sampling and residual-update algorithm. |
| Equal token ids can share target rows even when their parents differ. | False | Causal attention contract; SpecInfer tree materialization | State is a function of the full ancestor path, not token identity alone. |
| The optimal tree is independent of hardware, batch size, temperature, and workload. | False | Hydra; Sequoia | Tree utility and verification time are configuration-dependent. |
| A high average acceptance length proves a serving win. | False | Kangaroo; Clover; Sequoia | Draft time, tree size, target kernel shape, cache work, and batching still matter. |
This article owns proposal generation, candidate-shape compilation, verifier compatibility, and offline hardware-calibrated selection. M7.8 owns the online multi-request controller and production lifecycle.
0x02 A Common Proposal-System Interface
Let the committed prefix be . A proposer returns a typed result, not merely a list of token ids:
where is proposal-side state: a draft KV cache, retrieval cursor, shallow-layer cache, head state, or feature-drafter state. The result has five classes of fields:
@dataclass(frozen=True)
class ProposalResult:
nodes: list[ProposalNode]
probability_semantics: Literal[
"normalized_conditional", "score_only", "frequency", "absent"
]
sampling_relation: Literal[
"iid", "without_replacement", "beam", "deterministic_lookup"
]
topology: Literal["sequence", "set", "tree", "metadata_graph"]
state_handle: ProposalStateHandle
manifest_hash: str
The graph contains nodes with:
is optional and is an optional ranking score. A parametric draft model can provide the conditional proposal probability for a node. Prompt lookup and exact-match retrieval may provide scores or frequencies that are useful for ranking but are not automatically the required by rejection sampling. Keeping q and score in separate fields prevents a convenient but invalid cast.
The runtime linearizes the graph into target inputs:
token_ids: [N_nodes]
parent_index: [N_nodes]
position_ids: [N_nodes]
ancestor_mask: [N_nodes, prefix_len + N_nodes]
proposal_prob: [N_nodes] or absent
proposal_score: [N_nodes] or absent
source_id: [N_nodes]
state_owner: [N_nodes]
origin_request: [N_nodes]
The target computes one hidden/KV row for every candidate token under its ancestor path. The distribution that scores a candidate, however, comes from the parent coordinate:
The row for processes token(v) and predicts its children. It does not predict itself. This one-row offset is a frequent implementation error because the tensors remain shape-correct.
0x02A Verifier capability negotiation
The runtime must reject an incompatible pair before target execution:
| Verifier mode | Required proposal semantics | Required sampling relation | Candidate shape |
|---|---|---|---|
| Target-sample membership | Scores may be absent | Any construction | Set of children/tree |
| One-draft | Normalized conditional | Autoregressive sample from | One sequence |
| SpecTr set coupling | Normalized defining candidate-vector supply | Stated i.i.d. construction | One-position set |
| SpecInfer residual | Normalized conditional distributions | Stated SSM sampling process | Tree |
| Sequoia residual | Normalized conditional distributions | Sampling without replacement plus fallback | Tree |
def bind_verifier(proposal, verifier):
assert verifier.supports_probability(proposal.probability_semantics)
assert verifier.supports_sampling_relation(proposal.sampling_relation)
assert verifier.supports_topology(proposal.topology)
return BoundRound(proposal=proposal, verifier=verifier)
A heterogeneous graph from Hydra and REST cannot invent one by attaching Hydra probabilities to some rows and retrieval frequencies to others. Either define and sample from a normalized mixture proposal, use a verifier such as target-sample membership that does not require , or verify the subgraphs under separately proved contracts.
0x02B Immutable round manifest
Before the first proposal, freeze:
target checkpoint + tokenizer + output head
sampling policy, temperature, truncation, RNG policy
proposal checkpoint / index / skip pattern / head package
probability semantics and sampling relation
topology compiler version and node/depth limits
verifier algorithm and exact/heuristic mode
target and proposal cache generations
kernel/backend, dtype, batch regime, and hardware profile
The manifest is not administrative metadata. A tokenizer change alters retrieved token spans; a sampling-policy change alters acceptance statistics; a target-kernel change alters the measured tree optimum; and a cache-generation mismatch can turn valid ids into stale state.
0x02C Round Cost, Not Acceptance Alone
For candidate graph , define:
If target-valid output tokens are produced in the round, then:
Relative to ordinary target decoding cost per token:
This equation explains why the highest-accuracy proposal can lose. A large draft model may increase while increasing even more. A wide tree may improve first-token coverage while moving into a less favorable kernel regime.
Renderer-safe ledger:
round_cost = proposal + retrieval + packing + target_verify
+ selection + temporary_state
time_per_committed_token = round_cost / E[committed_tokens]
speedup requires:
E[committed_tokens] > round_cost / target_AR_step_cost
0x03 Draft-Source Taxonomy
| Proposal source | Extra training | Resident state | Proposal probability | Main strength | Main failure mode |
|---|---|---|---|---|---|
| Separate smaller LM | Optional if a compatible checkpoint exists | Draft weights + draft KV | Native | Clean autoregressive proposal distribution | Weight/KV memory and target mismatch |
| Prompt lookup | None | Prefix token index | Usually absent | Nearly free repeated n-grams | Only works when the continuation repeats |
| REST retrieval | Datastore build, no drafter training | Suffix index + continuation trie | Frequency is not necessarily calibrated | Domain/code repetition without draft weights | Retrieval miss, stale/domain-specific datastore |
| Draft & Verify | No new weights | Same model, skipped-layer draft path | Native draft logits | No separate model memory | Draft path may still be expensive; layer pattern is model/task-sensitive |
| Kangaroo | Small adapter training | Shallow target layers + adapter | Native draft logits | Very shallow reusable self-draft path | Adapter and exit threshold need calibration |
| Medusa heads | Head training | Parallel future-token heads | Per-head marginals | Parallel proposal generation | Future heads ignore prior drafted tokens |
| Hydra/Clover | Head or adapter training | Dependent head state | Conditional proposal logits | Better sequential consistency | Longer draft critical path |
| EAGLE feature drafter | Drafter training | Feature drafter + target features | Drafter logits | Predicts closer to target representation | Feature-cache and target-version coupling |
| DeepSeek MTP module | Joint pretraining | Integrated MTP module | Module logits | Causal future-token training path | Inference path is optional and runtime-specific |
No row dominates every workload. The source must be chosen with the target checkpoint, output policy, memory budget, batch regime, and request domain in view.
0x04 Non-Parametric Drafting: Prompt Lookup And REST
0x04A Prompt Lookup
Prompt lookup searches the existing prefix for an n-gram ending at the current position and copies the tokens that followed an earlier occurrence.
For prefix tokens:
[A, B, C, D, A, B, C]
the suffix [A,B,C] matches the earlier prefix, so D is a candidate next token. Longer continuations can be copied until the match ends or a configured candidate budget is reached.
def prompt_lookup(tokens, max_ngram, max_candidates):
for n in range(min(max_ngram, len(tokens)), 0, -1):
suffix = tokens[-n:]
starts = find_previous_occurrences(tokens[:-n], suffix)
if starts:
start = starts[-1] + n
return tokens[start : start + max_candidates]
return []
The current Transformers assisted-decoding documentation exposes prompt lookup through prompt_lookup_num_tokens, with a maximum matching n-gram size. That is an implementation boundary, not a guarantee that all runtimes use the same index, tie-breaking, or cache path.
Prompt lookup has no standalone draft weights or draft KV cache. Its quality is highly workload-dependent: source code, templated text, and repeated documents create useful matches; unconstrained conversation may not.
0x04B REST: Move The Repetition Source Into A Datastore
REST builds a datastore of context-continuation pairs:
At inference, it searches for contexts whose suffix matches the longest suffix of the current prefix. If no match exists at length , it decrements until candidates appear.
The retrieved continuations are inserted into a trie. Every trie node stores a prefix frequency. REST prunes to a candidate-node budget and linearizes the remaining subtree for tree-attention verification.

Source: REST, Figure 1. Retrieval returns continuations after the longest matching suffix; duplicate prefixes accumulate frequency in a trie; pruning turns frequency into a finite candidate budget; tree attention verifies the surviving paths. None of those frequencies is automatically a calibrated draft probability.
def rest_propose(prefix, datastore, max_suffix, node_budget):
matches = []
for n in range(max_suffix, 0, -1):
matches = datastore.exact_suffix(prefix[-n:])
if matches:
break
trie = ContinuationTrie()
for continuation in matches:
trie.insert(continuation, increment_frequency=True)
return trie.keep_high_frequency_nodes(node_budget)
REST avoids a parametric draft model, but does not avoid systems work:
offline:
corpus selection -> tokenization -> context/continuation extraction
-> suffix index construction -> versioning
online:
suffix query -> retrieve continuations -> trie merge -> prune
-> linearize -> build ancestry mask -> target verify
Its paper uses target-model sampling and accepts a retrieved child when it matches the target-sampled token. This preserves the target’s ordinary sampling path without pretending trie frequency is a calibrated draft probability.
0x04C Source-to-index trace and release lifecycle
Assume the tokenized corpus contains:
[4, 5, 6, 9, 4, 5, 6, 10, 11]
For query suffix [4,5,6], exact occurrences end before 9 and before
10,11. The retrieved continuation multiset is therefore:
[9, 4, 5, 6, 10, 11]
[10, 11]
The first continuation is long because retrieval reads forward in the corpus;
the second reaches the corpus boundary. The two root children are tied: 9
starts one retrieved continuation and 10 starts one. The later 10 in the
first continuation belongs to the separate full prefix [9,4,5,6,10]; it
does not increment the root child [10].
root child [9]: count 1
root child [10]: count 1
full prefix [9,4,5,6,10]: count 1 (a different trie node)
root-child order on a tie: [9, 10]
For this toy example, rank siblings by descending prefix count, then ascending
token ID on ties. Thus 9 precedes 10 only because of the declared tie-break,
not because either root is more frequent. This is a local illustrative rule,
not a claim about the official implementation’s tie-breaking. It specifies
sibling order, not a complete global node-budget pruning policy. Trie counts
remain corpus statistics, not .
The official REST implementation follows this shape: initialize target cache, search increasingly shorter suffixes, build tree buffers, assign a draft mask, run target tree decoding, evaluate the posterior, and update the target cache. That trace also exposes non-paper engineering choices such as batch-size-one assumptions and repository-specific empty-retrieval fallback behavior. Those choices are implementation-observed, not part of REST’s algorithmic contract.
An index release must bind at least:
corpus snapshot and license/governance policy
train/evaluation exclusion manifest
tokenizer files and normalization
context length and continuation length
suffix key encoding and endianness
frequency counter width
trie pruning and tie-breaking policy
index checksum and builder commit
target checkpoint family used for calibration
Evaluation leakage is a proposal-quality leak even when target verification keeps the output distribution valid. If benchmark answers occur in the datastore, acceptance and latency results no longer measure the intended generalization setting. Exactness is not a defense against contaminated evaluation.
0x04D Prompt Lookup Versus Retrieval
| Dimension | Prompt lookup | REST-style retrieval |
|---|---|---|
| Candidate corpus | Current request prefix | External tokenized datastore |
| Update lifecycle | Per request, automatic | Build, version, refresh, invalidate |
| Retrieval latency | Small local scan/index lookup | CPU memory/index query and trie work |
| Domain leverage | Only repetition already in context | Can encode codebase/domain repetitions |
| Privacy boundary | Request-local | Datastore governance required |
| Distributional drift | Prefix-local | Datastore may become stale or mismatched |
0x05 Self-Speculation: Reuse The Target Without Reusing All Its Work
0x05A Draft & Verify: A Fixed Skipped-Layer Path

Source: Draft & Verify, introductory self-speculation figure. The green path skips selected target layers while drafting; the blue path executes full verification. Accepted green tokens, rejected red tokens, and the extra blue target prediction make the output/state boundary visible.
Draft & Verify represents the draft architecture by a binary layer-skip vector:
where one value denotes that a layer is bypassed during drafting. The full target path uses all layers.
The best skip vector is not the one with the highest acceptance rate. No skipped layers would maximize agreement but perform essentially the target computation. The paper instead minimizes average inference time per verified token on a development set:
where includes both draft and verification time divided by the verified-token count. The search space has patterns, so the paper uses Bayesian optimization rather than exhaustive enumeration for large models.
For development requests , a concrete objective is:
The denominator explains why acceptance alone is insufficient. Setting makes the draft equal to the target and tends toward perfect agreement, but it also repeats target-priced work. Setting nearly every component of to “skip” minimizes draft layers but can collapse verified progress. The optimizer must observe both effects together.
too few skipped layers:
high agreement, expensive draft
too many skipped layers:
cheap draft, low acceptance, wasted suffixes
wrong skipped-layer pattern:
can be worse than another pattern with the same number of layers
Draft length is also dynamic. If the current draft token confidence falls below threshold , drafting stops. The threshold is adjusted from a moving acceptance-rate estimate toward a target acceptance rate.
acceptance_ema = beta1 * acceptance_ema + (1 - beta1) * round_acceptance
if acceptance_ema <= target_acceptance:
threshold_candidate = gamma + epsilon
else:
threshold_candidate = gamma - epsilon
gamma = beta2 * gamma + (1 - beta2) * threshold_candidate
This control loop is heuristic policy, not part of speculative-sampling exactness. Exactness still comes from full-target verification.
0x05B Kangaroo: Shallow Shared Trunk, Adapter, Second Exit

Source: Kangaroo, framework figure. Frozen target layers and LM head are blue; the small trainable adapter is orange. The second exit stops low-confidence drafting, while retained shallow features feed the remaining target layers during verification.
Kangaroo avoids running an arbitrary skipped-layer network for each draft token. It reuses a fixed shallow target subnetwork and trains a small adapter :
The adapter bridges shallow features to the target’s output space and reuses the target LM head. In the paper, the adapter contains attention and normalization without a full FFN-heavy draft model.
For a draft sequence of positions, the important shapes are:
shallow hidden: F_l [B, K, d]
adapter attention: A(F_l) [B, K, d]
shared LM logits: Z_s [B, K, V]
full upper layers: M_b[l:](F) [B, K, d]
target logits: Z_t [B, K, V]
Kangaroo’s adapter is intentionally smaller than a copied Transformer block: one multi-head attention path plus two normalization operations, with no full FFN in the reported design. The target LM head maps both adapter output and full-target output into vocabulary space. Shared output weights do not imply shared hidden-state semantics.
The adapter is trained by distillation from the target distribution:
Drafting exits when top-1 confidence falls below :
Kangaroo also keeps the shallow feature for the stopped position so the remaining target layers can process a parallel unit during verification. This exposes an implementation advantage that an abstract “same model drafts itself” label hides: intermediate target features can be reused only when their provenance and layer boundary match the full verification path.
The adapter loss is a soft-target cross-entropy. If target logits are and shallow-adapter logits are , with temperature :
The frozen target owns the teacher distribution. Adapter parameters receive gradients; shallow target layers and the shared LM head remain frozen in the paper’s setup. This is a different training contract from Draft & Verify, which searches a skip pattern but trains no new network.
0x05C Self-Draft State Contract
authoritative state:
committed target KV and output tokens
provisional state:
shallow/skipped-path hidden rows
draft logits
candidate token ids
draft confidence
verification state:
full-path target rows for each candidate position
A runtime must never relabel skipped-path or shallow-adapter state as final target state merely because the token is later accepted. Reuse is valid only where the method proves that the cached tensor is exactly the tensor the target path needs.
After computational-path equivalence has been established, the following predicate is a necessary metadata check, not a proof that the tensors are equal. Matching these fields alone cannot make skipped-path activations equivalent to full-target activations:
def may_reuse(candidate_state, target_need):
return (
candidate_state.checkpoint == target_need.checkpoint
and candidate_state.layer_boundary == target_need.layer_boundary
and candidate_state.token_id == target_need.token_id
and candidate_state.position == target_need.position
and candidate_state.ancestry_hash == target_need.ancestry_hash
and candidate_state.dtype == target_need.dtype
and candidate_state.cache_generation == target_need.cache_generation
)
Draft & Verify can reuse target-compatible portions of the common path only where path equivalence has been proved and that predicate is true. Kangaroo can pass a shallow feature into the remaining target layers because the architecture explicitly defines that boundary. Neither method may publish a skipped-path upper-layer KV row as if the full target had computed it.
0x06 Independent And Dependent Draft Heads
0x06A Why Independent Heads Lose Conditional Information
Let be the target hidden state at the current prefix. A bank of standard future-token heads predicts:
Each head sees the same prefix representation. The joint proposal implied by independent heads is:
The target’s causal factorization is instead:
The missing condition is the earlier drafted continuation. Head 3 may predict a grammatically plausible third token that is inconsistent with the tokens chosen by heads 1 and 2.
0x06B Hydra: Condition On Earlier Drafted Embeddings

Source: Hydra, Figure 1. Standard draft heads receive only the base hidden state, so later heads do not know the tokens chosen by earlier heads. Hydra feeds earlier sampled-token embeddings into later heads. The orange dependency arrows improve conditional consistency but lengthen the proposal critical path.
Hydra parameterizes future head with the prefix hidden state and earlier drafted-token embeddings:
The basic paper architecture concatenates these vectors into an MLP input. This restores explicit sequential dependence, but the heads can no longer all finish at once.
Hydra++ compares additional design choices:
- scale each head MLP to four layers;
- distill the target distribution instead of only predicting hard ground-truth labels;
- add a prefix-attention decoder layer that produces a richer draft input once per decoding round.
The target backbone remains frozen in the paper’s experiments. Basic Hydra/Medusa heads were trained for one epoch in that setup; Hydra++ heads were trained longer. Those are source-reported recipes, not universal hyperparameters.
Hydra source-to-tensor trace
Let the verified prefix end at token , and let head predict . Under teacher forcing its input is:
At runtime, ground-truth future embeddings are replaced by the selected
earlier proposals. For batch size and hidden width , basic head
therefore receives [B, (i+1)d] if the base hidden and each token embedding
have width . Later heads are larger in their first projection and cannot
complete before earlier tokens are selected.
The following zero-based teaching sketch requires an active predecessor in
the same document occurrence. It skips the first token of each segment rather
than inventing an initial hidden state. If BOS is needed, the caller includes
an actual BOS token and its target hidden row inside that segment; the first
content token can then use that row. Never wrap to hidden[-1], borrow a
previous document’s row, or clamp the index to hidden[t].
def hydra_teacher_rows(tokens, hidden, max_future, *, segment_ids, valid):
# hidden[j] is the target state AFTER tokens[j], computed segment-causally.
# valid is input availability, not a loss-only supervision mask.
n = len(tokens)
if not (len(hidden) == len(segment_ids) == len(valid) == n):
raise ValueError("unaligned packed inputs")
if type(max_future) is not int or max_future < 0:
raise ValueError("max_future must be a nonnegative integer")
if any(type(flag) is not bool for flag in valid):
raise ValueError("valid must contain booleans")
rows = []
for t in range(1, n):
for i in range(1, min(max_future, n - t - 1) + 1):
# Predecessor, all embeddings, and label must share one active run.
if not all(valid[j] and segment_ids[j] == segment_ids[t]
for j in range(t - 1, t + i + 1)):
continue
conditioning = [hidden[t - 1]] + [
embed(tokens[j]) for j in range(t, t + i)
]
rows.append((i, concat(conditioning), tokens[t + i]))
return rows
Here segment IDs identify document occurrences, and all arrays retain their
original packed addresses. Hidden rows must already come from a target forward
with segment-causal attention; row filtering cannot repair contaminated hidden
states. Any additional loss-only mask is applied separately, without removing
input context. For a segment of length L, head i has
max(L - i - 1, 0) eligible rows before such supervision masking.
Empty streams, one-token segments and max_future=0 yield no rows.
This is a local boundary convention for the article’s teacher-row sketch,
not a claim about the upstream implementation’s BOS or packing policy. The
last embedding is at t+i-1; the label at t+i is never an input.
The official Hydra implementation makes the shift mechanical with rolled token embeddings and expands selected paths one head at a time. Its PrefixMLP variant runs one additional decoder layer once per proposal round, then lets the depth-specific MLP heads reuse that prefix-aware state. The reported Hydra++ recipe combines four-layer heads, teacher-distribution loss, and this shared prefix layer. Those three changes are separable design choices, not consequences of dependence itself.
0x06C Clover: Regressive Attention Instead Of Concatenation Alone

Source: Clover, architecture overview. Clover carries a hidden draft state between depths, injects the preceding token embedding through an attention decoder, optionally augments the target representation, and reuses the target language-model head.
Clover propagates a hidden draft state and injects the previous drafted token embedding through an attention decoder:
The updated is fed through the speculative predictor. Clover also studies an augmenting Transformer block on top of the target representation and reuses the target LM head across speculative depths.
The paper specifies this block at the Attention(Q_i,K_i,V_i) boundary; its
architecture figure further depicts a lightweight gated interaction. The
article does not replace that boundary with an invented universal attention
formula, because the exact gate is implementation-specific. The important
design difference is stable: basic Hydra widens a depth-specific MLP
input by concatenating all prior embeddings, while Clover recurrently updates
a fixed-width state. The latter avoids linearly growing input width, but adds
a serial recurrent dependency and an attention-decoder parameterization.
Medusa:
all heads parallel; weak continuation dependence
Hydra:
prior drafted embeddings condition later heads
Hydra++:
deeper heads + target distillation + prefix attention
Clover:
recurrent draft state + previous-token attention + optional augmenting block
0x06D Latency Tradeoff
Let be one head-stage cost and the speculation depth.
Idealized independent-head critical path:
Idealized dependent-head critical path:
This does not imply dependent heads are slower end to end. If dependence increases accepted length enough to use a much smaller tree or fewer target rounds, the total ratio can improve:
Clover explicitly motivates its design for smaller practical token trees and larger batch sizes, where an enormous independent Cartesian tree would become compute-bound.
0x07 Candidate Topologies
0x07A One Sequence
A depth- sequence contains proposal nodes. Its useful prefix disappears after the first rejected token.
0x07B Multiple Independent Sequences
With sequences of depth , the unmerged budget is:
Shared prefixes should be merged; otherwise identical target activations and KV rows are recomputed.
0x07C Cartesian Future Heads
If depth keeps candidate tokens, a full Cartesian tree has:
For :
The formula derives directly: depth 1 has nodes; each receives children; each depth-2 node receives children.
0x07D Prefix-Merged Tree And The DAG Boundary
If two proposal sources emit the same token under the same full ancestor path, they represent the same target computation and can share a node. Source-specific proposal probabilities still need careful handling by the verifier.
The full-prefix condition is necessary. Consider:
path 1: A -> B
path 2: X -> B
The two B nodes have the same token id and depth, but different causal
histories. Their attention outputs, logits, and KV rows can differ. Merging
them by token id would give one path the other’s state. The canonical key is:
not (depth, token_id).
A proposal planner may use a DAG to share immutable metadata, source handles, or suffix descriptions. Before target execution, it must materialize parent-unique candidate rows unless it has proved complete state equivalence. For an ordinary causal decoder, merging identical full prefixes produces a trie, which is still a tree.
def merge_by_full_prefix(candidate_paths):
rows_by_prefix = {}
for path in candidate_paths:
parent = -1
prefix = ()
for token in path.tokens:
prefix = prefix + (token,)
if prefix not in rows_by_prefix:
rows_by_prefix[prefix] = CandidateRow(
row_id=len(rows_by_prefix),
token=token,
parent=parent,
sources=[],
)
row = rows_by_prefix[prefix]
row.sources.append(path.source)
parent = row.row_id
return topological_rows(rows_by_prefix.values())
Tree flattening must preserve ancestry. Here candidate_roots contains the
alternative first proposed tokens, not a committed-prefix or anchor row.
It may contain one candidate or a forest of alternatives. Candidate depth starts
at one; position stores that relative depth, while position_id is the
absolute target-input position. The prefix-frontier logits already exist and
are not appended to these candidate rows. This candidate-only convention is
separate from Sequoia’s root-inclusive optimization score below.
The flattening and validation snippets use the same dictionary-row interface.
build_ancestor_mask(rows, prefix_len) supplies the backend mask: all prefix
columns are visible, followed by self/ancestor-only candidate columns.
PREFIX_FRONTIER = -1 # logits owned by the already processed prefix
def flatten_tree(candidate_roots, prefix_len):
assert prefix_len >= 0
rows = []
queue = [(node, -1, 1, ()) for node in candidate_roots]
while queue:
node, parent_row, depth, parent_prefix = queue.pop(0)
row = len(rows)
full_prefix = parent_prefix + (node.token_id,)
rows.append({
"token_id": node.token_id,
"parent": parent_row,
"position": depth,
"position_id": prefix_len + depth - 1,
"predictor_row": PREFIX_FRONTIER if parent_row == -1 else parent_row,
"full_prefix": full_prefix,
"q": node.proposal_probability,
"source": node.source_id,
})
for child in node.children:
queue.append((child, row, depth + 1, full_prefix))
mask = build_ancestor_mask(rows, prefix_len)
return rows, mask
For node and candidate node :
All candidate nodes may also attend to the committed prompt prefix. Sibling candidates must not attend to one another.
0x07E Candidate row, predictor row, and KV row
For a prefix of length and candidate row at depth :
candidate input row r:
token_ids[r] is processed at position T + d_r - 1
probability that verifies token_ids[r]:
prefix-frontier logits, if parent[r] == -1
logits[parent[r]], otherwise
KV written at row r:
belongs to token_ids[r] under ancestry(parent[r])
logits produced at row r:
predict children of r, not r itself
For rows [A, B, C, D] with parents [-1, 0, 1, 1], token A is
scored by frontier logits, B by row A, and both C and D by row B.
Rows C and D may share a predictor distribution while still owning
different input/KV rows. This separation closes the common one-position
shift bug.
0x08 Multiple Drafts Require A New Exactness Derivation
0x08A One Draft Is A Maximal Coupling
Let be one draft token and the required target token. The one-draft speculative acceptance probability is:
This is maximal coupling under mismatch cost:
The familiar accept/reject/correction rule implements that coupling.
0x08B Why Repeating It Over Candidates Is Wrong
Suppose every draft sample is 1, while the target is Bernoulli. Testing each of copies independently with acceptance probability would output 1 with probability at least:
For , that is not . More chances to accept the same token have duplicated its probability mass.
0x08C SpecTr: Membership-Cost Optimal Transport
For candidate vector , let be the set of distinct proposed tokens. SpecTr changes the cost to:
A candidate vector has supply:
A valid coupling must preserve both the candidate-vector supply and the target-token demand:
The exact objective is:
subject to those two marginal constraints. The zero-cost mass is the probability that the selected target token belongs to the proposed set; the remaining mass is rejection/correction. The exact discrete linear program has transport variables, exponential in . SpecTr derives an efficient valid selection procedure with a stated multiplicative approximation to optimal acceptance rather than solving this LP online.
Finite transport oracle
Take vocabulary {a,b,c}, draft distribution
, target , and . There are nine
candidate vectors with supplies such as:
Q(a,a) = 0.16
Q(a,b) = 0.16
Q(a,c) = 0.08
...
Q(c,c) = 0.04
An exhaustive max-flow oracle connects candidate vector to token at zero cost only when . It then checks:
for every candidate vector X:
sum_y pi[X,y] == Q(X)
for every output token y:
sum_X pi[X,y] == p(y)
For this toy instance all target demand can be assigned to a candidate vector
that contains the demanded token, so the optimal membership acceptance is
1.0. That does not mean two arbitrary draft tokens are always accepted;
it is a property of this finite coupling and these distributions.
One-position set versus multi-step tree
SpecTr’s derivation couples candidates for one next-token decision. A tree repeats a selection problem at successive accepted nodes, where every child distribution is conditional on a different prefix. Applying the one-position LP to all tree nodes at once without preserving those conditional histories is not justified. SpecInfer and Sequoia provide their own recursive residual contracts for that setting.
This is a useful design lesson:
candidate diversity:
can increase the probability that a target-valid token is present
selection algorithm:
must allocate target probability across the whole candidate set
independent p/q tests:
do not automatically define a valid multi-candidate coupling
0x09 SpecInfer: Expand, Merge, Linearize, Verify
SpecInfer turns one or more small speculative models into a token tree in two ways.

Source: SpecInfer, Figure 2. Expansion branches one speculative model at selected positions; merge combines trees from several speculative models by shared token prefixes. Both paths then require linearization, ancestor-only target attention, subtree verification, and one committed path.
Expansion keeps multiple top candidates per step according to a configured width vector such as:
width by depth = [2, 2, 1]
Merge combines trees from multiple speculative models. Paths with identical full token prefixes share nodes. Equal suffix tokens under different parents remain separate target rows.
The target verifier then:
- linearizes all tree nodes;
- assigns topology-aware positions and an ancestor mask;
- executes target attention for all nodes in one pass;
- walks one accepted path;
- commits only target-valid path state.
SpecInfer’s tree attention is defined so each node receives the same attention output it would receive if its root-to-node path were processed as an ordinary sequence. Topology-aware masking fuses these paths without allowing sibling leakage.
The compiled buffers must agree:
tree token row r -> token_ids[r]
parent relation -> parent_index[r]
causal coordinate -> position_ids[r]
allowed context -> ancestor_mask[r]
probability for row r -> frontier logits or target_logits[parent_index[r]]
temporary target state -> branch_kv[r]
The paper’s expansion strategy branches one speculative model at selected positions. Its merge strategy combines trees from several speculative models. Both strategies terminate at the same target ABI; they differ in how proposal distributions and source ownership reach each child.
In the following integration sketch, merge_identical_prefixes returns a
prefix container whose children are the first-token candidates. The container
represents the already processed prefix; it is not itself a target-input row.
An empty candidate forest falls back to the ordinary target step.
def tree_speculative_round(prefix, speculators):
trees = [s.propose_tree(prefix) for s in speculators]
merged = merge_identical_prefixes(trees)
if not merged.children:
return ordinary_target_step(prefix)
rows, mask = flatten_tree(merged.children, len(prefix))
validate_candidate_graph(rows, len(prefix))
target = target_model.verify_tree(prefix, rows, mask)
committed_path = verify_under_configured_policy(
tree=merged,
target_distributions=target.distributions,
proposal_distributions=proposal_metadata(merged),
)
commit_target_kv(target.branch_cache, committed_path)
discard_siblings(target.branch_cache, committed_path)
return committed_path.tokens
SpecInfer describes both greedy verification and a multi-step stochastic verifier. Its stochastic correctness applies to the complete residual-update procedure. It should not be simplified to “pick any child that looks likely.”
0x09A Stochastic residual update
At one node, let be the target distribution and let proposal be the next child tested. At step :
If is rejected, the remaining target mass becomes:
This update is not optional cleanup. The accepted mass for token is ; the unaccepted target mass is exactly the positive residual. Therefore accepted mass plus rejected-branch residual reconstructs . Induction over children preserves the original target marginal.
def verify_children(target_p, proposals):
residual = target_p
for token, q in proposals:
accept = min(1.0, residual[token] / q[token])
if uniform() < accept:
return token
residual = normalize(positive_part(residual - q))
return sample(residual)
For target and two i.i.d. proposals from
, the repository oracle enumerates all nine proposal pairs,
every accept/reject branch, and the final residual sample. The resulting
output marginal is (0.5, 0.3, 0.2) to floating-point tolerance. Re-running
each candidate against the original instead would fail this test.
0x09B Temporary KV Is Topology State
For homogeneous full K/V rows, candidate nodes, layers, KV heads, head width , and bytes per scalar, raw candidate code payload is:
This is a dense payload example, not the generic admission cost of a quantized, MLA, sliding-window or shared-page cache. Use the actual per-layer retained segments and incremental union of physical allocations, including qparams, residual/sparse state, page rounding and sharing exactly once. Keep workspace disjoint. M8.6 owns quantized representation costs, M5.8 latent representation, and M5 cache retention/publication/lifetime. Cache schema, quantizer specification and allocation policy therefore belong in the measured profile identity.
The target verifier may write all candidate rows, but only one root-to-node path can become the committed autoregressive prefix. Parent indices and request ownership are therefore correctness metadata, not bookkeeping decoration.
0x0A Sequoia: Derive The Tree Objective
Sequoia separates two optimization problems:

Source: Sequoia, Figure 1. The left plot reports source-measured accepted-token growth as tree budget increases; the right compares a sequence, independent sequences, a full k-ary tree, and a DP-optimized topology. The vertical hardware markers motivate a second optimization: the tree maximizing expected accepted tokens need not maximize wall-clock speed.
- choose a tree that converts a fixed node budget into a large expected generated-token count;
- choose size and depth for the measured target/draft hardware costs.
0x0AA Positional Acceptance Model
Let be the probability that child position is selected, conditional on its parent having been reached. At most one sibling is selected, so these are mutually exclusive outcomes, not separate chances conditioned on testing each sibling. For the represented child slots:
The remaining mass means no represented child is selected. Do not normalize it away: it accounts for stopping the accepted path at this parent. If calibration instead records , the acceptance rate conditional on rejection of all earlier siblings, convert with the probability chain rule:
These conditional rates need not sum to one; the resulting selected-child
probabilities must sum to at most one. This conversion does not assume
independent sibling tests. For node , let Path(v) be the child indices
followed from the root, and set .
The probability of reaching is:
Let indicate that verification reaches node . The generated-token count under the paper’s convention is:
By linearity of expectation:
That is why the final tree score is a sum of path-probability products, not merely node count or maximum depth.
With the root counted as one node and depth measured in edges from that root, a verified path visits at most nodes. Consequently:
This is an independent sanity check on the optimizer’s result. A depth-two tree cannot have expected progress greater than three under this convention, even if it contains many siblings.
0x0AB Sampling Without Replacement And Robustness
SpecInfer’s baseline stochastic construction may sample the same high- token more than once. Duplicates do not increase set coverage, and repeated rejection of one overconfident draft token is especially wasteful at low temperature. Sequoia changes the per-parent proposal process:
- sample a child from the current draft distribution;
- remove that token from future draws at the parent;
- after rejection, update the target residual;
- if all nonzero draft mass has been exhausted, use a uniform distribution over unsampled tokens as the proposal fallback.
Sampling without replacement changes the joint proposal law. It therefore cannot be paired with a verifier derived for i.i.d. samples by changing one flag. Sequoia proves its sampling and residual-verification procedure together. The article preserves that pair as one algorithmic contract.
0x0AC Depth-Indexed Dynamic-Programming Recurrence
The official Sequoia optimizer includes depth in the state. Define as the maximum expected generated-token score for a tree with:
n: total node budget, including the root of this subproblem
d: maximum remaining depth
b: number of child slots already represented at this root
For one root-only tree:
With one child, the root contributes one and the child subtree is reached with probability :
For branch slot , split the node budget into:
left part:
root plus the first b-1 child subtrees, using y nodes
right part:
the b-th child subtree, using n-y nodes
The right part contributes only if child position is accepted. Therefore:
where contains only splits that leave valid left and right subtrees. The first term preserves the root and previous branches; the second adds the expected score of branch . A backpointer stores the maximizing split and the maximizing branch count of the right subtree, making topology reconstruction part of the algorithm rather than an omitted postprocess.
def validate_selected_child_probabilities(probabilities):
from math import fsum, isfinite
if not all(isfinite(p) and 0.0 <= p <= 1.0 for p in probabilities):
raise ValueError("invalid selected-child probability")
if fsum(probabilities) > 1.0 + 1e-12:
raise ValueError("sibling probability mass exceeds one")
def optimize_tree(max_nodes, max_depth, acceptance):
# acceptance[0] is an unused zero sentinel, not root reach probability.
validate_selected_child_probabilities(acceptance[1:])
B = len(acceptance) - 1
score = full((max_nodes + 1, max_depth + 1, B + 1), -inf)
backpointer = {}
for depth in range(max_depth + 1):
score[1, depth, 0] = 1.0
for depth in range(1, max_depth + 1):
for nodes in range(2, max_nodes + 1):
score[nodes, depth, 1] = (
1.0
+ acceptance[1]
* max(score[nodes - 1, depth - 1, :])
)
backpointer[nodes, depth, 1] = (1, nodes - 1)
for branches in range(2, min(B, nodes - 1) + 1):
for left_nodes in valid_splits(nodes, branches):
right_nodes = nodes - left_nodes
candidate = (
score[left_nodes, depth, branches - 1]
+ acceptance[branches]
* max(score[right_nodes, depth - 1, :])
)
if candidate > score[nodes, depth, branches]:
score[nodes, depth, branches] = candidate
backpointer[nodes, depth, branches] = (
left_nodes, right_nodes
)
return reconstruct_tree(backpointer, score)
This model assumes acceptance depends on branch rank . A richer calibration can estimate by depth and branch rank. That improves fit but increases sample requirements and makes the artifact more sensitive to workload drift.
0x0AD Hardware-Aware Objective
The tree with the highest is not necessarily the fastest tree. Let:
G(n,d): expected generated tokens for a tree of size n and depth d
t(n): measured target time to verify n nodes / one-token target time
c: measured draft time per depth step / one-token target time
Sequoia evaluates:
and searches over . Verification shape is measured, not assumed linear. An offloaded target may prefer a much larger tree because every target round transfers or streams expensive weights. An on-device target may reach a compute-bound regime much earlier.
The corrected illustrative oracle explicitly chooses conditional sibling-test
rates h = [0.82, 0.48, 0.24]. These are synthetic assumptions, not measured
Sequoia calibration data. Converting them gives selected-child probabilities
p = [0.82, 0.0864, 0.022464], whose sum is 0.928864; the remaining
0.071136 is the probability of selecting none of the three represented slots.
Passing h directly as p would violate the sibling probability budget.
The toy search uses two to eight total nodes, maximum edge depth four, and
synthetic normalized target costs t(2..8) = [1.00, 1.03, 1.08, 1.16, 1.28, 1.43, 1.62], with draft depth cost c=0.09. It selects a five-node chain at
depth four. Its expected progress is:
The normalized time per token is (1.16 + 4 * 0.09) / 3.49588976, about
0.4348. Here only the first child slot appears at each non-leaf, so the
chain stops there with probability 1-0.82, including outcomes assigned to
unrepresented later slots. The expected progress remains below the five-node
path maximum. Independent enumeration of small ordered trees checks the DP
scores and selected shape. These are deterministic teaching results, not
measured latency or a hardware speedup claim.
0x0AE Acceptance Statistics Are Versioned Artifacts
The positional acceptance vector is estimated from data. Sequoia reports that optimal trees can change with model pair, temperature, dataset, and hardware. Therefore an optimized tree artifact needs provenance:
target checkpoint + tokenizer
proposal checkpoint/index/head version
sampling policy and temperature range
calibration dataset and date
batch-size regime
hardware and target kernel version
measured t(n) and c curves
chosen tree topology hash
Using an old tree is not generally a correctness failure if verification remains exact, but it can erase the speedup.
0x0B Training And Runtime Integration Matrix
| Method | Target frozen? | Trained state | Draft execution | Candidate shape | Exactness path |
|---|---|---|---|---|---|
| Separate draft LM | Usually | Draft model or existing checkpoint | Autoregressive draft KV | Sequence/tree | speculative sampling or greedy match |
| REST | Yes | None; datastore built offline | CPU/index retrieval + trie | Retrieved tree | Target sample membership or stated REST verifier |
| Draft & Verify | Yes | None | Skipped target layers | Sequence | Full target verification |
| Kangaroo | Yes | Adapter | Shallow target + adapter | Sequence | Full target verification |
| Medusa | Frozen in Medusa-1; joint in Medusa-2 | Future-token heads, optionally backbone | Parallel heads | Static sparse tree | Greedy or configured acceptance policy |
| Hydra/Hydra++ | Yes in reported setup | Dependent heads; optional prefix-attention layer | Sequential conditioned heads | Data-derived static tree | Target verification |
| Clover | Usually | Regressive decoder + augmenting block | Sequential attention decoder | Smaller dependency-aware tree | Target verification |
| SpecTr | Draft/target separate | No special training required by selector | draft sequences | Multi-candidate sequences | Valid transport plan |
| SpecInfer | Separate SSMs | Optional fine-tuning/boosting | One or multiple SSMs | Expanded/merged tree | Greedy or MSS verifier |
| Sequoia | Separate or self-draft compatible | Offline acceptance calibration | Depends on proposer | DP-optimized tree | Sequoia sampling/verifier |
The table is intentionally paper-by-contract rather than paper-by-speedup. Draft & Verify’s skip-vector search, Kangaroo’s adapter distillation, Hydra++‘s teacher loss, SpecInfer’s optional SSM improvement, and Sequoia’s offline tree calibration create different mutable artifacts. Treating them all as “a draft model” hides what must be trained, versioned, loaded, and rolled back.
0x0BA Training Labels Differ By Head Semantics
Independent head learns a future marginal from the same trunk state:
Dependent heads need a conditioning policy during training:
teacher forcing:
later head receives the ground-truth prior token
self-conditioning:
later head receives a sampled/argmax earlier prediction
distillation:
head matches the target distribution, not only the hard label
Teacher forcing is stable but can create exposure mismatch at inference. Self-conditioning better matches runtime state but introduces nondifferentiable selection or surrogate choices. Target distillation conveys probability mass beyond one label but requires target logits and storage/compute.
For Hydra-style hard labels:
For Hydra++ target distillation:
The paper reports a frozen Vicuna backbone, one epoch for basic Hydra and Medusa heads, ten epochs for Hydra++, AdamW, and a cosine schedule. Those are source-reported experimental settings. They do not establish that every target model, dataset, or head depth should use the same schedule.
0x0C End-To-End Proposal Buffer Trace
Consider two sources:
Hydra:
A -> B -> [C, D]
REST:
A -> B -> E
A -> F
another Hydra path:
X -> B
After prefix merge:
root
A
|-- B
| |-- C
| |-- D
| `-- E
`-- F
X
`-- B # distinct B: different full prefix and target state
Flattened rows:
| row | token | parent | depth | proposal source | q available? |
|---|---|---|---|---|---|
| 0 | A | -1 | 1 | Hydra + REST | source-dependent |
| 1 | B | 0 | 2 | Hydra + REST | Hydra q; REST frequency |
| 2 | F | 0 | 2 | REST | no calibrated q assumed |
| 3 | C | 1 | 3 | Hydra | yes |
| 4 | D | 1 | 3 | Hydra | yes |
| 5 | E | 1 | 3 | REST | no calibrated q assumed |
| 6 | X | -1 | 1 | Hydra | yes |
| 7 | B | 6 | 2 | Hydra | yes; distinct from row 1 |
The runtime cannot feed this heterogeneous graph into an arbitrary verifier. It must choose a verifier compatible with the available proposal semantics, for example target-sample membership over the whole child set, or separate verified subtrees with a proved combination rule.
The target-coordinate compiler additionally returns:
| candidate row | token | predictor coordinate | target position |
|---|---|---|---|
| 0 | A | prefix frontier | |
| 1 | B after A | row 0 | |
| 3 | C after A,B | row 1 | |
| 4 | D after A,B | row 1 | |
| 6 | X | prefix frontier | |
| 7 | B after X | row 6 |
Rows 1 and 7 contain the same token id but different parent rows, masks, and KV state. Rows 3 and 4 share predictor row 1 but not input/KV rows.
0x0CA Integrated selection oracle
def compile_speculative_round(prefix, proposal_results, manifest):
assert all(result.manifest_hash == manifest.hash
for result in proposal_results)
paths = collect_paths(proposal_results)
trie = merge_identical_full_prefixes(paths)
rows = materialize_parent_unique_rows(trie)
coords = compile_positions_masks_and_predictor_rows(rows, prefix)
verifier = negotiate_verifier(
probability_semantics=collect_probability_contract(rows),
sampling_relation=collect_sampling_contract(rows),
topology="tree",
requested_mode=manifest.verifier_mode,
)
target = verify_target(rows, coords)
selection = verifier.select(rows, target)
publish_target_path(selection, target.branch_cache)
return selection.tokens
The repository fixture compiles four paths into seven target rows, keeps the
two history-distinct B rows separate, verifies every ancestor-mask entry,
enumerates the SpecInfer output marginal, solves a finite membership-transport
instance, runs the depth-indexed Sequoia DP, and hashes the resulting proposal
artifact. This is a deterministic correctness oracle, not a latency claim.
0x0CB Cache Commit Trace
If target verification chooses A -> B -> D:
commit:
target-computed KV rows for A, B, D
discard:
C, E, F target branch rows
retain separately if policy needs it:
proposal-side draft KV or retrieval cursor
never commit:
proposal-model KV as target KV
sibling target rows
a correction-token row computed for a rejected token
This inherits M7.1’s correction-token rule: an emitted correction token needs target state computed for that actual token before a future decode step depends on its KV.
0x0D Evaluation: Measure The Whole Frontier
Proposal quality
acceptance by depth
accepted path length distribution
first-child coverage
distinct-candidate coverage
calibration of q where required
retrieval match length and miss rate
Proposal cost
draft latency by depth
retrieval/index latency
tree construction and pruning time
CPU-GPU transfer time
proposal weights and KV memory
Target verification
target time by node count and topology
mask/position construction time
temporary target KV bytes
kernel occupancy and graph-capture hit rate
Output and serving
time per committed token
inter-token latency distribution
throughput under batch sizes 1, 2, 4, 8, ...
exact output-distribution tests where claimed
quality tests for heuristic acceptance
fallback frequency
Benchmark claims in the source papers are configuration-specific. Hydra’s reported throughput gains, REST’s retrieval overhead, Clover’s larger-batch results, SpecTr’s speedups, SpecInfer’s distributed/offload results, and Sequoia’s large-tree offload gains should all remain source-reported rather than becoming universal expectations.
0x0E Failure Lab
| Failure | Observable symptom | Root cause | Required fix |
|---|---|---|---|
| Repeated one-draft tests over duplicate candidates | Output distribution shifts toward repeated token | Candidate probability counted multiple times | Use a proved multi-candidate selector |
| Dependent heads trained with only teacher forcing collapse at runtime | Later-head accuracy drops sharply | Exposure mismatch | Evaluate self-conditioned sequences; adjust training |
| Huge Cartesian head tree | Acceptance rises but latency worsens | Target verification becomes compute-bound | Prune or optimize topology against measured cost |
| REST datastore drift | Retrieval hit rate remains high but acceptance falls | Continuations no longer match target/domain | Version and refresh datastore |
| Prompt lookup on low-repetition requests | Mostly empty/length-1 drafts | No repeated n-grams | Fall back without forcing a candidate budget |
| Skipped-layer draft state committed as target state | Future outputs diverge | Provisional hidden/KV provenance violated | Commit only full-target-compatible state |
| Tree mask exposes siblings | Artificially high acceptance or corrupted logits | Candidate leakage | Assert ancestry mask row by row |
| Source frequencies used as | Invalid acceptance ratios | Ranking score is not proposal probability | Use compatible membership verifier or calibrate/prove |
| Acceptance-calibrated tree moved to new hardware | Expected tokens unchanged, speedup disappears | curve changed | Re-profile hardware-aware objective |
| Optimizer maximizes accepted tokens only | Chooses oversized/deep tree | Proposal and target costs omitted | Optimize wall-clock ratio |
| Equal token id merged across different parents | Later logits depend on the wrong history | Metadata DAG treated as target-state DAG | Merge only identical full prefixes; materialize parent-unique rows |
| Candidate scored by its own output row | Shape checks pass but acceptance is shifted | Input-row/logit-row off-by-one | Score roots from frontier and other nodes from parent logits |
| Mixed REST frequency and Hydra passed to one selector | Target marginal test fails | Heterogeneous scores relabeled as one distribution | Define a normalized mixture or choose a compatible verifier |
| SpecInfer rejection restarts from original | Duplicate candidates receive excess mass | Residual distribution was not updated | Carry |
| Sequoia topology reconstructed without depth state | Tree exceeds draft-depth budget | Simplified 2D DP lost the critical path | Optimize and backtrack |
| Conditional sibling-test rates passed directly to the Sequoia DP | Expected progress can exceed every possible path | Mutually exclusive selected-child probabilities exceed unit mass | Convert conditional rates, retain stop mass, and check |
| Retrieval benchmark content is in the datastore | Unrealistic acceptance and latency | Split contamination | Freeze and audit corpus exclusion manifest |
| Self-spec hidden row reused after target or policy change | Silent divergence or cache corruption | State provenance/version mismatch | Prove computational-path equivalence, then validate checkpoint, layer, token, ancestry, dtype, and generation |
0x0F Implementation Assertions
def validate_candidate_graph(rows, prefix_len):
assert prefix_len >= 0
for row_id, row in enumerate(rows):
parent = row["parent"]
assert -1 <= parent < row_id
expected_depth = 1 if parent == -1 else rows[parent]["position"] + 1
assert row["position"] == expected_depth
assert row["position_id"] == prefix_len + expected_depth - 1
parent_prefix = () if parent == -1 else rows[parent]["full_prefix"]
assert row["full_prefix"] == parent_prefix + (row["token_id"],)
if row["q"] is not None:
assert 0.0 <= row["q"] <= 1.0
expected_predictor = (
PREFIX_FRONTIER if parent == -1 else parent
)
assert row["predictor_row"] == expected_predictor
mask = build_ancestor_mask(rows, prefix_len)
for u in range(len(rows)):
assert all(bool(mask[u, p]) for p in range(prefix_len))
for v in range(len(rows)):
should_see = is_ancestor(rows, ancestor=v, node=u) or u == v
assert bool(mask[u, prefix_len + v]) == should_see
def validate_commit(selected_rows, branch_cache, target_token_ids):
assert forms_single_root_to_node_path(selected_rows)
assert all(branch_cache[row].token_id == target_token_ids[row]
for row in selected_rows)
assert no_sibling_rows(selected_rows)
Additional release assertions:
tokenizer(target) == tokenizer(parametric_draft)
proposal checkpoint compatible with target version
retrieval corpus excludes protected evaluation material
probability semantics accepted by configured verifier
sampling relation accepted by configured verifier
tree node budget <= runtime temporary-state budget
verifier supports every proposal metadata type in the graph
exact mode never invokes heuristic acceptance
hardware profile matches deployed kernel/model/batch regime
proposal artifact hash binds topology + profile + policy
0x10 Design Decision Guide
Use prompt lookup when:
the workload contains repeated prompt material,
no additional model memory is acceptable,
and empty proposals can fall back cheaply.
Use REST-style retrieval when:
domain/code continuations repeat across requests,
a governed datastore is acceptable,
and CPU/index latency fits the target round.
Use a separate draft model when:
a well-aligned smaller checkpoint exists,
its weights and KV fit,
and native proposal probabilities simplify exact sampling.
Use self-speculation when:
duplicate model memory is the binding constraint,
the target exposes a useful shallow/skipped path,
and the runtime can keep provisional and authoritative state separate.
Use independent heads when:
parallel proposal latency matters most,
small sparse trees are sufficient,
and later-head consistency is acceptable.
Use dependent heads when:
later-depth proposal quality limits accepted length,
the added sequential head path is cheap,
and better paths permit a smaller verification tree.
Use hardware-aware trees when:
the proposer/verifier is stable enough to calibrate,
verification time is nonlinear in tree size,
and multiple candidate shapes can be compiled or captured.
0x11 Red Flags
"Draft source and verifier are interchangeable."
No. Proposal metadata constrains which exact verifier is valid.
"Dependent heads are simply more accurate Medusa heads."
They change the draft dependency graph and critical path.
"Retrieval is free because it has no neural model."
It adds index memory, query, trie, packing, and governance costs.
"Tree attention makes all candidate shapes equally cheap."
Node count, depth, topology, masks, kernels, and batch shape matter.
"Maximize acceptance length, then deploy the winner."
Optimize time per committed token under the actual runtime.
"A tree calibrated once is optimal forever."
Model, sampler, workload, kernel, batch, and hardware changes invalidate cost assumptions.
"The same token at the same depth is one reusable node."
No. Target state belongs to the complete causal prefix.
"A proposal score can stand in for q."
Only a normalized distribution generated under the verifier's assumed
sampling law can fill that role.
"SpecTr solves tree verification once and for all."
Its core transport problem selects among candidates at one target position;
recursive trees need conditional per-node contracts.
Source and implementation manifest
Claims in this article use four evidence classes:
source-local:
exposition and figures preserved from A30-A33
externally verified:
equations, algorithms, and training contracts in primary papers
implementation-observed:
data structures and runtime behavior in pinned official repositories
rewrite interpretation:
common ABI, semantic row compiler, release manifest, and toy oracles
Repository observations are intentionally narrower than paper claims. The official REST code grounds suffix search and tree buffers; Kangaroo grounds the adapter/early-exit structure; Hydra grounds rolled embeddings and per-depth path expansion; FlexFlow grounds one SpecInfer systems realization; Sequoia’s repository grounds the three-dimensional DP and hardware selector; Transformers grounds one prompt-lookup API. None of those snapshots proves behavior for a different commit or runtime.
0x12 Publish Gate
- Proposal source, topology, and verifier are separated.
- Probability semantics and sampling relation are negotiated explicitly.
- Candidate rows, predictor rows, and KV rows use distinct coordinates.
- Retrieval and prompt lookup are not treated as calibrated draft distributions.
- Retrieval corpus, tokenizer, index, and split lifecycle are versioned.
- Independent and dependent head factorizations are derived.
- Hydra, Hydra++, and Clover training/architecture choices are compared.
- Self-speculative state reuse is provenance-qualified.
- Equal token ids under different parents are never merged as target state.
- Multi-candidate exactness is derived beyond repeated one-draft tests.
- SpecTr one-position coupling is separated from recursive tree verification.
- SpecInfer tree buffers and target-state ownership are explicit.
- SpecInfer residual updates reproduce the target marginal in an executable oracle.
- Sequoia’s expected-tree score, depth-indexed DP, and reconstruction are derived.
- Hardware-aware deployment optimization requires measured verification cost; the local teaching profile is explicitly synthetic.
- Sequoia selected-child probabilities satisfy the sibling-mass budget, and expected progress respects the path-length bound.
- Tensor, pseudocode, cache, and release invariants are included.
- Source-reported benchmark claims are not generalized.
0x13 What This Unlocks
M7 now has the algorithmic pieces required to reason about a proposal system:
M7.1:
exact one-sequence draft/verify sampling
M7.2:
same-model heads and tree attention
M7.3:
Jacobi/lookahead proposal generation
M7.5-M7.6:
feature drafting and integrated causal MTP modules
M7.7:
source selection, dependent heads, multi-candidate selection,
and tree optimization
The remaining question is operational: how these rounds coexist across many requests, how speculative state is budgeted and scheduled, and how a production system proves a speedup without compromising output or rollback safety. That is the owner question for M7.8.
References
- Yaniv Leviathan, Matan Kalman, Yossi Matias. Fast Inference from Transformers via Speculative Decoding.
- Xiaoxuan Liu et al. Draft & Verify: Lossless Large Language Model Acceleration via Self-Speculative Decoding.
- Jiahao Liu et al. Kangaroo: Lossless Self-Speculative Decoding via Double Early Exiting.
- He Zhu et al. REST: Retrieval-Based Speculative Decoding.
- Tianle Cai et al. Medusa: Simple LLM Inference Acceleration Framework with Multiple Decoding Heads.
- Zachary Ankner et al. Hydra: Sequentially-Dependent Draft Heads for Medusa Decoding.
- Yuhui Yang et al. Clover: Regressive Lightweight Speculative Decoding with Sequential Knowledge.
- Xupeng Miao et al. SpecInfer: Accelerating Generative Large Language Model Serving with Tree-based Speculative Inference and Verification.
- Ziyi Yang et al. SpecTr: Fast Speculative Decoding via Optimal Transport.
- Benjamin Spector, Chris Re. Accelerating LLM Inference with Staged Speculative Decoding.
- Zhuoming Chen et al. Sequoia: Scalable, Robust, and Hardware-aware Speculative Decoding.
- Hugging Face. Assisted Decoding.
- Immi’s Workshop. A30 - Decoding Speculation.
- Immi’s Workshop. A31 - Medusa.
- Immi’s Workshop. A32 - Lookahead Decoding.
- Immi’s Workshop. A33 - DeepSeek MTP.
- FasterDecoding. REST official implementation.
- Equationliu. Kangaroo official implementation.
- Zachary Ankner et al. Hydra official implementation.
- FlexFlow. FlexFlow / SpecInfer implementation.
- Infini-AI-Lab. Sequoia official implementation.
- Hugging Face. Transformers pinned implementation.