feat(dflash): K=γ verify model orchestration + EAGLE ctx-accumulator contiguity fix#292
feat(dflash): K=γ verify model orchestration + EAGLE ctx-accumulator contiguity fix#292Sujimoshi wants to merge 8 commits into
Conversation
…4 lm_head Split out of Avarok-Cybersecurity#218 (DFlash speculative decoding for Qwen3.6-27B-NVFP4). Adds the model-level plumbing DFlash's draft/verify path needs: trait default no-op hooks (prefill_phase1_verify, prefill_gdn_wy16) for future verify-path PRs, a row-major K-row dflash_hidden_save capture buffer (dflash_hidden_save_rows, try_dflash_capture_draft/_all) so every accepted verify position gets its own target hidden instead of only rows 0/1, ctx_slot_positions on DflashProposerState to track true sequence positions across thinking-token gaps, an FP32 GDN output sibling buffer (gdn_buf_out_f32 / ATLAS_DFLASH_VERIFY_GDN_F32 prototype) and ssm_verify_h_tmp scratch, a dense_gemm_pipelined kernel for the draft head lm_head, and a RoPE fix for the drafter (config.json has rope_scaling=null; the prior YaRN-interpolated inv_freq corrupted positions and caused 0% accept rate — replaced with the standard 1/theta^(2j/dim) formula). Conflicts against main (which has evolved independently since Avarok-Cybersecurity#218 branched, most notably via Avarok-Cybersecurity#229's NVFP4 MMQ FFN + FlashInfer-GDN work) were resolved by keeping main's own additions (default_loops module, VARLEN-FLA batched methods, NVFP4 lm_head) intact and layering the DFlash-specific fields/methods alongside them, rather than reapplying the original patch wholesale. impl_a1.rs's misc-scratch block was extracted into impl_a1_init::build_misc_scratch (shared with the new gdn_buf_out_f32/ssm_verify_h_tmp allocations) to keep the constructor readable. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ot drafter's Found while GPU-testing this PR end-to-end on GB10: the DFlash lm_head NVFP4 fast path (w4a16_gemm) used the drafter's own (uncapped) vocab_size as the GEMM's N, but lm_head_nvfp4 is quantized against the target model's tokenizer-capped vocab_size, which can be smaller. On a checkpoint where the tokenizer caps vocab from 248320 to 248077, this read ~243 rows past the end of the packed weight/scale buffers, producing CUDA_ERROR_ILLEGAL_ADDRESS on the first DFlash proposal and poisoning the CUDA context for the rest of the process. Threads the target's capped config.vocab_size through build_model -> BlockDiffusionDraftHead::from_weights as a new lm_head_nvfp4_vocab_size field, and fixes both the GEMM call and the subsequent argmax loop (which shares the same row stride and had the same latent bug, though it wouldn't itself crash — just read the wrong row data). Re-verified end-to-end on GB10 with the same drafter checkpoint and target checkpoint that reproduced the original crash: 3 consecutive requests including the one that previously triggered the CUDA-700 poisoning now all complete cleanly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Soft-load dense_gemm_bf16_pipelined via try_kernel (unused in this PR, shouldn't hard-fail model load) - Make drafter RoPE config-driven (standard vs YaRN) based on config.json's rope_scaling field instead of hardcoding standard-only - Guard ctx_slot_positions push against max_ctx_len to stay in lockstep with ctx_len clamping; downgrade expected-case "ctx_len update skipped" log from warn to trace - Remove LM_HEAD_GEMM_LOGGED debug-session leftover (static + one-shot GEMM pointer dump) - Gate gdn_buf_out_f32 (FP32 GDN verify buffer) allocation behind ATLAS_DFLASH_VERIFY_GDN_F32 env var instead of always allocating Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The two new DFlash verify-scaffolding hooks pushed transformer_layer.rs to 535 LoC, tripping the file-size-cap CI gate. Condensed verbose doc comments (no logic changes) back to 492 LoC. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…1 conv, opt-in F32 GDN output Extracted from Avarok-Cybersecurity#218 (DFlash speculative decoding), stacked on Avarok-Cybersecurity#258 (model glue). SSM/GDN layer-level pieces of the K=γ verify path: - gated_delta_rule_wy16.cu: fused K=16 WY-chunkwise GDN verify kernel (+ F32-output variant) writing final h_state and Hi_0..Hi_14 intermediates in one pass; wired via prefill_gdn_wy16. - causal_conv1d_update_prefill_inter: batched phase-1 conv that also writes per-token conv_state intermediates for partial-accept rollback; wired via prefill_phase1_verify. - ATLAS_DFLASH_VERIFY_QKVZ_FIX (default ON): route the M=1 verify QKVZ projection through the same w4a16_gemv kernel serial decode uses (~2.29% rel_diff otherwise). - ATLAS_DFLASH_VERIFY_OUTPROJ_FIX (default ON): per-row w4a16_gemv out_proj for verify-window calls (≤17 tokens, native-NVFP4 builds only) to keep batched verify numerically aligned with serial decode (~2.26% rel_diff otherwise). Normal prefill chunks keep the shared GEMM dispatch. - ATLAS_DFLASH_VERIFY_GDN_F32 (opt-in): F32 GDN output in the split4 and wy16 verify branches, removing a BF16-truncation source. - decode_batched sequential K∉{2,3,4,17} fallback extracted to conv_gdn_sequential.rs; prof!-instrumented decode GDN/norm launches. - mod.rs: TransformerLayer impl moved to trait_transformer_impl.rs (500-LoC cap). Deviations from Avarok-Cybersecurity#218 as-authored, due to main's independent evolution: qkvz/out_proj projection ladders were replaced on main by shared dispatch helpers (prefill_qkvz_proj / prefill_out_proj_dispatch) that now carry the CUTLASS-NVFP4 and FP8 branches, so the verify fixes are layered as guarded pre-branches instead of reapplying Avarok-Cybersecurity#218's inline ladders; the out_proj fix is additionally gated to ≤17-token calls because phase3 is now also the hot batched-prefill path. NVTX instrumentation is left to Avarok-Cybersecurity#255. 218's trait_prefill_gdn_batched.rs and qkvz_projection.rs extractions were dropped — main since made its own supersets of both. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…contiguity fix Extracted from Avarok-Cybersecurity#218 (DFlash speculative decoding), stacked on Avarok-Cybersecurity#290 (SSM-layer verify kernels). Model-level orchestration of the K=γ verify path plus a correctness fix for the drafter's context accumulator: - verify_d_kgamma_layers.rs / verify_d_kgamma_attn_meta.rs: per-layer K=γ forward loop and batched attention metadata, extracted from verify_d.rs to keep it under the 500-LoC cap. - dflash_append.rs: EAGLE ctx-slot append dispatchers (dflash_accept_append / dflash_eagle_accept_append / dflash_eagle_kgamma_append) plus dflash_decode_ctx_append_dispatch, called unconditionally at the end of every decode() step so the drafter's ctx accumulator stays contiguous even across stretches where DFlash itself is gated off (e.g. inside a <think> block). Wires the accompanying `skip_next_decode_append` one-shot flag on `DflashProposerState` (new field) so propose()'s own internal decode-append doesn't double-append a row already appended by one of the eagle dispatchers. - verify_a.rs / verify_b.rs / verify_d.rs: wiring for the above plus the K=γ dispatch path (decode_verify_graphed_kgamma_dispatch). Deviations from Avarok-Cybersecurity#218 as-authored, due to main's independent evolution: NVTX instrumentation (verify_step, per-layer/per-phase ranges, d2h_argmax_readback) stripped throughout — left to Avarok-Cybersecurity#255, not yet merged into this stack. prefill_b/batch_kernel.rs and prefill_c.rs had their own `output_f32`/`output_f32_written` GdnPrefillBuffers fields already (from Avarok-Cybersecurity#290's F32-GDN-output work); Avarok-Cybersecurity#218's patch tried to add the same fields again verbatim — kept the existing (real, in prefill_c.rs's case non-null) values and dropped the duplicates. Test plan: cargo check/fmt/clippy/LoC-cap all green on this branch tip. GPU validation on GB10 (Qwen3.6-27B-NVFP4 + DFlash draft, T=0) pending — will report accept-rate/divergence vs the Avarok-Cybersecurity#290 baseline (byte 634) and whether this fixes the previously-observed 0/16 accept collapse on the forced K=γ path (ATLAS_DFLASH_DRAFT_CAP override), since that collapse predates this ctx-accumulator fix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
[BETA] Automated PR review — SeedSource AI pipelineAdvisory only, not a merge gate. AI-generated (internal risk-triage, Atlas serve gate, GLM-5.2 review), attributed per Atlas convention. Triage
Serve gate
GLM-5.2 code reviewThe diff is truncated mid-file ( Concerns:
Risk: Medium — the vocab-size fix addresses a real OOB, but the truncation hides whether the consumer side uses it correctly. Request full diff for Pipeline: build+serve on GB10, GLM-5.2 via NVIDIA NIM, internal risk-triage classifier. External diff treated as untrusted input. Public repo. |
Summary
Next cluster from the #218 split ("DFlash K=γ correctness + throughput optimizations"). Wires the SSM-layer K=γ verify kernels landed in #290 into the model's verify/decode/append orchestration layer.
Stacked on #290 (which stacks on #258) — merge order: #258, #290, then this.
Contents (
crates/spark-model/src/model/trait_impl/):verify_d.rs,verify_d_kgamma_layers.rs(new),verify_d_kgamma_attn_meta.rs(new) — K=γ verify step implementation using the WY16 GDN kernel and batched phase-1 conv from feat(dflash): SSM-layer K=γ verify kernels — WY16 GDN, batched phase-1 conv, opt-in F32 GDN output #290.dflash_append.rs(new) — EAGLE ctx-slot append dispatchers:dflash_accept_append,dflash_eagle_accept_append,dflash_eagle_kgamma_append, plusdflash_decode_ctx_append_dispatch.decode_a.rs— callsdflash_decode_ctx_append_dispatchunconditionally at the end of everydecode()step (both CUDA-graph-replay and non-graph paths), fixing a real bug: the EAGLE ctx accumulator (ctx_hidden_acc) previously only advanced from the DFlash verify/propose path, so when DFlash gating turned off for a stretch (e.g. inside a<think>block) and resumed, the drafter's first post-resumepropose()conditioned on stale/non-contiguous history.verify_a.rs,verify_b.rs,prefill_b/batch_kernel.rs,prefill_c.rs,mod.rs— supporting wiring (new trait methods, batch-kernel/prefill hookups).crates/spark-model/src/layers/dflash_head.rs/propose.rs— minimal addition: askip_next_decode_appendone-shot flag onDflashProposerState, set by the newdflash_append.rsdispatchers when they've already appended the relevant ctx row(s) beforepropose()runs, and consumed bypropose_draftsto avoid double-appending. Scoped narrowly — the rest ofdflash_head/propose.rs(the "dflash_head core" cluster:last_num_accepted, forward_block changes, etc.) is left for a later PR in the stack.Deviations from #218 as-authored
nvtx_diag::NvtxRangespans inverify_d.rs/verify_d_kgamma_layers.rs) stripped — that module doesn't exist yet on this stack (belongs to perf(spark-runtime): opt-in NVTX kernel-attribution + phase-timing instrumentation #255, not yet merged). Substantive comments explaining sync/D2H safety were kept, just de-framed from "NVTX stage" language.GdnPrefillBuffersstruct-literal duplicateoutput_f32/output_f32_writtenfields (added independently by both feat(dflash): SSM-layer K=γ verify kernels — WY16 GDN, batched phase-1 conv, opt-in F32 GDN output #290 and dflash: DFlash K=γ correctness + throughput optimizations (verify 585→269ms, tok/s 2.9→22) #218's original diff at the same call sites) de-duplicated inprefill_b/batch_kernel.rsandprefill_c.rs, keeping the real wired value inprefill_c.rs.Test plan
cargo check -p spark-model/cargo check --workspacecargo fmt --all -- --checkcargo clippy --workspace --tests(crate-wide#![deny(clippy::all)])ATLAS_DFLASH_DRAFT_CAP=16): CUDA graph captures correctly (K=17slot), but accept rate remains 0/16 (0%) across all verify calls — identical to feat(dflash): SSM-layer K=γ verify kernels — WY16 GDN, batched phase-1 conv, opt-in F32 GDN output #290's pre-existing finding, unchanged by this PR's ctx-accumulator fix. Confirms the K=γ 0%-accept collapse is NOT caused by ctx-accumulator discontiguity; root cause remains the deeper SSM state-management mismatch for K∉{2,3,4} already documented inpropose.rs's safety-cap comment. Tracked as a separate, still-open issue — out of scope for this PR.🤖 Generated with Claude Code