Repository navigation
npu: the draft loop commits a verify prefix instead of rolling back, and gates the chain on tau - #798
Conversation
…and gates the chain on tau Two changes to the speculative loop, both from how this is done elsewhere (reference only, nothing copied): 1. DEFERRED COMMIT. A verify batch leaves k rows of state behind and only the accepted prefix survives. A state snapshot per iteration would cost ~100 MB at 400 tokens, and attention needs no rollback at all -- it is position-indexed and the caller supplies pos. The state that cannot be re-indexed is a GDN layer's recurrence, so instead of rolling it back the verify pass defers it: the rows store their recurrence inputs and BaseModel::commit_verify(accepted) applies exactly the accepted rows, dropping the rest. Nothing is recomputed and nothing is snapshotted; the cost is k rows of update inputs, not a state copy. truncate() is gone from the interface: a base that cannot defer reports it from commit_verify() rather than pretending the state is consistent. 2. TAU GATE. The draft chain continues only while the drafter's own probability is at least tau (0.6, the published setting for this head); the first below-tau draft is still verified -- it is in the batch anyway -- but nothing is drafted after it. DraftHead::draft() gains an optional confidence out-parameter; a head that cannot report it leaves it empty and the gate is skipped for that iteration rather than guessed. Checked on the toy base (69 assertions, all green): emitted text still identical to plain greedy decode in every case; the loop commits exactly the accepted prefix and leaves no verify rows uncommitted; and with tau=0.6 a low-confidence head's rows-verified drops from 192 to 24 over the same 24 emitted tokens -- the gate is what keeps a weak drafter from paying for a full-width batch every iteration.
PR Reviewer Guide 🔍(Review updated until commit a77f9c9)Here are some key observations to aid the review process:
|
|
Persistent review updated to latest commit a77f9c9 |
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT: READY
At a77f9c91 (update-branched; its two files byte-identical to 53334b09, git diff --stat → empty), build green. Built and
ran the suite rather than reading the claim:
$ ninja mtp_draft_test && ./mtp_draft_test
INFO k=8 perfect: iterations=3 steps=3 batches=3 emitted=24 accepted=24 passes/token=0.250
INFO k=8 garbage: passes/token=2.000 (plain decode = 1.000), rows verified=24
PASS tau gate: text still identical to plain decode
PASS tau gate: a below-tau first draft is verified alone (1 row per iteration)
INFO tau=0.6 garbage head: rows verified=24 over 24 iterations, passes/token=2.000
PASS commit: no verify rows left uncommitted at the end
PASS commit: the last commit was a prefix of the verified rows
INFO half head k=4: commits=12 last_commit=1 accepted=12 drafted=24
all checks passed
So both changes carry their own assertions rather than being described: "the last commit was a prefix of the verified rows"
is the property the deferred commit has to have, and "a below-tau first draft is verified alone" is the tau gate behaving
with a head that has nothing confident to add. The old k=8 numbers are unchanged (0.250 optimistic / 2.000 worst), which is
what a gate that only stops drafting early should do.
Two design points I checked in the code, because they are the ones that could be quietly wrong:
- removing
truncate()fromBaseModeland makingcommit_verify(accepted)the only path is the right shape: a base that
cannot defer now says so fromcommit_verify()instead of leaving the caller to believe the state was rewound. Attention needs
nothing (position-indexed, caller suppliespos), and the GDN recurrence is exactly the state that cannot be re-indexed, so
deferring k rows of update inputs (kilobytes) instead of a ~100 MB snapshot is the cheap correct answer. - the confidence out-parameter is optional: a head that cannot report a probability leaves it empty and the gate is skipped
for that iteration rather than guessed — so a weak drafter degrades to the old behaviour instead of being silently gated on a
number nobody produced.
And the scoping note is honest: the 4-row verify with leaf fill is a tree on top of this loop and stays out; the acceptance
figures will be reported as "chain + tau, width k" so they are not confused with the tree numbers. tprs-ready applied.
Two changes to the speculative loop in
npu/mtp/draft.h(the loop itself is #785; this is what makes a rejected draftcheap and keeps a weak drafter from over-drafting). Reference only — the designs come from other people's published
numbers, nothing is copied.
1. Deferred commit instead of rollback. A verify batch leaves k rows of state behind and only the accepted prefix
survives. A state snapshot per iteration would cost ~100 MB at 400 tokens, and attention needs no rollback at all — it is
position-indexed and the caller supplies
pos. The state that cannot be re-indexed is a GDN layer's recurrence, soinstead of rolling it back the verify pass defers it: the rows store their recurrence inputs, and
BaseModel::commit_verify(accepted)applies exactly the accepted rows and drops the rest. Nothing is recomputed andnothing is snapshotted; the cost is k rows of update inputs (kilobytes), not a state copy.
truncate()is gone from theinterface: a base that cannot defer says so from
commit_verify()rather than pretending the state is consistent.2. Tau gate on the chain. Drafting continues only while the drafter's own probability is at least
tau(0.6 — thepublished setting for this head). The first below-
taudraft is still verified (it is in the batch anyway), nothing isdrafted after it.
DraftHead::draft()gains an optional confidence out-parameter; a head that cannot report it leaves itempty and the gate is skipped for that iteration rather than guessed.
Checked on the toy base — 69 assertions, all green (
ctest -R mtp_draft):The 4-row verify with leaf fill that the published numbers use is a tree on top of this loop (spare rows carry the
drafts' 2nd/3rd candidates); it needs the per-row banks the note in the header describes, so it stays out of this PR —
--kand the tau gate are the honest subset the 08:00 measurement can use, and the acceptance figures will be reportedas "chain + tau, width k" so they are not confused with the tree numbers.
Not merged here.