Repository navigation
[Model] Decoder-side SWA bounded replay for DeepSeek-V4.1 - #58132
Conversation
1652023 to
9a86c2c
Compare
|
/ci run |
|
✅ Triggered Buildkite CI #91349 for commit |
|
This pull request has merge conflicts that must be resolved before it can be |
6709ae4 to
69d3837
Compare
| @triton.jit | ||
| def _gather_replay_batch_kernel( | ||
| query_start_loc_ptr, # [num_reqs + 1] | ||
| dropped_before_ptr, # [num_reqs + 1] rows trimmed before each boundary |
There was a problem hiding this comment.
_gather_replay_batch_kernel JIT-compiles on the first long eager prefill while serving (jit_monitor warns). It's a bare @triton.jit not registered for JIT warmup, and the startup dummy runs never launch it: graph captures return before the trim, and dummy rows aren't prefills, so trims is False. _pad_replayed_slots_kernel from #56227 has the same issue: dummy batches carry no replay start, so replay_start_np.any() is False. Could we warm both once in the self._replay is None block (it runs during the startup dummy runs), e.g. _gather_replay_batch_kernel.warmup(..., NUM_GROUPS=len(specs), BLOCK=1024, grid=(1,)), or wrap them as VllmTritonJitKernel?
There was a problem hiding this comment.
Thx for catching the issue. Fixed now
e8b989d to
bcac4aa
Compare
|
/ci run |
|
✅ Triggered Buildkite CI #91717 for commit |
|
✅ Triggered Buildkite CI #91784 for commit |
ROCm serves DeepSeek-V4.1 through the AMD model classes, so vllm-project#58132 never builds decoder_replay_layers. Construct it on the AMD model and expose it on the vision wrapper. ROCm leaves the prefix-cache window at 0, so the shared model state builds replay_start and warms the gather kernel when decoder replay layers exist. The pad kernel stays on the prefix-cache path. Signed-off-by: Frida Andersson <fanderss@amd.com>
ROCm serves DeepSeek-V4.1 through the AMD model classes, so vllm-project#58132 never builds decoder_replay_layers. Construct it on the AMD model and expose it on the vision wrapper. ROCm leaves the prefix-cache window at 0, so the shared model state builds replay_start and warms the gather kernel when decoder replay layers exist. The pad kernel stays on the prefix-cache path. Signed-off-by: Frida Andersson <fanderss@amd.com>
### What this PR does / why we need it? Add decoder bounded replay for DeepSeek V4.1 on Ascend MRV2, following vllm-project/vllm#58132. For eligible prefill requests, layers after the last KV-source layer process only the final sliding-window tokens. Earlier layers process the full batch. Decode tokens and rows required for prompt logprobs are preserved. - Prepare replay batches and independent attention metadata through the MRV2 model-state hook. - Coordinate replay decisions and token counts across DP ranks, including idle ranks. - Gather rows, positions, query boundaries, and slot mappings with a Triton kernel. - Handle sequence-parallel states and DSA CP indexer buffers, then scatter retained outputs and auxiliary hidden states back to their original positions. - Reuse upstream Ascend SWA visibility bounds and preserve encoder-side replay boundaries for prefix-cache hits. The implementation targets MRV2 only and adds no MRV1 runner changes. ### Does this PR introduce _any_ user-facing change? Yes. Decoder replay is controlled by `swa_bounded_replay=True` in `LLM`, or `--swa-bounded-replay` in the CLI. Supported configurations require MRV2 and `NONE` or `FULL_DECODE_ONLY`. Trimming runs only in eager steps; graph steps retain the full batch. Prefix caching uses the existing encoder-side bounded replay support. Sequence parallelism requires DSA CP. Speculative decoding is limited to DSpark with a compatible sliding window. MRV1, PP, PCP, DCP, microbatching, LoRA, and configurations with Engram layers after the replay boundary disable decoder replay with a warning. ### How was this patch tested? Waiting to be tested. - vLLM main: vllm-project/vllm@c4df37d Signed-off-by: Yizhou Liu <liu_yizhou@outlook.com>
…roject#17496) ### What this PR does / why we need it? Add decoder bounded replay for DeepSeek V4.1 on Ascend MRV2, following vllm-project/vllm#58132. For eligible prefill requests, layers after the last KV-source layer process only the final sliding-window tokens. Earlier layers process the full batch. Decode tokens and rows required for prompt logprobs are preserved. - Prepare replay batches and independent attention metadata through the MRV2 model-state hook. - Coordinate replay decisions and token counts across DP ranks, including idle ranks. - Gather rows, positions, query boundaries, and slot mappings with a Triton kernel. - Handle sequence-parallel states and DSA CP indexer buffers, then scatter retained outputs and auxiliary hidden states back to their original positions. - Reuse upstream Ascend SWA visibility bounds and preserve encoder-side replay boundaries for prefix-cache hits. The implementation targets MRV2 only and adds no MRV1 runner changes. ### Does this PR introduce _any_ user-facing change? Yes. Decoder replay is controlled by `swa_bounded_replay=True` in `LLM`, or `--swa-bounded-replay` in the CLI. Supported configurations require MRV2 and `NONE` or `FULL_DECODE_ONLY`. Trimming runs only in eager steps; graph steps retain the full batch. Prefix caching uses the existing encoder-side bounded replay support. Sequence parallelism requires DSA CP. Speculative decoding is limited to DSpark with a compatible sliding window. MRV1, PP, PCP, DCP, microbatching, LoRA, and configurations with Engram layers after the replay boundary disable decoder replay with a warning. ### How was this patch tested? Waiting to be tested. - vLLM main: vllm-project/vllm@c4df37d Signed-off-by: Yizhou Liu <liu_yizhou@outlook.com>
…ct#58132) Signed-off-by: Yifan Qiao <yifanqiao@inferact.ai> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…roject#17496) ### What this PR does / why we need it? Add decoder bounded replay for DeepSeek V4.1 on Ascend MRV2, following vllm-project/vllm#58132. For eligible prefill requests, layers after the last KV-source layer process only the final sliding-window tokens. Earlier layers process the full batch. Decode tokens and rows required for prompt logprobs are preserved. - Prepare replay batches and independent attention metadata through the MRV2 model-state hook. - Coordinate replay decisions and token counts across DP ranks, including idle ranks. - Gather rows, positions, query boundaries, and slot mappings with a Triton kernel. - Handle sequence-parallel states and DSA CP indexer buffers, then scatter retained outputs and auxiliary hidden states back to their original positions. - Reuse upstream Ascend SWA visibility bounds and preserve encoder-side replay boundaries for prefix-cache hits. The implementation targets MRV2 only and adds no MRV1 runner changes. ### Does this PR introduce _any_ user-facing change? Yes. Decoder replay is controlled by `swa_bounded_replay=True` in `LLM`, or `--swa-bounded-replay` in the CLI. Supported configurations require MRV2 and `NONE` or `FULL_DECODE_ONLY`. Trimming runs only in eager steps; graph steps retain the full batch. Prefix caching uses the existing encoder-side bounded replay support. Sequence parallelism requires DSA CP. Speculative decoding is limited to DSpark with a compatible sliding window. MRV1, PP, PCP, DCP, microbatching, LoRA, and configurations with Engram layers after the replay boundary disable decoder replay with a warning. ### How was this patch tested? Waiting to be tested. - vLLM main: vllm-project/vllm@c4df37d Signed-off-by: Yizhou Liu <liu_yizhou@outlook.com>
上游来源:vllm-project/vllm#58132 (4b2e1cfa7b),先带入自包含的 DecoderReplayLayers 与其单测;model_state/model.py 的接线在后续提交完成。 本仓 ForwardContext 已含 is_padding,测试无需改写。 Co-authored-by: DSH Agent <dsh-agent@local> Signed-off-by: DSH Agent <dsh-agent@local> Signed-off-by: reputationly <197039020@qq.com>
上游来源:vllm-project/vllm#58132 (4b2e1cfa7b),适配点: - model_state 按上游整文件合入(含 replay batch gather kernel / kept InputBatch / DP 同步);本仓 InputBatch 没有 fast_prefill 字段,去掉该 replace 参数; - model.py 按本仓 layer 返回 5 元组 + aux 重算的 API 重写 _run_layer_range / _collapse / _run_replay_layers(上游为 previous_aux 返回式 API),forward 在 decoder_replay_start 处切分,eager prefill 交给 DecoderReplayLayers; - 补上 dp_utils 的 skip_dp_coordination/should_skip_dp_coordination(本仓缺失); - vl_model 暴露 decoder_replay_layers; - 上游 test_deepseek_v41_replay_batch.py 带入(7 passed + decoder 层 3 passed)。 Co-authored-by: DSH Agent <dsh-agent@local> Signed-off-by: DSH Agent <dsh-agent@local> Signed-off-by: reputationly <197039020@qq.com>
Purpose
Decoder-side SWA bounded replay for DeepSeek-V4.1, on top of the encoder side (#56227). The layers past the last KV-source layer (21-39 of 40 on V4.1-Flash) own only sliding-window KV, so in eager prefill steps they run on each request's last 128 tokens, cold prefills included. Simplified re-submission of #56752 (closed); no other open PR implements this.
DeepseekV41ModelState.prepare_attnprepares the kept rows as a sub-batch, the way a microbatch is prepared: one Triton kernel gathers rows, positions, slot mappings and the replay-layer KV start, and the sub-batch gets attention metadata and a forward context of its own. DP ranks agree on whether any rank trims and on every rank's replay token count.DecoderReplayLayersgathers the layer inputs by those rows, runs the replay layers under that context and scatters the outputs back.prepare_attnalready gets the step's graph mode, which DP ranks share, so there are no nested captures, no eager breaks and no runner changes; the diff is confined tovllm/models/deepseek_v41/, a config docstring and the CI job list.MoEOutputto the replay layers unchanged, and layer 21's first boundary finalizes it. A trimming step holds a prefill longer than the window, more tokens than any step that defers its finalize, so the trim path only sees tensors.--no-swa-bounded-replayturns off both sides. A no-op on ROCm.Test Plan
vllm-bench, random token-id prompts, prefix cache reset before every point.Test Result
Unit tests cover the replay rows and sub-batch metadata (adaptive verification, prompt-logprobs requests, DP agreement), graph steps getting no replay batch, and the gather/scatter with the indexer buffers. pre-commit and mypy are clean.
Accuracy (GB200, V4.1-Flash)
exact_match/flexible-extract; one standard error is 0.0072. 0 request errors. On TP4 the fused MoE finalize of #58586 is active, so every decode step passes the cut layer's unfinalized MoE output through the replay layers.Performance (GB200, V4.1-Flash)
Saturated prefill throughput with decoder replay stays at 83K-86K tok/s on TP4 and 199K-228K on DEP4 at every prompt length, against 68K-54K and 134K-120K without. From 16K up, prefill TTFT drops 25-36% on TP4 and 37-45% on DEP4 at any concurrency, and TPOT drops up to 29% and 39% at high concurrency.
TP4:
DEP4:
Decoder replay on / off. TTFT is the prefill-only p50. Each point is one run of 4 x concurrency prompts with the default
max_num_batched_tokens16384 (per rank on DEP4) and max CUDA graph size 1024; each arm runs on its own GB200 node, in parallel.Regressions. Only prompts of 8K or less at concurrency 64 or less; the table has every such point on either setup, with decoder replay on vs off.
Same-node check (TP4, both arms on one GB200 node, 10 single prefill-only requests each):
AMD (MI355X, ROCm 7.2.3)
A no-op: the ROCm model classes have no
decoder_replay_layers, and the encoder side stays off on ROCm as before. The new tests are not in the AMD mirror of the CI job. Checked at 9a86c2c99f against its base 496c647 (the rebase onto main and the eager-only follow-up change only code ROCm does not run), V4.1-Flash TP4 with the recipes.vllm.ai MI355X command minus--no-swa-bounded-replay(DSpark, 5 speculative tokens):tests/evals/gsm8k/gsm8k_eval.pyaccuracy (5-shot, n=1319, concurrency 128), within noise. Prefix-sharing prompts of up to 256K tokens served without errors on both trees, with the same prefix-cache hits. The two new test files plustest_deepseek_v41_replay_start.pyandtest_deepseek_v4_vl_rocm.py: 23 passed.🤖 Developed with Claude Code; all changes reviewed and tested by the author.