Skip to content

[New model][DSv4] Serve DeepSeek-V4-Flash-Vision-Exp on SM12x Spark - #6

Merged
asterayx merged 15 commits into
mainfrom
cursor/dsv4-flash-vision-exp-df88
Sep 1, 2026
Merged

asterayx merged 15 commits into
mainfrom
cursor/dsv4-flash-vision-exp-df88

Conversation

@asterayx

@asterayx asterayx commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Purpose

Serve official deepseek-ai/DeepSeek-V4-Flash-Vision-Exp on the 2× DGX Spark (GB10 / SM121) stack that is already green for text-only DeepSeek-V4-Flash-0731.

This is not a duplicate of #1 / #2 / #3.

Upstream source: cherry-pick of vllm-project/vllm#54566.

Spark first-boot fixes on this branch:

  1. Allow DSpark k=5 when Vision-Exp n_predict=3 (0731 still uses this).
  2. VL wrapper inherits SupportsEagle3.
  3. Do not rewrite the DSpark draft back to the VL wrapper (SWA cache name collision).
  4. GB10 precompiled _moe_C.topk_softplus_sqrt is 10-arg. Detect the schema, keep the 10-arg hash path, overwrite image sentinel rows in Python.
  5. Graph-safe VL overwrite. Do not call image_mask.any() (host sync) during CUDA-graph capture.
  6. FlashInfer dual-cache prefill cubin is SWA topk=128 only. Slice text SWA to 128 and keep C4A. Image-widened rows drop C4A.
  7. Vision-Exp serve uses DSpark k=3, matching num_nextn_predict_layers=3. k=5 started at ~68% draft accept then fell to ~27% on the same text algorithm CoT that 0731 handled (positions 4/5 ~0.11/0.03). k=3 is next_n=4, a native SM12x decode width (no 5→6 pad). Capture 6 seqs × 4 = 24. ./docker/gb10/run.sh (0731) stays on k=5 / 36.

Test Plan

.venv/bin/python -m pytest \
  tests/utils/test_sm12x.py::test_sm12x_dspark_capture_avoids_q_len_5_dummy \
  tests/utils/test_sm12x.py::test_sm12x_align_flashinfer_dual_prefill_vision_width \
  tests/kernels/moe/test_topk_softplus_sqrt.py::test_legacy_kernel_overwrites_image_rows_with_bias_vl \
  tests/config/test_speculative_draft_hf_overrides.py \
  -v --noconftest

Test Result

Capture-size (k=5 set unchanged, k=3 → 4/8/12/16/24), dual-prefill align, and n_predict override tests passed. Spark e2e not run here (no SM121).

AI assistance

AI assistance was used (Cursor Grok 4.6). A human submitter must review every changed line and run the Spark serve before treating this as production-ready.

Open in Web Open in Cursor 

Isotr0py and others added 15 commits September 1, 2026 03:08
Signed-off-by: Isotr0py <Isotr0py@outlook.com>

Co-authored-by: asterayx <asterayx@users.noreply.github.com>
Signed-off-by: Isotr0py <Isotr0py@outlook.com>
Signed-off-by: Isotr0py <Isotr0py@outlook.com>
Signed-off-by: Isotr0py <Isotr0py@outlook.com>

Co-authored-by: asterayx <asterayx@users.noreply.github.com>
Keep DSpark: image sentinels are in-vocab reserved ids. Proxy
lm_head and MTP hidden states through the VL wrapper. Add
run-vision.sh for the official Vision-Exp checkpoint.

Co-authored-by: Cursor Grok 4.6
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
hf_config_override stamps n_predict from num_nextn_predict_layers.
Vision-Exp ships 3 MTP layers; the MTP reuse check then rejects
the proven Spark DSpark k=5 (5 % 3 != 0). DSpark drafts k tokens
in one pass, so drop that leftover n_predict on the V4 draft.

Co-authored-by: Cursor Grok 4.6
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Set dspark_draft_topk=None so MagicMock does not enter the
Qwen3 top-k validator.

Co-authored-by: Cursor Grok 4.6
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
After weight load, DSpark calls set_eagle3_aux_hidden_state_layers
on the target. The VL wrapper is not SupportsEagle3, so Spark
dies with "Model does not support EAGLE3 interface". Inherit the
protocol; defaults unwrap via get_language_model() to the text
backbone that already has EagleModelMixin.

Co-authored-by: Cursor Grok 4.6
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
SupportsEagle3 is a runtime_checkable Protocol with a ClassVar,
so issubclass() is not allowed.

Co-authored-by: Cursor Grok 4.6
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
The convertor maps vision_n_layers>0 to
DeepseekV4ForConditionalGeneration. After DSpark remaps the draft
to DSparkDraftModel, update_arch_() ran the convertor again and
rebuilt a second language_model stack. SWA cache names then
collided: language_model.model.layers.0.attn.swa_cache.

Skip the VL rewrite for DSpark/MTP draft archs and mark the V4
DSpark draft as _dsv4_vl_inner.

Co-authored-by: Cursor Grok 4.6
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Vision-Exp Python passes bias_vl into _moe_C.topk_softplus_sqrt,
but the Spark precompiled kernel only accepts 10 args. Detect the
schema, use the old call for text/hash, and overwrite image
sentinel rows in Python when the kernel has no bias_vl.

Co-authored-by: Cursor Grok 4.6
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
The 10-arg GB10 fallback overwrote image-sentinel rows in Python, then
bailed out with image_mask.any(). That host sync is illegal during
CUDA-graph capture and kills Vision-Exp serve right after dummy
warmup. Always apply the torch.where overwrite instead.

Co-authored-by: Cursor Grok 4.6
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
FlashInfer SM120 DSV4 dual-cache prefill is only instantiated for SWA
topk=128. Vision-Exp allocates window+vision_max_n_token (128+384=512)
even on text dummy rows, so the 8192-token autotune dummy launched
topk=512 + C4A extra and aborted. Slice text SWA to 128 and keep C4A.
Image-widened rows drop C4A and use the single-cache 512 cubin. 0731
(width 128) is unchanged.

Co-authored-by: Cursor Grok 4.6
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Vision-Exp ships num_nextn_predict_layers=3. Forcing k=5 matched 0731
but long text CoT acceptance fell from ~68% to ~27% (positions 4/5
near zero). Serve Vision with k=3 (next_n=4, a native SM12x decode
width). Capture 6 seqs x 4 = 24. 0731 run.sh stays on k=5 / 36.

Co-authored-by: Cursor Grok 4.6
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
${SPECULATIVE_CONFIG:-{...}} ended at the first `}` so vLLM saw
...probabilistic"}} and refused --speculative-config. Assign JSON
defaults with quoted literals instead. Same for CUGRAPH_CFG.

Co-authored-by: Cursor Grok 4.6
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
@asterayx
asterayx marked this pull request as ready for review September 1, 2026 08:12
@asterayx
asterayx merged commit ab04a79 into main Sep 1, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-01T08:13:26.293095Z d333818 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

cursor Bot pushed a commit that referenced this pull request Sep 1, 2026
…stack.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: asterayx <asterayx@users.noreply.github.com>
cursor Bot pushed a commit that referenced this pull request Sep 1, 2026
docker/gb10/run.sh and run-vision.sh expose /metrics on host port 30001
(rank 0 only). Default scrape target and docs now match that stack.

Co-authored-by: Cursor Grok 4.6 <cursoragent@cursor.com>
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants