Repository navigation
[Bugfix][MoE] Restore TP-sharded routed-expert capture for DP=1 - #61388
Conversation
Signed-off-by: Ronald1995 <ronaldautomobile@163.com>
…x/fix-single-dp-routing-capture Signed-off-by: Ronald1995 <ronaldautomobile@163.com>
Signed-off-by: Ronald1995 <ronaldautomobile@163.com>
Model end-to-end reproducer for the DP=1 sharded capture (1/2): the test caseThis is the model-level reproducer for the "Required model end-to-end reproducer" table. It is deliberately not collected by CI (the filename does not match pytest's What it asserts. For every request it rebuilds the whole batch from each TP rank's raw pre-capture shard (recorded by the probe in the next comment), concatenates the shards in TP-rank order, trims to the pre-SP forward token count, and compares every token/layer/expert id against the Cases covered (PR table + the remaining DP=1 branch of the capturer):
How to run. With a real checkpoint on a Blackwell host (all three export VLLM_ROUTED_EXPERTS_E2E_MODEL=/path/to/deepseek-v4-checkpoint
export VLLM_ROUTED_EXPERTS_E2E_BACKEND=deep_gemm_mega_moe
uv run --no-sync python -m pytest -q -s tests/models/deepseek_v41_routed_experts_capture_e2e.pyWithout a checkpoint (weights-free tiny model, any two GPUs) the sharded layout is supplied by the probe's export VLLM_ROUTED_EXPERTS_E2E_DUMMY=1
export VLLM_ROUTED_EXPERTS_E2E_EMULATE_SP=1
uv run --no-sync python -m pytest -q -s tests/models/deepseek_v41_routed_experts_capture_e2e.pyBase-vs-fix: run the same file by absolute path while the base revision supplies The module needs Vs base / validation results are posted in a separate comment. |
Model end-to-end reproducer for the DP=1 sharded capture (2/2): the validation probe
It changes nothing on disk: the test puts a generated shim on It can also force a capture-input layout, which is how the DP=1 branches can be exercised on a host where no
|
Model end-to-end reproducer (3/3): base vs fix results, and a hardware gate you should know aboutHeadline
The hardware gate (affects what "required model E2E" can mean)
So on H20 I ran the reproducer with the shard layout supplied by the validation probe ( Environment
The two revisions are compared by overlaying the PR's own files on one installed vLLM build, so the diff under test is exactly this PR's diff -?verified by blob hash: the wheel's The probe confirms every measured request really was fed a TP shard ( Base revision -?
|
…eplay Co-authored-by: OpenAI Codex <noreply@openai.com> Signed-off-by: Ao Shen <281812371+aoshen02@users.noreply.github.com>
|
✅ @Ronald1995, CI is now available for this PR.
|
…outing-capture Signed-off-by: Ronald1995 <ronaldautomobile@163.com>
Document DP/TP layouts in the restoration helper and preserve their priority. Reject incomplete DP shard groups explicitly, validate layer indices before collectives, and normalize TP gather inputs. Cover noncontiguous shards, empty ranks, padding ties, and invalid inputs through the existing capture test suite. Validation: 25 isolated CPU capture cases passed in normal and optimized modes. All applicable pre-commit checks passed with Windows adaptations. Signed-off-by: Ronald1995 <ronaldautomobile@163.com>
Move microbatch write offsets and decoder replay row retention out of this change. Keep TP token counts, layout restoration, and their regression coverage. The removed fixes are preserved for independent follow-ups. Validation: 25 isolated CPU layout cases pass in normal and optimized modes; all applicable pre-commit checks pass with Windows adaptations. Signed-off-by: Ronald1995 <ronaldautomobile@163.com>
…outing-capture Signed-off-by: Ronald1995 <ronaldautomobile@163.com>
Pass the replay batch's original token count to the forward context so TP-sharded routing can be reconstructed there too. This does not change decoder replay's row-retention policy. Validation: applicable pre-commit checks and mypy passed. Signed-off-by: Ronald1995 <ronaldautomobile@163.com>
CUDA-graph model E2E + the new regression cases (2xH20-3e, SM90)Tested revision: 1. The new capturer cases: PR head vs base
The base failures split cleanly:
Independent check of the layout helper: I extract the real 2. CUDA-graph model E2E (case 5 of the reproducer, 2 GPUs)
base -?fails before it can compare. The eager reference itself is wrong, i.e. the same pre-fix defect: PR head -? So in graph mode the capture path ran (4 records per prompt), each forward took exactly one all-gather -?the Environment note (not a PR issue): the graph-mode server first died at startup building flashinfer's sampling JIT -?this image's 3. Full reproducer suite at this revision
Every case therefore passes at 4. What this still does not cover
Logs and dumps: |
|
/ci run |
|
✅ Triggered Buildkite CI #94984 for commit |
|
/ci retry |
|
✅ No failed, timed-out, or expired jobs need retrying: https://buildkite.com/vllm/ci/builds/94984 |
|
/ci retry |
|
✅ Queued 1 failed job(s) for retry in Buildkite CI #94984. |
Remove the duplicate forward token count and its count-only caller plumbing. Keep the pre-SP batch descriptor in eager mode and cover model-sharded padding masks and compact decoder replay contexts. Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Ao Shen <aoshen@inferact.ai>
|
/ci run |
|
✅ Triggered Buildkite CI #95067 for commit |
Share the layout error, remove redundant TP guards and temporary counts, and use the declared DPMetadata field. Keep layout precedence and collective behavior unchanged; exercise real metadata in the existing tests. Co-authored-by: Codex <noreply@openai.com> Signed-off-by: Ao Shen <aoshen@inferact.ai>
|
/ci run |
|
✅ Triggered Buildkite CI #95145 for commit |
Overview
Restore complete routed-expert rows when model-level sequence parallelism shards tokens across TP ranks and DP=1 has no DP metadata. Related platform-specific work: vllm-project/vllm-ascend#18502.
Claims
BatchDescriptor.num_tokens(orDPMetadatafor multi-DP), gather in rank order, and trim SP padding.ForwardContext.num_tokensfield or count-only caller arguments.Validation
--confcutdir) against a nightly-image overlay. Includes realsp_padding_maskmutation and compact V4.1 replay contexts. A mask-length implementation fails both new TP-rank regressions.optimize=1) and 96,203 multi-DP differential cases passed. Earlier model reproducer and commands: discussion.Real-weight DeepSeek-V4.1-Flash A/B
Control:
fe18b045fd; candidate: this descriptor simplification. GB200, TP2/DP1/EP,deep_gemm_mega_moe, default padding skipping, async scheduling, prefix caching, chunked prefill, SHM/value delivery. Both eager andFULL_AND_PIECEWISEwere exercised.Environment: official nightly
vllm/vllm-openai@sha256:a7deff2c216def98c193352aca50fb03a2ee29231355b3033dc3789009f6d23e, V4.1 snapshot2cba9e42aa026125f3ed06c6d98c1db82f7ca027. Only the affected production Python files were overlaid per variant; not a full checkout rebuild. Model runs used--max-model-len 8192 --max-num-batched-tokens 2048 --max-num-seqs 16 --gpu-memory-utilization 0.92, concurrent prompt lengths 33/1024/2051/4096 and 8 output tokens, then repeated the 1024-token prefix.VLLM_DEEP_GEMM_WARMUP=skipbypassed an existing image warmup API mismatch; normal JIT and graph capture still ran. Correctness instrumentation makes these runs unsuitable for throughput claims.Details
The previous DP=1 path wrote only the received TP shard, leaving later routing rows stale. Restore the local token axis before buffer assignment. Layer bounds are checked before collectives and gather inputs are contiguous.
The pre-SP count must survive model-level sharding:
is_paddingcan itself become a TP shard and is not a reliable count source. The existing batch descriptor retains the original size, including in compact decoder-replay contexts. Creating that descriptor for eager execution removes duplicate state and three count-only caller edits (production diff for this refinement: net -11 lines).This updates the existing TP fix rather than opening a duplicate. Microbatch write offsets (#57184) and decoder-replay row retention (#61643) remain separate concerns, unchanged here. The restoration helper shares one layout error, reads the declared
DPMetadata.local_sizesfield directly, and retains the existing layout priority. Tests use actualDPMetadataobjects.AI assistance was used for implementation, review and validation.
Pull Request Checklist
/pr-checklistskill.