forked from sgl-project/sglang
-
Notifications
You must be signed in to change notification settings - Fork 0
JetSpec tree drafting on DFlash — lossless; width=1 clean drop-in #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
vincentzed
wants to merge
41
commits into
main
Choose a base branch
from
jetspec-tree-draft
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
42d57f1
Add JetSpec tree drafting for DFlash
vincentzed 1fe1175
Fix DFlash tree live validation issues
vincentzed 8f9e732
WIP checkpoint: DFlash tree verify — dense lossless, MoE in progress
vincentzed 6dd0f39
WIP checkpoint 2: MoE tree verify narrowed to prompt-4 holdout
vincentzed 7c80ee7
Fix DFlash tree Mamba commit guard
vincentzed fcda4ef
Record DFlash tree Job 0 status
vincentzed 5817fc9
Make DFlash MoE tree verify lossless
vincentzed 5c2120c
Record DFlash tree Job 1 status
vincentzed 11c65c0
Enable DFlash tree cuda graph verify
vincentzed ff27559
Record DFlash tree Job 2 status
vincentzed e8d533a
Document DFlash tree cuda graph perf
vincentzed c1499d7
Record DFlash tree Job 3 status
vincentzed e9c1269
docs: record dense dflash tree perf sweep
vincentzed dd1cc29
dflash: make dense tree verify compact by default
vincentzed e7dd3d4
jetspec: record canonical compact tree benchmark
vincentzed c4255a5
jetspec: record EAGLE-parity attempt + localize dense reverify cause
vincentzed 35f4c49
dflash: keep fa4 page16 for baseline
vincentzed 4d4a5f0
docs: record fa4 tree verify finding
vincentzed 2bc08a7
docs: record fa4 mtbench benchmark
vincentzed 11a29da
Diagnose DFlash FA4 tree mask mismatch
vincentzed fb09f49
Fix DFlash FA4 tree mask verification
vincentzed 077c8bc
Record DFlash FA4 no-reverify benchmarks
vincentzed 18ead1a
Record JetSpec paper dataset DFlash benchmarks
vincentzed b101fa1
Cuda graph compact FA4 tree verify
vincentzed 06f498d
Fix b255 compact FA4 tree verify losslessness
vincentzed cbff217
Update DFlash final rebench results
vincentzed 313e627
Profile DFlash tree decode hotspots
vincentzed 2fa912f
Add top2gap DFlash tree construction
vincentzed 80c073a
Record lean top2gap DFlash sweep
vincentzed a696e2e
Optimize DFlash tree metadata and KV commit
vincentzed e04fd9c
Reduce DFlash compact tree metadata overhead
vincentzed fdba66e
Use kernel tree accept for DFlash compact verify
vincentzed b107deb
Record DFlash tree verifier residual blocker
vincentzed 14fc414
Add FA4 exact DFlash paged tree verify
vincentzed 00b126f
Wire FA4 paged DFlash tree verify
vincentzed d495bcc
Record final DFlash paged verify gate
vincentzed cbbf89d
docs: record paged tree verifier ab finding
vincentzed aa0236d
docs: record DFlash AR oracle re-gate
vincentzed 0a60011
docs: record DFlash JetSpec profile matrix
vincentzed 77584d7
jetspec: PR cleanup — untrack run/profile/log artifacts, add README +…
vincentzed f9b4fc7
jetspec: include canonical MoE command + top2gap sweep harness
vincentzed File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| runs/ | ||
| profiles/ | ||
| logs/ | ||
| *.pid | ||
| *.nsys-rep | ||
| *.trace.json.gz | ||
| _ref/ | ||
| _oldattempt/ | ||
| _hf_configs/ | ||
| baseline_linear.json |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| # JetSpec tree drafting on SGLang DFlash | ||
|
|
||
| Extends SGLang's linear DFlash speculative decoding with **parallel tree drafting** (JetSpec): the DFlash draft head's per-depth block logits feed a token **tree** (top2gap construction), verified under a tree-causal mask. `tree_width=1` is the unchanged linear path; `width>1` is the new tree path. | ||
|
|
||
| ## What this delivers | ||
|
|
||
| - **Lossless tree spec-decode** (token-exact vs linear DFlash), dense Qwen3-8B + MoE Qwen3.6-35B-A3B, cuda-graphed, EAGLE-parity direct commit (no reverify). | ||
| - **`top2gap` construction** — per-depth fanout from the top-1/top-2 logprob gap (branch where the drafter is uncertain, chain where confident). Reproduces the paper's accept length at a fraction of the budget. | ||
| - **`width=1` is a byte-identical, near-zero-overhead drop-in** for linear DFlash. | ||
| - A proven FA4-exact paged-tree verify kernel (opt-in, default-off) + a full break-even / profiling analysis. | ||
|
|
||
| ## Full speedup matrix (Qwen3-8B, B300, FA4 + page_size 16, greedy) | ||
|
|
||
| | Config | GSM8K tok/s | vs DFlash | MATH-500 tok/s | vs DFlash | accept (G / M) | lossless | | ||
| |---|---:|---:|---:|---:|---:|:--:| | ||
| | **DFlash w1 (native linear)** | **1170.5** | 1.00× | **1522.1** | 1.00× | 5.85 / 7.62 | baseline | | ||
| | linear JetSpec (width=1) | 1152.4 | **0.985×** | 1488.6 | **0.978×** | 5.85 / 7.62 | ✓ exact | | ||
| | compact tree (top2gap w8/b16) | 1002.2 | 0.856× | 1167.5 | 0.767× | 6.45 / 7.90 | ✓ exact | | ||
| | paged tree (w8/b16) | 900.2 | 0.769× | 1060.7 | 0.697× | 6.50 / 8.02 | ✗ (default-off) | | ||
|
|
||
| - vs **AR-greedy** (the paper's baseline): every spec config is ~4–9× faster — that comparison is trivially won and not the interesting bar. | ||
| - The interesting bar is **SGLang's linear DFlash**, which is already FA4 + cuda-graph + fused-kernel optimized. | ||
|
|
||
| ## Why the tree could not improve further (the honest result) | ||
|
|
||
| - **Break-even rule:** tree beats linear iff `accept_ratio > step_cost_ratio`. The tree verify costs **~1.29× (compact) / 1.44× (paged)** per step at equal node count, so it needs that much more acceptance to win. | ||
| - **The accept gain is too small:** tree gives **+0.6 (GSM8K) / +0.28 (MATH)** accept over linear; break-even needs **+1.5 / +2.4**. The draft head's tree just doesn't concentrate enough probability to clear the verify overhead. | ||
| - **Construction was maxed** (top2gap is the reference's sweep-winning algorithm) and **the paged kernel is a net loss** (it removes the K/V gather but a different memory layout adds attention time *and* breaks bit-exactness vs the compact verify — fp non-associativity flips greedy near-ties). | ||
| - **The paper's own tree is slower than SGLang's linear** (paper 984/1150 tok/s vs our linear 1170/1522), so "beat SGLang linear DFlash" is a strictly harder bar than the paper's published speedup (which is vs AR-greedy). Conclusion: against an already-SOTA linear baseline, tree drafting trades verify cost for accept length and nets out **below linear** on throughput. | ||
|
|
||
| ## The good news: width=1 is a clean drop-in | ||
|
|
||
| - **Linear JetSpec (width=1) is within ~1.5–2% of native DFlash** (1152 vs 1170, 1489 vs 1522) and **token-exact** — i.e. within measurement noise. | ||
| - That means the tree code path adds **negligible per-step overhead when not used**, so the feature is safe to land: it never regresses the linear DFlash path, and `width>1` is available for workloads where verify is cheaper or the draft head concentrates better (e.g. weaker/AR baselines, or future paged-engine work). | ||
|
|
||
| ## Reproduce | ||
|
|
||
| ```bash | ||
| python jetspec/bench_paper_sglang.py # GSM8K / MATH-500, configurable width/budget | ||
| bash jetspec/run_dflash_gate_bench.sh # losslessness gate vs fresh linear oracle | ||
| ``` | ||
|
|
||
| Detailed run-by-run notes: `jetspec/notes/bench_results.md`; status: `jetspec/STATUS.md`. |
Large diffs are not rendered by default.
Oops, something went wrong.
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| # Old attempt (realtree) — handoff artifacts | ||
|
|
||
| The previous Codex run removed the branch-reverify band-aid and implemented the REAL target | ||
| tree verify, but stopped (interrupted) before it was fully lossless. It got VERY close and | ||
| isolated the bug. Use this to continue — do NOT start over. | ||
|
|
||
| ## State of the code (already in the working tree, compiles cleanly) | ||
| WIP edits (also backed up as `jetspec/_oldattempt/realtree_wip.patch`) touch: | ||
| - `python/sglang/srt/speculative/dflash_worker_v2.py` (325-line rework: real tree verify, band-aid removed) | ||
| - `python/sglang/srt/layers/attention/hybrid_linear_attn_backend.py` (route DFlash tree through the topk>1 verify path) | ||
| - `python/sglang/srt/model_executor/runner/decode_cuda_graph_runner.py`, `base_runner.py`, `eager_runner.py`, `model_runner.py` (cuda-graph wiring for tree decode) | ||
| - `python/sglang/srt/speculative/{dflash_info.py,dflash_tree_utils.py,spec_info.py}`, test file | ||
|
|
||
| ## THE KEY FINDINGS (save you hours) | ||
| 1. **`jetspec/baseline_linear.json` is STALE** — it was captured under a different launch | ||
| mode/config (flashinfer attn / graph state). The CURRENT width=1 linear DFlash (no-graph) | ||
| does NOT match it. So DO NOT gate losslessness against `baseline_linear.json`. | ||
| **Use `jetspec/runs/8b_linear_current_nograph_31216.json` as the current-code 8B linear | ||
| oracle** (recaptured from the exact current code/launch). Several earlier "mismatches" | ||
| (incl. all of prompt 0) were FALSE ALARMS from the stale baseline. | ||
| 2. **Against the fresh oracle, the real remaining bug is OVER-ACCEPTANCE in the tree-greedy | ||
| accept path**, reproducing on 8B w7/b64 at **prompts 3, 5, 9 only** (first diffs ~@51/@36/@9). | ||
| "Over-acceptance" = the tree accept commits a branch token the target's own greedy argmax | ||
| would NOT have produced. Prompt 5's first diff is a simple duplicate token — easiest to trace | ||
| the bad accept chunk. This is an accept-selection / node-gating bug, NOT a draft-tree, KV, or | ||
| mask-construction bug (cap=0 root-only verification was internally consistent). | ||
|
|
||
| ## What was tried (don't repeat) | ||
| - cachefix / tritonattn / nograph variants — all still failed because they were compared vs the | ||
| STALE baseline; the real comparator is the fresh oracle above. | ||
| - cap=0 (root-only tree) — confirmed the divergence is in accept logic, not deeper tree rows. | ||
|
|
||
| ## Failing-run artifacts | ||
| `jetspec/runs/8b_tree_w7_b64_realtree*.json`, `..._debug_prompt0_*.json` — contain per-prompt | ||
| `losslessness.mismatches` with first_diff positions. | ||
|
|
||
| ## The fix to make | ||
| Match the accept semantics of the reference tree verify in | ||
| `jetspec/_ref/JetSpec/jetspec/core/tree_attention_kernel.py` and the verify stack in | ||
| `jetspec/_ref/JetSpec/jetspec/inference_engine/compiled_verify_stack.py` / | ||
| `paged_tree_attn.py`. The over-acceptance is almost certainly in how the accepted path is | ||
| selected from the target's per-node logits (greedy: accept child c at node n iff | ||
| target_argmax(logits[n]) == draft_token(c); stop at first node whose best child != target argmax). | ||
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Claimed
realtree_wip.patchfile does not exist in the repository. The note says WIP edits are backed up there, but the file is absent, making this reference misleading.Prompt for AI agents