Fix DeepSeek-V4/DeepSeek-V4-Pro DP-attention gather semantics - #31700
Conversation
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
/tag-and-rerun-ci |
d92ba3c to
c7f0930
Compare
|
/rerun-failed-ci |
a873bc9 to
68d70aa
Compare
|
/rerun-failed-ci |
|
/rerun-test test_moe_ep.py |
|
Results for 🚀 |
|
/rerun-test test_moe_ep.py test_moe_ep_extra.py |
|
Results for 🚀 |
|
/rerun-test test_deepep_small.py |
|
|
/rerun-test test_deepep_small.py |
|
Results for 🚀 |
3cb3183 to
c538e04
Compare
|
/rerun-failed-ci |
|
/rerun-failed-ci |
|
All NV pipelines have passed. @ch-wan could you help to review and merge? Thanks! |
Motivation
Fixes #31699.
DeepSeek-V4 DP-attention produces numerically invalid output when
moe_a2a_backend=none,data_parallel_size>1, andattn_tp_size>1.By the time the MoE gather runs,
self_attnhas already reduced its outputacross the attention-TP group. The hidden states are therefore replicated
across attention-TP ranks.
The existing
dp_gather_partialcalls treat those tensors as unreduced partialcontributions. Their reduce-scatter sums the replicated values, multiplying the
hidden-state magnitude by
attn_tp_sizeat every MoE layer.The same replicated-versus-partial distinction applies to the NextN input-ID
gather.
Modifications
dp_gather_replicatefor the normal post-attention hidden-state gather.dp_gather_replicatefor the NextN input-ID gather.MAX_LEN implementation can zero its local input on non-leader attention-TP
ranks, and
input_ids[:, None]otherwise aliases the caller-owned tensor.The hidden-state inputs are not cloned because they are dead after their
gathers; cloning those large activations once per layer would add unnecessary
overhead.
Reproduction
Environment
The captured A/B used:
nvidia/DeepSeek-V4-Pro-NVFP4a9cf5e68elmsysorg/sglang:nightly-dev-cu13-20260715-50d1edaamoe_a2a_backendomitted, so it defaults tononeSGLANG_SHARED_EXPERT_TP1=1--enable-dp-lm-head, to exclude the LM-head path as a confounding variable--quantization; checkpoint quantization is auto-detectedThe same failure was independently reproduced with attention TP8 x DP2 and on
two hosts with 8 H100 GPUs each.
The PR diff applies cleanly to the tested
a9cf5e68erevision. Use theunmodified revision for the failing run and the same revision with this PR diff
applied for the passing run. Keep the checkpoint and every launch argument
identical.
Stage the checkpoint on a login or transfer host, not in the GPU allocation:
The model and source checkout must be visible at the same paths on both GPU
hosts.
Run one
sglang.launch_serverprocess on each host. Both processes use global--tensor-parallel-size 16; this is 16 total ranks across the two hosts, not 16GPUs per host.
On host 0:
On host 1:
Then run this command inside the SGLang container/environment on both hosts:
Do not pass
--quantizationor--moe-a2a-backend.Once host 0 reports ready, send:
For attention TP8 x DP2 on the same 16 GPUs, change only
--data-parallel-size 4to--data-parallel-size 2.A single 8-GPU H200 host can run flat TP8, but flat TP does not exercise this
DP-attention gather and is not the demonstrated reproduction.
Accuracy Tests
Before: unpatched source fails
The unpatched server reports healthy and returns successful, well-formed JSON,
but the generated content is numerically corrupted.
For
What is the capital of France?attemperature=0, captured pre-fixcontent included:
For
What is 4 times 5 plus 2? Answer with just the number.the pre-fix serverreturned:
Neither response answers its prompt. The failure occurred with no server
exception and no request error.
After: patched source passes
With the patch applied, the same deterministic checks returned:
Results:
baseline.
with zero request errors and coherent generated text.
The synchronous path was exercised directly. The NextN call site was not enabled\nin these runtime tests; it was changed because it has the same replicated-input\ncollective semantics.
Local checks against current
main:py_compile: passedgit diff --check: passedSpeed Tests and Profiling
The patched TP4 x DP4 8K-input/1K-output run completed its full sweep:
A pre-fix performance comparison is not meaningful because every pre-fix
generated response was numerically invalid. Those jobs were stopped after the
correctness failure was confirmed.
Checklist
DP collectives; it was validated on two-node, 16-GPU systems.
CI States
Latest PR Test (Base): ✅ Run #30963574545
Latest PR Test (Extra): ❌ Run #30963574465