[Spec decode] Support Kimi-K3 DCP with DSpark - #52188
Conversation
GirasoleY
left a comment
There was a problem hiding this comment.
Thanks for adding DCP + DSpark support! Overall the change looks good.
I left a few inline comments about moving the repeated metadata construction out of hot path.
| remainder = torch.clamp( | ||
| per_query_global_lens % dcp_span - self.dcp_rank * interleave, | ||
| min=0, | ||
| max=interleave, | ||
| ) | ||
| seq_lens = per_query_global_lens // dcp_span * interleave + remainder | ||
| block_table = block_table.repeat_interleave(query_len, dim=0) | ||
| q = q.unsqueeze(1) |
There was a problem hiding this comment.
This is inefficient as it run for every mla forward.
Let's construct the dcp related seqlen/query_start_loc/block table expansion in metadata builder, then reuse them for all MLA layers.
The same metadata can be reused in combine path as well.
There was a problem hiding this comment.
Thanks for the suggestion. It is now changed to run only once per forward pass and reused across layers. Please check again.
| @@ -118,6 +122,22 @@ class FlashInferMLAMetadataBuilder(MLACommonMetadataBuilder[MLACommonMetadata]): | |||
| # Non-causal DSpark blocks are flattened to single-token rows in forward_mqa. | |||
| supports_non_causal_multi_token_decode: ClassVar[bool] = True | |||
There was a problem hiding this comment.
Enable supports_non_causal_multi_token_dcp for flashinfer_mla as well?
There was a problem hiding this comment.
supports_non_causal_multi_token_dcp is not supported by flashinfer_mla by this PR. will let it use tokenspeed backend for the draft model for now.
There was a problem hiding this comment.
Make sense. I added a refactor PR to remove flashinfer specific changes.
There was a problem hiding this comment.
Thanks! The refactor looks great.
eecd761 to
7ecab4c
Compare
GirasoleY
left a comment
There was a problem hiding this comment.
Added a refactor to move the flattened decode metadata into MLACommonDecodeMetadata. the rest LGTM :)
…fix in separate PR) This reverts commit f9d4516d49113369e4f6ba5b650daae89ac51d8c. Signed-off-by: wzhao18 <wzhao18.sz@gmail.com>
Signed-off-by: wzhao18 <wzhao18.sz@gmail.com>
6d6cb7d to
073f76a
Compare
|
✅ Triggered Buildkite CI #84210 for commit |
|
/ci retry |
1 similar comment
|
/ci retry |
|
✅ Queued 1 failed job(s) for retry in Buildkite CI #84210. |
Preserve the TP-only FlashInfer DSpark path from vllm-project#50000 while removing the FlashInfer-specific causal DCP flattening and cached metadata introduced by vllm-project#52188. Signed-off-by: Summer Yang <girasoleyang@gmail.com>
Upstream vllm-project#52188 landed DCP-aware draft slot mapping for DFlash/DSpark (cp_local_slot + prepare_dcp_local_seq_lens), superseding the localizer this branch carried. Keep upstream's version, which also handles the null block and the rejected context suffix, and reduce this branch to what it still adds: the KV-head-replicated draft cache for dense (GQA/MHA) drafts. The query block's K/V still must not be slotted into a head-replicated cache, so that behavior moves behind PAD_QUERY_SLOTS_UNDER_CP, derived from the draft attention layers rather than forced for every DCP run. Upstream's MLA draft path (Kimi-K3) keeps its real query slots. Signed-off-by: Mikhail Kostryukov <mike@triptrack.net> Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: wzhao18 <wzhao18.sz@gmail.com> Signed-off-by: Zhu, Zufang <zufang.zhu@intel.com>
### What this PR does / why we need it? The PR adapts vllm-ascend for compatibility with the latest vLLM main (commit `ba07e4a4`). | Files | Upstream vLLM change | vllm-ascend adaptation | |-------|---------------------|------------------------| | `.github/vllm-main-verified.commit` | — | Updated verified main commit hash from `cdc4824a21` to `ba07e4a48` | | `tests/e2e/conftest.py` | [vllm#53272](vllm-project/vllm#53272) — upstream plans to remove native Hunyuan V1/VL; [vllm#51665](vllm-project/vllm#51665) — dropped HunYuanVL `lm_head` workaround | Added `skip` condition for HunyuanVL e2e when `vllm_version_is("0.27.1")` is False (vLLM main) | | `tests/ut/core/test_profiling_chunk.py` | — vLLM main `Scheduler.__init__` reads `model_config.uses_mrope`, which infinitely recurses on a bare MagicMock | Version-gated: sets `type(model_config).uses_mrope = PropertyMock(return_value=False)` on main | | `tests/ut/core/test_recompute_scheduler.py` | — vLLM main `Scheduler.add_request` reads `spec_decode_metrics_level` | Version-gated: sets `scheduler.spec_decode_metrics_level = "none"` on main | | `tests/ut/patch/platform/test_patch_structured_output.py` | — Upstream changed structured output validation error type from `ValueError` to `VLLMValidationError` | Version-gated: `error_type = ValueError if vllm_version_is("0.27.1") else VLLMValidationError` used in all three fake validation functions and `pytest.raises` | | `vllm_ascend/attention/attention_v1.py` | [vllm#52839](vllm-project/vllm#52839) — moved `pcp.py` from `vllm.model_executor.layers.attention.pcp` to `vllm.v1.attention.ops.pcp` | Version-gated `_gather_prefill_cache_inputs` import path | | `vllm_ascend/compilation/acl_graph.py` | [vllm#49134](vllm-project/vllm#49134) — `get_current_vllm_config()` now raises `AssertionError` when called outside `set_current_vllm_config()` context | `update_full_graph_params` version-gated: main branch wraps `get_impl_cls()`/`update_graph_params` in `with set_current_vllm_config(vllm_config):` | | `vllm_ascend/models/deepseek_mtp.py` | [vllm#53106](vllm-project/vllm#53106) — removed `skip_prefixes` kwarg from `AutoWeightsLoader.__init__` | `AscendGlmMoeDsaForCausalLM.load_weights` version-gated: 0.27.1 uses `skip_prefixes=["rot."]`; main uses `WeightsMapper(orig_to_new_prefix={"rot.": None})` passed via `load_weights(weights, mapper=mapper)` | | `vllm_ascend/spec_decode/llm_base_proposer.py` | [vllm#52861](vllm-project/vllm#52861) — added `DeepseekV32MTPModel` to MTP architecture set in `model_returns_tuple()` | `model_returns_tuple` version-gated: 0.27.1 checks `{"DeepSeekMTPModel", "KimiK3MTPModel"}`; main also includes `"DeepseekV32MTPModel"` | | `vllm_ascend/worker/v2/spec_decode/dflash/speculator.py` | [vllm#52188](vllm-project/vllm#52188) — added `cp_rank`, `CP_SIZE`, `CP_INTERLEAVE` params to `_prepare_dflash_inputs_kernel` for DCP support | Entire `_prepare_dflash_inputs_kernel_ascend` kernel duplicated under `vllm_version_is("0.27.1")` gate: 0.27.1 uses 30 pos + 3 constexpr (no DCP params); main uses 31 pos + 5 constexpr | ### Does this PR introduce _any_ user-facing change? ### How was this patch tested? - vLLM version: v0.27.1 - vLLM main: vllm-project/vllm@cdc4824 --------- Signed-off-by: hfadzxy <starmoon_zhang@163.com>
### What this PR does / why we need it? The PR adapts vllm-ascend for compatibility with the latest vLLM main (commit `ba07e4a4`). | Files | Upstream vLLM change | vllm-ascend adaptation | |-------|---------------------|------------------------| | `.github/vllm-main-verified.commit` | — | Updated verified main commit hash from `cdc4824a21` to `ba07e4a48` | | `tests/e2e/conftest.py` | [vllm#53272](vllm-project/vllm#53272) — upstream plans to remove native Hunyuan V1/VL; [vllm#51665](vllm-project/vllm#51665) — dropped HunYuanVL `lm_head` workaround | Added `skip` condition for HunyuanVL e2e when `vllm_version_is("0.27.1")` is False (vLLM main) | | `tests/ut/core/test_profiling_chunk.py` | — vLLM main `Scheduler.__init__` reads `model_config.uses_mrope`, which infinitely recurses on a bare MagicMock | Version-gated: sets `type(model_config).uses_mrope = PropertyMock(return_value=False)` on main | | `tests/ut/core/test_recompute_scheduler.py` | — vLLM main `Scheduler.add_request` reads `spec_decode_metrics_level` | Version-gated: sets `scheduler.spec_decode_metrics_level = "none"` on main | | `tests/ut/patch/platform/test_patch_structured_output.py` | — Upstream changed structured output validation error type from `ValueError` to `VLLMValidationError` | Version-gated: `error_type = ValueError if vllm_version_is("0.27.1") else VLLMValidationError` used in all three fake validation functions and `pytest.raises` | | `vllm_ascend/attention/attention_v1.py` | [vllm#52839](vllm-project/vllm#52839) — moved `pcp.py` from `vllm.model_executor.layers.attention.pcp` to `vllm.v1.attention.ops.pcp` | Version-gated `_gather_prefill_cache_inputs` import path | | `vllm_ascend/compilation/acl_graph.py` | [vllm#49134](vllm-project/vllm#49134) — `get_current_vllm_config()` now raises `AssertionError` when called outside `set_current_vllm_config()` context | `update_full_graph_params` version-gated: main branch wraps `get_impl_cls()`/`update_graph_params` in `with set_current_vllm_config(vllm_config):` | | `vllm_ascend/models/deepseek_mtp.py` | [vllm#53106](vllm-project/vllm#53106) — removed `skip_prefixes` kwarg from `AutoWeightsLoader.__init__` | `AscendGlmMoeDsaForCausalLM.load_weights` version-gated: 0.27.1 uses `skip_prefixes=["rot."]`; main uses `WeightsMapper(orig_to_new_prefix={"rot.": None})` passed via `load_weights(weights, mapper=mapper)` | | `vllm_ascend/spec_decode/llm_base_proposer.py` | [vllm#52861](vllm-project/vllm#52861) — added `DeepseekV32MTPModel` to MTP architecture set in `model_returns_tuple()` | `model_returns_tuple` version-gated: 0.27.1 checks `{"DeepSeekMTPModel", "KimiK3MTPModel"}`; main also includes `"DeepseekV32MTPModel"` | | `vllm_ascend/worker/v2/spec_decode/dflash/speculator.py` | [vllm#52188](vllm-project/vllm#52188) — added `cp_rank`, `CP_SIZE`, `CP_INTERLEAVE` params to `_prepare_dflash_inputs_kernel` for DCP support | Entire `_prepare_dflash_inputs_kernel_ascend` kernel duplicated under `vllm_version_is("0.27.1")` gate: 0.27.1 uses 30 pos + 3 constexpr (no DCP params); main uses 31 pos + 5 constexpr | ### Does this PR introduce _any_ user-facing change? ### How was this patch tested? - vLLM version: v0.27.1 - vLLM main: vllm-project/vllm@cdc4824 --------- Signed-off-by: hfadzxy <starmoon_zhang@163.com>
### What this PR does / why we need it? The PR adapts vllm-ascend for compatibility with the latest vLLM main (commit `ba07e4a4`). | Files | Upstream vLLM change | vllm-ascend adaptation | |-------|---------------------|------------------------| | `.github/vllm-main-verified.commit` | — | Updated verified main commit hash from `cdc4824a21` to `ba07e4a48` | | `tests/e2e/conftest.py` | [vllm#53272](vllm-project/vllm#53272) — upstream plans to remove native Hunyuan V1/VL; [vllm#51665](vllm-project/vllm#51665) — dropped HunYuanVL `lm_head` workaround | Added `skip` condition for HunyuanVL e2e when `vllm_version_is("0.27.1")` is False (vLLM main) | | `tests/ut/core/test_profiling_chunk.py` | — vLLM main `Scheduler.__init__` reads `model_config.uses_mrope`, which infinitely recurses on a bare MagicMock | Version-gated: sets `type(model_config).uses_mrope = PropertyMock(return_value=False)` on main | | `tests/ut/core/test_recompute_scheduler.py` | — vLLM main `Scheduler.add_request` reads `spec_decode_metrics_level` | Version-gated: sets `scheduler.spec_decode_metrics_level = "none"` on main | | `tests/ut/patch/platform/test_patch_structured_output.py` | — Upstream changed structured output validation error type from `ValueError` to `VLLMValidationError` | Version-gated: `error_type = ValueError if vllm_version_is("0.27.1") else VLLMValidationError` used in all three fake validation functions and `pytest.raises` | | `vllm_ascend/attention/attention_v1.py` | [vllm#52839](vllm-project/vllm#52839) — moved `pcp.py` from `vllm.model_executor.layers.attention.pcp` to `vllm.v1.attention.ops.pcp` | Version-gated `_gather_prefill_cache_inputs` import path | | `vllm_ascend/compilation/acl_graph.py` | [vllm#49134](vllm-project/vllm#49134) — `get_current_vllm_config()` now raises `AssertionError` when called outside `set_current_vllm_config()` context | `update_full_graph_params` version-gated: main branch wraps `get_impl_cls()`/`update_graph_params` in `with set_current_vllm_config(vllm_config):` | | `vllm_ascend/models/deepseek_mtp.py` | [vllm#53106](vllm-project/vllm#53106) — removed `skip_prefixes` kwarg from `AutoWeightsLoader.__init__` | `AscendGlmMoeDsaForCausalLM.load_weights` version-gated: 0.27.1 uses `skip_prefixes=["rot."]`; main uses `WeightsMapper(orig_to_new_prefix={"rot.": None})` passed via `load_weights(weights, mapper=mapper)` | | `vllm_ascend/spec_decode/llm_base_proposer.py` | [vllm#52861](vllm-project/vllm#52861) — added `DeepseekV32MTPModel` to MTP architecture set in `model_returns_tuple()` | `model_returns_tuple` version-gated: 0.27.1 checks `{"DeepSeekMTPModel", "KimiK3MTPModel"}`; main also includes `"DeepseekV32MTPModel"` | | `vllm_ascend/worker/v2/spec_decode/dflash/speculator.py` | [vllm#52188](vllm-project/vllm#52188) — added `cp_rank`, `CP_SIZE`, `CP_INTERLEAVE` params to `_prepare_dflash_inputs_kernel` for DCP support | Entire `_prepare_dflash_inputs_kernel_ascend` kernel duplicated under `vllm_version_is("0.27.1")` gate: 0.27.1 uses 30 pos + 3 constexpr (no DCP params); main uses 31 pos + 5 constexpr | ### Does this PR introduce _any_ user-facing change? ### How was this patch tested? - vLLM version: v0.27.1 - vLLM main: vllm-project/vllm@cdc4824 --------- Signed-off-by: hfadzxy <starmoon_zhang@163.com>
### What this PR does / why we need it? The PR adapts vllm-ascend for compatibility with the latest vLLM main (commit `ba07e4a4`). | Files | Upstream vLLM change | vllm-ascend adaptation | |-------|---------------------|------------------------| | `.github/vllm-main-verified.commit` | — | Updated verified main commit hash from `cdc4824a21` to `ba07e4a48` | | `tests/e2e/conftest.py` | [vllm#53272](vllm-project/vllm#53272) — upstream plans to remove native Hunyuan V1/VL; [vllm#51665](vllm-project/vllm#51665) — dropped HunYuanVL `lm_head` workaround | Added `skip` condition for HunyuanVL e2e when `vllm_version_is("0.27.1")` is False (vLLM main) | | `tests/ut/core/test_profiling_chunk.py` | — vLLM main `Scheduler.__init__` reads `model_config.uses_mrope`, which infinitely recurses on a bare MagicMock | Version-gated: sets `type(model_config).uses_mrope = PropertyMock(return_value=False)` on main | | `tests/ut/core/test_recompute_scheduler.py` | — vLLM main `Scheduler.add_request` reads `spec_decode_metrics_level` | Version-gated: sets `scheduler.spec_decode_metrics_level = "none"` on main | | `tests/ut/patch/platform/test_patch_structured_output.py` | — Upstream changed structured output validation error type from `ValueError` to `VLLMValidationError` | Version-gated: `error_type = ValueError if vllm_version_is("0.27.1") else VLLMValidationError` used in all three fake validation functions and `pytest.raises` | | `vllm_ascend/attention/attention_v1.py` | [vllm#52839](vllm-project/vllm#52839) — moved `pcp.py` from `vllm.model_executor.layers.attention.pcp` to `vllm.v1.attention.ops.pcp` | Version-gated `_gather_prefill_cache_inputs` import path | | `vllm_ascend/compilation/acl_graph.py` | [vllm#49134](vllm-project/vllm#49134) — `get_current_vllm_config()` now raises `AssertionError` when called outside `set_current_vllm_config()` context | `update_full_graph_params` version-gated: main branch wraps `get_impl_cls()`/`update_graph_params` in `with set_current_vllm_config(vllm_config):` | | `vllm_ascend/models/deepseek_mtp.py` | [vllm#53106](vllm-project/vllm#53106) — removed `skip_prefixes` kwarg from `AutoWeightsLoader.__init__` | `AscendGlmMoeDsaForCausalLM.load_weights` version-gated: 0.27.1 uses `skip_prefixes=["rot."]`; main uses `WeightsMapper(orig_to_new_prefix={"rot.": None})` passed via `load_weights(weights, mapper=mapper)` | | `vllm_ascend/spec_decode/llm_base_proposer.py` | [vllm#52861](vllm-project/vllm#52861) — added `DeepseekV32MTPModel` to MTP architecture set in `model_returns_tuple()` | `model_returns_tuple` version-gated: 0.27.1 checks `{"DeepSeekMTPModel", "KimiK3MTPModel"}`; main also includes `"DeepseekV32MTPModel"` | | `vllm_ascend/worker/v2/spec_decode/dflash/speculator.py` | [vllm#52188](vllm-project/vllm#52188) — added `cp_rank`, `CP_SIZE`, `CP_INTERLEAVE` params to `_prepare_dflash_inputs_kernel` for DCP support | Entire `_prepare_dflash_inputs_kernel_ascend` kernel duplicated under `vllm_version_is("0.27.1")` gate: 0.27.1 uses 30 pos + 3 constexpr (no DCP params); main uses 31 pos + 5 constexpr | ### Does this PR introduce _any_ user-facing change? ### How was this patch tested? - vLLM version: v0.27.1 - vLLM main: vllm-project/vllm@cdc4824 --------- Signed-off-by: hfadzxy <starmoon_zhang@163.com>
… DFlash/DSpark (vllm-project#48392) Taken from PR vllm-project#48392 head (origin/pr-48392, 8/21) as a net diff against main: the author re-based onto vllm-project#52188 (cp_local_slot in the input-prep kernel), so the earlier in-kernel _pos_to_slot/FORCE_PAD_UNDER_CP approach is superseded by a host-side dcp_kv_head_replicated flag plus a PAD_QUERY_SLOTS_UNDER_CP tl.constexpr, keeping cp_local_slot untouched. - Attention: cache_num_kv_heads decouples stored KV heads per block from the impl's projection head count. - qwen3_dflash: dcp_kv_head_replicas() + precompute all-gather replicate the projected K/V across the DCP group before the cache write. - dflash speculator: PAD query slots under DCP for a replicated draft cache (query block attends fresh K/V, never the cache). - flash_attn: descale=None in _forward_with_dcp for non-quantized caches. - config/vllm.py: allow the sharded case only for Qwen3-family DFlashDraftModel/Qwen3DSparkModel with a non-quantized draft KV cache; keep rejecting v1 runner, DeepSeek-V4 DSpark, other archs, quantized draft caches, and partial replication. - test: 3 new tests in test_dflash_prepare_inputs.py (DCP partition, query-slot PAD for replicated cache, no-DCP no-op). Needed for GLM-5.2 DSpark (Qwen3 draft, MHA 64 KV heads, TP4/DCP4) tests. Signed-off-by: Leoyzen <leoyzen@gmail.com>
Purpose
This PR adds support for running Kimi-K3 decode context parallel with DSpark with FlashinferMLA and Tokenspeed as target causal attention backend and Tokenspeed as the draft non-causal backend.
Test Plan
Kimi K3 GSM8k with the different backend combination.
Test Result
Default (no backend specified):
FlashinferMLA target + Tokenspeed draft:
Tokenspeed target + Tokenspeed draft:
Essential Elements of an Effective PR Description Checklist
supported_models.mdandexamplesfor a new model.