fix: speculative verify with --mtp-draft > 2 commits wrong tokens#358
Merged
Conversation
metal_graph_verify_suffix_tops() asked ds4_gpu_indexer_topk_tensor() for the top-`top_rows` tokens of a single logits row (n_tokens=1, top_k=top_rows) instead of the top-1 of each of `top_rows` rows. The signature is (selected, scores, n_comp, n_tokens, top_k), so row_tops[i>0] came back as row 0 runner-ups and the verifier accepted or rejected drafts against the wrong rows, committing tokens the model never produced. Visible only at draft depth > 2: at depth 2 top_rows == 1 and the code takes the dedicated argmax path above this branch, so the swapped call is never reached. Adds tests/ds4_test.c --mtp-verify-depth: runs greedy speculative decode at draft 4 over a verbatim-copy task, then teacher-forces the committed tokens back through plain decode and asserts each is a (near-)argmax at its position. That is the invariant speculative verify must preserve, and unlike comparing whole token streams it tolerates the benign tie divergences of near-greedy speculation. Self-skips unless DS4_TEST_MTP points at an MTP GGUF. Without the fix a committed token sits ~21 logits below the argmax (worst gap 20.96 at token 145); with the fix every committed token is the argmax (gap 0.00). The shared test engine loads the MTP head only when DS4_TEST_MTP is set, and only on the fast engine, so the default suite and the quality engine are unaffected. Verified on M4 Max / Metal, DeepSeek-V4-Flash q2-q4 imatrix base + MTP-Q4K-Q8_0 head: make ds4_test DS4_TEST_MODEL=<base> DS4_TEST_MTP=<mtp> ./ds4_test --mtp-verify-depth Ran alongside --server --metal-tensor-equivalence --long-context: all pass. The swapped call site is backend-shared (ds4.c), so CUDA is affected and fixed identically, but this was not verified on a CUDA machine.
Owner
|
Thank you, merged. |
TrevorS
added a commit
to TrevorS/ds4
that referenced
this pull request
Jun 17, 2026
…upstream Single consolidated fork commit over antirez/ds4, tuned for DGX Spark (GB10, sm_121, unified memory, ~236 GB/s). Collapses the prior land/steering/python stack plus this session's batch-decode + managed-KV work into one commit. Engine (speed/accuracy, GB10): - MTP speculative decode: combined-forward verify, adaptive K=1/2 cascade (opt-in), deterministic verify default + DS4_CUDA_FAST_VERIFY fast path. - DS4_BATCH_DECODE (opt-in): route plain ds4_session_eval through the n=1 combined-verify batch forward (verify kernel set: expert-tile MoE, heads8 attention, cuBLAS f16). +21% plain decode @4k and @65k, token-identical in greedy + seeded-sampled testing (near-tie caveat, same as MTP combined). - managed-KV policy fix: ds4_gpu_should_use_managed_kv_cache always consults cudaMemGetInfo free memory instead of the context_bytes < 8 GiB blind spot that OOM-hung the box at 131k ctx with the model resident. - MoE expert-tile/rowspan kernels, atomic-free MoE down, Q8 residency cache, HBM hot-span device-copy with the _exps. filter, host-register, window attn. Product: - Multi-profile directional-steering cache + /v1/steering server admin API. - In-process Python ctypes bindings (libds4.so) exposing engine/session/steering. Validation + tooling: - CUDA correctness gate (tensor-equivalence, cuda-ppl, cpu-cuda-ppl) + primer. - gamut perf suite, longctx sweep harness, MTP retrain harness (v2 head), eugr N-runs mean+/-std methodology, ds4-bench --batch-cost/--batch-check, cascade A/B harness, thermal/memory-watchdog soak driver. Gates green: token-diff identity (greedy+sampled, 4k+65k), mtp-correctness worst_rms=0, mtp-selfconsistency maxabs=0, agent 86.5% accept / 21.9 t/s, no BOS spam. Rebased onto upstream cafc134 ("Fix server const warning"; +25 commits over base 59d9bc7: CUDA/ROCm SSD streaming + mixed-precision routed experts + loader refactor, MTP verify-topk fix antirez#358, agent raw-mode/edit fixes, server hardening). Conflict resolutions (4 files, 6 hunks): - ds4.c verify MoE: kept our verify_ordered_moe block, composed upstream's new DS4_ROCM_BUILD async-finish guard ahead of it. - ds4.c verify top-k (antirez#358): kept our per-row argmax loop over upstream's indexer_topk arg-swap fix; ours is correct + faster (avoids the ~17ms single-thread O(n_vocab) scan). Validated by upstream's own antirez#358 regression (test_mtp_verify_depth): worst_argmax_gap=0.000, max_chunk=5. - ds4_cuda.cu / tests / Makefile: union merges (both sides' additions kept). Post-rebase re-validation on GB10: build clean; fork-fixes intact (device-copy 8.20 GiB via _exps. filter, host-register 80.76 GiB, 344 dense f16 prewarms, managed-KV fix firing under tight free-mem); mtp-verify-depth/mtp-correctness (worst_rms=0)/mtp-selfconsistency (maxabs=0, bit-exact) all OK.
TrevorS
added a commit
to TrevorS/ds4
that referenced
this pull request
Jun 17, 2026
…upstream Single consolidated fork commit over antirez/ds4, tuned for DGX Spark (GB10, sm_121, unified memory, ~236 GB/s). Collapses the prior land/steering/python stack plus this session's batch-decode + managed-KV work into one commit. Engine (speed/accuracy, GB10): - MTP speculative decode: combined-forward verify, adaptive K=1/2 cascade (opt-in), deterministic verify default + DS4_CUDA_FAST_VERIFY fast path. - DS4_BATCH_DECODE (opt-in): route plain ds4_session_eval through the n=1 combined-verify batch forward (verify kernel set: expert-tile MoE, heads8 attention, cuBLAS f16). +21% plain decode @4k and @65k, token-identical in greedy + seeded-sampled testing (near-tie caveat, same as MTP combined). - managed-KV policy fix: ds4_gpu_should_use_managed_kv_cache always consults cudaMemGetInfo free memory instead of the context_bytes < 8 GiB blind spot that OOM-hung the box at 131k ctx with the model resident. - MoE expert-tile/rowspan kernels, atomic-free MoE down, Q8 residency cache, HBM hot-span device-copy with the _exps. filter, host-register, window attn. Product: - Multi-profile directional-steering cache + /v1/steering server admin API. - In-process Python ctypes bindings (libds4.so) exposing engine/session/steering. Validation + tooling: - CUDA correctness gate (tensor-equivalence, cuda-ppl, cpu-cuda-ppl) + primer. - gamut perf suite, longctx sweep harness, MTP retrain harness (v2 head), eugr N-runs mean+/-std methodology, ds4-bench --batch-cost/--batch-check, cascade A/B harness, thermal/memory-watchdog soak driver. Gates green: token-diff identity (greedy+sampled, 4k+65k), mtp-correctness worst_rms=0, mtp-selfconsistency maxabs=0, agent 86.5% accept / 21.9 t/s, no BOS spam. Rebased onto upstream cafc134 ("Fix server const warning"; +25 commits over base 59d9bc7: CUDA/ROCm SSD streaming + mixed-precision routed experts + loader refactor, MTP verify-topk fix antirez#358, agent raw-mode/edit fixes, server hardening). Conflict resolutions (4 files, 6 hunks): - ds4.c verify MoE: kept our verify_ordered_moe block, composed upstream's new DS4_ROCM_BUILD async-finish guard ahead of it. - ds4.c verify top-k (antirez#358): kept our per-row argmax loop over upstream's indexer_topk arg-swap fix; ours is correct + faster (avoids the ~17ms single-thread O(n_vocab) scan). Validated by upstream's own antirez#358 regression (test_mtp_verify_depth): worst_argmax_gap=0.000, max_chunk=5. - ds4_cuda.cu / tests / Makefile: union merges (both sides' additions kept). Also pruned dead cuda_model_range_is_cached (our own pre-rebase orphan; base had 3 refs, the loader rework left ours unreferenced) -> build warning-clean. Post-rebase re-validation on GB10: build clean; fork-fixes intact (device-copy 8.20 GiB via _exps. filter, host-register 80.76 GiB, 344 dense f16 prewarms, managed-KV fix firing under tight free-mem). All gates green: mtp-verify-depth (worst_argmax_gap=0.000, max_chunk=5), mtp-correctness (worst_rms=0), mtp-selfconsistency (maxabs=0, bit-exact), cuda-ppl (ppl=3.886775, delta=0.000000 vs committed baseline), cuda-tensor-equivalence (worst_rms=0.0052, no layer fails, nonfinite=0).
TrevorS
added a commit
to TrevorS/ds4
that referenced
this pull request
Jun 17, 2026
…upstream Single consolidated fork commit over antirez/ds4, tuned for DGX Spark (GB10, sm_121, unified memory, ~236 GB/s). Collapses the prior land/steering/python stack plus this session's batch-decode + managed-KV work into one commit. Engine (speed/accuracy, GB10): - MTP speculative decode: combined-forward verify, adaptive K=1/2 cascade (opt-in), deterministic verify default + DS4_CUDA_FAST_VERIFY fast path. - DS4_BATCH_DECODE (opt-in): route plain ds4_session_eval through the n=1 combined-verify batch forward (verify kernel set: expert-tile MoE, heads8 attention, cuBLAS f16). +21% plain decode @4k and @65k, token-identical in greedy + seeded-sampled testing (near-tie caveat, same as MTP combined). - managed-KV policy fix: ds4_gpu_should_use_managed_kv_cache always consults cudaMemGetInfo free memory instead of the context_bytes < 8 GiB blind spot that OOM-hung the box at 131k ctx with the model resident. - MoE expert-tile/rowspan kernels, atomic-free MoE down, Q8 residency cache, HBM hot-span device-copy with the _exps. filter, host-register, window attn. Product: - Multi-profile directional-steering cache + /v1/steering server admin API. - In-process Python ctypes bindings (libds4.so) exposing engine/session/steering. Validation + tooling: - CUDA correctness gate (tensor-equivalence, cuda-ppl, cpu-cuda-ppl) + primer. - gamut perf suite, longctx sweep harness, MTP retrain harness (v2 head), eugr N-runs mean+/-std methodology, ds4-bench --batch-cost/--batch-check, cascade A/B harness, thermal/memory-watchdog soak driver. Gates green: token-diff identity (greedy+sampled, 4k+65k), mtp-correctness worst_rms=0, mtp-selfconsistency maxabs=0, agent 86.5% accept / 21.9 t/s, no BOS spam. Rebased onto upstream cafc134 ("Fix server const warning"; +25 commits over base 59d9bc7: CUDA/ROCm SSD streaming + mixed-precision routed experts + loader refactor, MTP verify-topk fix antirez#358, agent raw-mode/edit fixes, server hardening). Conflict resolutions (4 files, 6 hunks): - ds4.c verify MoE: kept our verify_ordered_moe block, composed upstream's new DS4_ROCM_BUILD async-finish guard ahead of it. - ds4.c verify top-k (antirez#358): kept our per-row argmax loop over upstream's indexer_topk arg-swap fix; ours is correct + faster (avoids the ~17ms single-thread O(n_vocab) scan). Validated by upstream's own antirez#358 regression (test_mtp_verify_depth): worst_argmax_gap=0.000, max_chunk=5. - ds4_cuda.cu / tests / Makefile: union merges (both sides' additions kept). Also pruned dead cuda_model_range_is_cached (our own pre-rebase orphan; base had 3 refs, the loader rework left ours unreferenced) -> build warning-clean. Post-rebase re-validation on GB10: build clean; fork-fixes intact (device-copy 8.20 GiB via _exps. filter, host-register 80.76 GiB, 344 dense f16 prewarms, managed-KV fix firing under tight free-mem). All gates green: mtp-verify-depth (worst_argmax_gap=0.000, max_chunk=5), mtp-correctness (worst_rms=0), mtp-selfconsistency (maxabs=0, bit-exact), cuda-ppl (ppl=3.886775, delta=0.000000 vs committed baseline), cuda-tensor-equivalence (worst_rms=0.0052, no layer fails, nonfinite=0).
redhunt07
pushed a commit
to redhunt07/ds4-DSpark-GB10
that referenced
this pull request
Jul 11, 2026
…upstream Single consolidated fork commit over antirez/ds4, tuned for DGX Spark (GB10, sm_121, unified memory, ~236 GB/s). Collapses the prior land/steering/python stack plus this session's batch-decode + managed-KV work into one commit. Engine (speed/accuracy, GB10): - MTP speculative decode: combined-forward verify, adaptive K=1/2 cascade (opt-in), deterministic verify default + DS4_CUDA_FAST_VERIFY fast path. - DS4_BATCH_DECODE (opt-in): route plain ds4_session_eval through the n=1 combined-verify batch forward (verify kernel set: expert-tile MoE, heads8 attention, cuBLAS f16). +21% plain decode @4k and @65k, token-identical in greedy + seeded-sampled testing (near-tie caveat, same as MTP combined). - managed-KV policy fix: ds4_gpu_should_use_managed_kv_cache always consults cudaMemGetInfo free memory instead of the context_bytes < 8 GiB blind spot that OOM-hung the box at 131k ctx with the model resident. - MoE expert-tile/rowspan kernels, atomic-free MoE down, Q8 residency cache, HBM hot-span device-copy with the _exps. filter, host-register, window attn. Product: - Multi-profile directional-steering cache + /v1/steering server admin API. - In-process Python ctypes bindings (libds4.so) exposing engine/session/steering. Validation + tooling: - CUDA correctness gate (tensor-equivalence, cuda-ppl, cpu-cuda-ppl) + primer. - gamut perf suite, longctx sweep harness, MTP retrain harness (v2 head), eugr N-runs mean+/-std methodology, ds4-bench --batch-cost/--batch-check, cascade A/B harness, thermal/memory-watchdog soak driver. Gates green: token-diff identity (greedy+sampled, 4k+65k), mtp-correctness worst_rms=0, mtp-selfconsistency maxabs=0, agent 86.5% accept / 21.9 t/s, no BOS spam. Rebased onto upstream cafc134 ("Fix server const warning"; +25 commits over base 59d9bc7: CUDA/ROCm SSD streaming + mixed-precision routed experts + loader refactor, MTP verify-topk fix antirez#358, agent raw-mode/edit fixes, server hardening). Conflict resolutions (4 files, 6 hunks): - ds4.c verify MoE: kept our verify_ordered_moe block, composed upstream's new DS4_ROCM_BUILD async-finish guard ahead of it. - ds4.c verify top-k (antirez#358): kept our per-row argmax loop over upstream's indexer_topk arg-swap fix; ours is correct + faster (avoids the ~17ms single-thread O(n_vocab) scan). Validated by upstream's own antirez#358 regression (test_mtp_verify_depth): worst_argmax_gap=0.000, max_chunk=5. - ds4_cuda.cu / tests / Makefile: union merges (both sides' additions kept). Also pruned dead cuda_model_range_is_cached (our own pre-rebase orphan; base had 3 refs, the loader rework left ours unreferenced) -> build warning-clean. Post-rebase re-validation on GB10: build clean; fork-fixes intact (device-copy 8.20 GiB via _exps. filter, host-register 80.76 GiB, 344 dense f16 prewarms, managed-KV fix firing under tight free-mem). All gates green: mtp-verify-depth (worst_argmax_gap=0.000, max_chunk=5), mtp-correctness (worst_rms=0), mtp-selfconsistency (maxabs=0, bit-exact), cuda-ppl (ppl=3.886775, delta=0.000000 vs committed baseline), cuda-tensor-equivalence (worst_rms=0.0052, no layer fails, nonfinite=0).
iSevenDays
pushed a commit
to iSevenDays/ds4
that referenced
this pull request
Jul 17, 2026
fix: speculative verify with --mtp-draft > 2 commits wrong tokens
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.
Summary
In
metal_graph_verify_suffix_tops, the multi-row branch callsds4_gpu_indexer_topk_tensorwithn_tokensandtop_kswapped: it asks for the top-top_rowstokens of a single row instead of the top-1 of each oftop_rowsrows. The signature is(selected, scores, n_comp, n_tokens, top_k), sorow_tops[i>0]come back as row 0's runner-ups. At draft depth > 2 the verifier then accepts or rejects drafts against the wrong rows and commits tokens the model never produced.It only fires above the shipped depth: at
--mtp-draft 2,top_rows == 1takes the dedicated argmax path just above this branch, so the swapped call is never reached. So this is latent (it does not affect default output) but raising the draft depth gives silently wrong tokens (a spurious EOS or divergence), and nothing in the suite covered the multi-row verify path.Fix
Swap the last two arguments back (signature is
(selected, scores, n_comp, n_tokens, top_k)):Test
Adds
tests/ds4_test.c --mtp-verify-depth. It runs greedy speculative decode at draft 4 over a verbatim-copy task, then teacher-forces the committed tokens back through plain decode and requires each to be a (near-)argmax — the invariant speculative verify must preserve. Unlike comparing whole token streams, that tolerates the benign tie divergences of near-greedy speculation.The MTP head is not in the default test model set, so it self-skips unless
DS4_TEST_MTPpoints at an MTP GGUF:Without the fix a committed token sits ~21 logits below the argmax (worst gap 20.96 at token 145); with the fix every committed token is the argmax (gap 0.00).
Notes
--server --metal-tensor-equivalence --long-context; all pass.ds4_gpu_indexer_topk_tensorcall sites use the correct argument order; this was the only swapped one.