Repository navigation
[ROCm] EAGLE: a malformed draft probability must reject, not accept - #59
Merged
Merged
Conversation
The previous commit guards q in the two residual passes but not in the accept test itself, where it does the most damage: `coin * q < p` is -inf < p for an -inf q and 0 < p for a zero one, so a corrupt row accepts unconditionally and the committed token comes from the draft head rather than the target. That is the direction that costs output quality, and it is invisible -- acceptance climbing to 1.0 reads as a good draft model. Zero also passes the range test the residual passes use, so widening that guard alone does not cover this site. X was sampled from q, so q(X) has to be strictly positive; anything else means the row is not the distribution X came from. Reject on that, which sends the step through the residual path and resamples from the target. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
xiaobochen-amd
pushed a commit
that referenced
this pull request
Sep 15, 2026
) The previous commit guards q in the two residual passes but not in the accept test itself, where it does the most damage: `coin * q < p` is -inf < p for an -inf q and 0 < p for a zero one, so a corrupt row accepts unconditionally and the committed token comes from the draft head rather than the target. That is the direction that costs output quality, and it is invisible -- acceptance climbing to 1.0 reads as a good draft model. Zero also passes the range test the residual passes use, so widening that guard alone does not cover this site. X was sampled from q, so q(X) has to be strictly positive; anything else means the row is not the distribution X came from. Reject on that, which sends the step through the residual path and resamples from the target. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit 8d63553)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #58, which landed before this commit was pushed. #58 guards
qin the two residual passes; this guards it in the accept test, which is the site where a corrupt row does the most damage.Problem
coin * q < pis-inf < pfor an-infq and0 < pfor a zero one. Either way the step accepts unconditionally and commits the draft head's token instead of the target's. Zero also passes the(q >= 0) & (q <= 1)range test #58 added to the residual passes, so that guard does not cover this site.The failure is invisible from outside: acceptance climbing toward 1.0 reads as a good draft model, not as a broken test.
Fix
Xwas sampled fromq, soq(X)has to be strictly positive. Anything else means the row is not the distributionXcame from — reject, which sends the step through the residual path and resamples from the target.Scope
This code is only reached when EAGLE verify actually samples, which on ROCm requires sgl-project#37134 (
_verify_uses_greedy). On this repo'smain, which does not carry that patch,_is_hipineagle_utils.pystill forces the argmax branch unconditionally and the chain sampler is dead code — so this lands ahead of the path it protects, same as the rest of #58.Why it matters
Measured on a tree that does carry sgl-project#37134 (GLM-5.2-FP8, 8x MI355X, TP8, NEXTN
steps=1 draft=2, GPQA-Diamond 198q,temperature=1.0 top_p=0.95,max_tokens=98304):The same benchmark with speculative decoding switched off entirely scores 0.904 at 96.0% termination, so the fixed speculative path is back to parity with no speculation.
Cost, single request, 512 tokens with
ignore_eos, same hardware: -2.2% throughput attemperature=1.0(125.98 vs 128.76 tok/s), and nothing measurable attemperature=0(135.28 vs 135.66) whereis_all_greedysends verify down the argmax path regardless.🤖 Generated with Claude Code
CI States
Latest PR Test (Base): ❌ Run #34720143350
Latest PR Test (Extra): ❌ Run #34720143222
Latest PR Test (AMD ROCm 10): ❌ Run #34720143421