Skip to content

Add DeepSeek-V4-Flash-Vision-Exp support with sm80 (Ampere) fixes - #58

Open
kaka86mm wants to merge 10 commits into
wtdcode:masterfrom
kaka86mm:pr/vision-sm80
Open

Add DeepSeek-V4-Flash-Vision-Exp support with sm80 (Ampere) fixes#58
kaka86mm wants to merge 10 commits into
wtdcode:masterfrom
kaka86mm:pr/vision-sm80

Conversation

@kaka86mm

@kaka86mm kaka86mm commented Sep 2, 2026

Copy link
Copy Markdown

Summary

Adds full multimodal support for DeepSeek-V4-Flash-Vision-Exp on top of the dsv4-vision-exp branch, including three sm80-specific fixes that make it actually work on Ampere GPUs (CMP 170HX / A100).

What's included

From upstream vllm PR #54566 (cherry-picked):

  • Full VL model wrapper (vl_model.py, vl_stub.py)
  • Multimodal preprocessor with in-vocab sentinel tokens (mm_preprocess.py, common/vision.py)
  • Vision MoE routing with bias_vl (CUDA kernel + router changes)
  • In-image bidirectional attention (sparse SWA backend)
  • fix breakable cg — 2-line config fix for CUDA-graph text corruption
  • enable mtp — speculative decoding plumbing for VL

sm80 / Ampere fixes (new, tested on 4× CMP 170HX):

  1. PP input_ids relaybias_vl routing requires input_ids on all PP ranks, but non-first ranks only receive hidden states. Relays input_ids through IntermediateTensors broadcast (3 hunks in nvidia/model.py).
  2. DSpark embed on last rank — the drafter aliases the target embedding table on the last PP rank, but embed_tokens only builds on the first rank. Now builds it on the last rank when speculative decoding is active (+1 GB VRAM).
  3. Ampere attention routing — routes sm80 to the existing Ampere backend (ROCm Triton + fp8_sm80 software encode/decode) instead of crashing with fp8e4nv not supported.

Tested on

4× CMP 170HX (unlocked to 64GB each, GA100 sm80, PCIe Gen2 x4, PP4):

  • Text: Beijing / math / color all correct under FULL CUDA graphs
  • Vision: carrots.jpeg → "4 carrots" (1.4s), corn.jpeg → "corn" (0.8s)
  • Tool calling: get_weather({"city": "Beijing"}) with correct finish_reason
  • DSpark n=3: 49 tok/s shallow, 88–92 tok/s depth-flat to 366k
  • Agent concurrency: C16=497 tok/s aggregate
  • KV pool: 4.72M tokens (layer partition 12,11,11,9)

Notes for reviewers

  • The cg fix (5ab628dd1) is 2 lines in config/vllm.py + models/config.py — without it, text queries return content from unrelated requests under CUDA graphs
  • The PP relay is 3 small hunks; without it, bias_vl routing crashes with vision MoE routing requires input_ids on PP ranks 1-3
  • The embed-on-last-rank patch is required for DSpark under PP; without it, the drafter can't alias the embedding table

Not included (deliberately)

  • The upstream main merge (contains DeepGEMM hard gates unusable on sm80)
  • LMCache integration changes (orthogonal to vision support)

wtdcode and others added 10 commits August 31, 2026 21:06
DeepSeek-V4-Flash-Vision-Exp keeps the V4-Flash language backbone
unchanged (the config diff against 0731 removes nothing and adds only
the ten vision_* keys), but its checkpoint carries weights the text
model has no home for:

- a ViT, an aligner and four sentinel embeddings, and
- a per-layer vision expert bias `ffn.gate.bias_vl`, plus a plain
  `ffn.gate.bias` on the first num_hash_layers layers, which the
  text-only checkpoint omits because hash routing ignores it.

Drop the vision tensors and allocate the hash-layer gate bias so the
backbone loads and serves text from a vision checkpoint. The skip
mapper has to run before hf_to_vllm_mapper: its ".ffn.gate.bias"
substring rule also matches ".ffn.gate.bias_vl" and would rename it
into a parameter that does not exist.

Verified on 4x A6000 (TP4, fp8_ds_mla, 8k ctx): weights load, KV cache
and CUDA graphs build, and greedy text generation is coherent
(127*43 -> 5461, capital of France -> Paris).

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
A faithful port of the reference vision tower: a 32-block bidirectional
ViT over one image's 14x14 patches with 2D RoPE, followed by an aligner
that folds each 3x3 square of ViT tokens into one language-model token.
The tower is ~0.3B, so it is replicated per rank rather than sharded.

The rotary tables are built on CPU and then copied to the device. This
looks gratuitous but is load-bearing: building them on device costs one
fp32 ULP in cos/sin, and bf16 rounding compounds that across the 32
residual blocks into ~9e-2 of drift in the tower output (against a ViT
output std of ~1e-1). With CPU-built tables the port is bit-exact.

Checked against the reference implementation on
inference/examples/images/carrots.jpeg with the checkpoint's own
weights: a 42x61 patch grid encodes to [2562, 1024] and aligns to
[294, 4096], both bitwise identical to the reference.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Isotr0py <Isotr0py@outlook.com>
Signed-off-by: Isotr0py <Isotr0py@outlook.com>
Signed-off-by: Isotr0py <Isotr0py@outlook.com>
Signed-off-by: Isotr0py <Isotr0py@outlook.com>
Signed-off-by: Isotr0py <Isotr0py@outlook.com>
Signed-off-by: Isotr0py <Isotr0py@outlook.com>
@wtdcode

wtdcode commented Sep 2, 2026

Copy link
Copy Markdown
Owner

From what I would tell, vllm-project/vllm#54566 is not stable enough to backport so that's why I put it in a standalone branch at this moment.

@maglat

maglat commented Sep 6, 2026

Copy link
Copy Markdown

From what I would tell, vllm-project/vllm#54566 is not stable enough to backport so that's why I put it in a standalone branch at this moment.

the PR is merged in the meanwhile. Is it possible to adopt into your project?

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.

4 participants