feat(npu): token-balanced async MoE microbatch split for DP+TP/SP#152
feat(npu): token-balanced async MoE microbatch split for DP+TP/SP#152ShwStone wants to merge 1 commit into
Conversation
|
Test plan: Let’s first use DSV2-Lite to validate accuracy with TP/SP u-batch splitting. |
There was a problem hiding this comment.
Pull request overview
This PR adds a token-balanced async MoE microbatch split policy for CAMAsync on non-PCP DP+TP/SP topologies, aiming to reduce pipeline stage imbalance when request lengths are skewed, while keeping the existing request-boundary behavior as the default.
Changes:
- Introduces
async_moe_splitselection ("request"default,"token"token-balanced TP-aligned) and topology capability detection/validation. - Implements token-balanced split planning (including padded token handling) and stage-local SP-aware slicing via a new
ubatch_sphelper. - Expands CPU-safe unit tests to cover split selection, alignment, padding edge cases, and SP-local stage slicing behavior.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/v1/worker/test_npu_runtime.py | Adds CPU-safe stubs and unit tests for token-balanced split behavior, padding edge cases, SP-local slice mapping, and validation messaging. |
| tests/unit/model_executor/models/test_forward_context.py | Updates forward-orchestration assertions to reflect the new stage-input slicing helper. |
| afd_plugin/v1/worker/npu/ubatch_utils.py | Adds token-balanced split policy, split-point computation, async ubatch slice creation, and SP-local ubatch slice mapping. |
| afd_plugin/v1/worker/npu/attention_model_runner.py | Switches async MoE ubatch planning to the new policy-aware helper and records whether SP-local slicing should be used. |
| afd_plugin/model_executor/models/npu/ubatch_sp.py | New module implementing SP-aware stage-input slicing and mapping global ubatch splits to per-rank token shards. |
| afd_plugin/model_executor/models/npu/deepseek_v2_async_cam_forward.py | Replaces inline slicing with build_async_moe_stage_inputs and threads SP-local slices through stage metadata/context. |
| afd_plugin/model_executor/models/forward_context.py | Extends async MoE ubatch metadata typing to include SP-local slicing fields. |
| afd_plugin/connectors/npu/async_cam.py | Documents and exposes "token" as a valid async_moe_split config value. |
| afd_plugin/compat/npu/feature_validation.py | Adds fail-fast validation for "token" split on unsupported topologies and warning guidance when "request" is used on capable topologies. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if int(getattr(parallel_config, "tensor_parallel_size", 1)) <= 1: | ||
| return False | ||
| if int(getattr(parallel_config, "prefill_context_parallel_size", 1)) != 1: | ||
| return False | ||
| return int(getattr(parallel_config, "decode_context_parallel_size", 1)) == 1 |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (4)
afd_plugin/v1/worker/npu/ubatch_utils.py:165
- AGENTS.md asks to avoid getattr/hasattr on vLLM/vLLM-Ascend structures so upstream compatibility issues fail loudly (AGENTS.md:64-69). In enable_token_balanced_async_moe_split, using getattr with defaults can silently mask missing/renamed fields and change behavior; access parallel_config attributes directly instead.
if int(getattr(parallel_config, "tensor_parallel_size", 1)) <= 1:
return False
if int(getattr(parallel_config, "prefill_context_parallel_size", 1)) != 1:
return False
return int(getattr(parallel_config, "decode_context_parallel_size", 1)) == 1
afd_plugin/v1/worker/npu/ubatch_utils.py:286
- build_sp_local_ubatch_slices_for_current_rank currently swallows all exceptions and silently falls back to global slices. This can hide real upstream/runtime breakages (e.g., get_tp_group/enable_sp API changes) and make SP slicing wrong without an obvious failure. Prefer only treating missing optional imports as a fallback, and let other exceptions surface.
if not bool(enable_sp()) or tp_size <= 1:
return ubatch_slices
except Exception:
return ubatch_slices
afd_plugin/v1/worker/npu/ubatch_utils.py:228
- The create_async_moe_ubatch_slices docstring says it raises AssertionError when num_ubatches != 2, but the function currently has no such assertion and will attempt to compute split points for any num_ubatches. Either update the docstring or enforce the 2-ubatch contract to match the stated behavior (and async_moe_ubatching validation).
Returns ``(None, "request_boundary")`` when the batch is too small to
split (fewer than ``num_ubatches`` requests or tokens); callers should
run such steps unubatched. Raises AssertionError if ``num_ubatches``
is not 2.
"""
afd_plugin/model_executor/models/npu/ubatch_sp.py:243
- _slice_sequence_tensor and _pad_sequence_tensor are currently unused (only definitions exist) and they implement the heuristic slicing/padding behavior that was previously identified as buggy for tensors whose token dimension is not inferred by shape[0] <= 4. Removing these unused helpers will reduce the risk of accidentally reintroducing that bug.
def _slice_sequence_tensor(tensor: torch.Tensor, token_slice: slice) -> torch.Tensor:
if tensor.dim() > 1 and int(tensor.shape[0]) <= 4:
return tensor[:, token_slice]
return tensor[token_slice]
4205f3d to
663eae6
Compare
|
Please fix DCO and CI. |
|
Scan:
Validated:
Verdict: REQUEST CHANGES |
jiangkuaixue123
left a comment
There was a problem hiding this comment.
Two suggestions on the async MoE ubatch metadata type definition.
|
|
||
|
|
||
| class AsyncMoeUbatchMetadata(TypedDict): | ||
| class _AsyncMoeUbatchMetadataOptional(TypedDict, total=False): |
There was a problem hiding this comment.
Could you add a class docstring explaining why the SP-local microbatch metadata is optional and when each field is populated and consumed?
There was a problem hiding this comment.
Added a class docstring on AsyncMoeUbatchMetadata explaining required vs optional fields and when each is populated/consumed.
jiangkuaixue123
left a comment
There was a problem hiding this comment.
One compatibility concern for the updated ubatch split path.
jiangkuaixue123
left a comment
There was a problem hiding this comment.
Overall, the structure LGTM. Please address the review comments and validate the accuracy. Once those are complete, this should be ready to merge.
|
Pushed a follow-up fix commit to resolve a test collection failure on CPU-only development paths. Root cause: The previous commit added a module-level Fix: Replaced |
CAMAsyncAFDConnector previously split async MoE prefill work into two microbatches only at request boundaries. This works for PCP deployments but produces heavily imbalanced stages in non-PCP DP+TP/SP topologies where request lengths differ. Add a token-count-based split policy: - Introduce async_moe_split connector_extra_config with values "request" (default, preserves PCP behavior) and "token". - On non-PCP DP+TP/SP topologies, split the padded prefill token workload into two TP-aligned stages of approximately equal size. - Rebuild stage-local request/token offsets, sequence lengths, and Ascend attention metadata for each stage. - Add SP-local ubatch slices (sp_local_ubatch_slices) so model-side stage slicing works when sequence parallelism shards tokens across TP ranks. - Move stage-input slicing into ubatch_sp.py and keep the forward orchestration in deepseek_v2_async_cam_forward.py minimal. Startup validation fail-fast: - Reject async_moe_split="token" on unsupported topologies. - Warn when running "request" on a topology that supports "token". Compatibility and review fixes: - Keep feature_validation CPU-safe by using standard logging instead of vllm.logger at module import time. - Document PCP compatibility contract in _build_attention_metadata_with_async_moe_ubatches. - Document the total=False TypedDict design choice for Python 3.10. - Unify stage input slicing and add high-dim fail-fast in ubatch_sp.py. - Expand unit tests for token/request split, 2D positions, and _build_attention_metadata_with_async_moe_ubatches. - Update user guide, connector contracts, and recipe README for the new async_moe_split option. Signed-off-by: ShwStone <haowenshi@outlook.com>
5b89a97 to
d937b72
Compare
|
Thanks for the thorough scan. All findings have been addressed in the latest push: 1. [major] Added two tests:
2. [major] Added 3. [minor] Docs stale Updated 4. [minor]
5. [minor] Unified DCO sign-off and GPG signature are also included in the latest commit. |
|
DCO sign-off added. The squashed commit now includes |

CAMAsyncAFDConnector previously split async MoE prefill work into two microbatches only at request boundaries. This works for PCP deployments but produces heavily imbalanced stages in non-PCP DP+TP/SP topologies where request lengths differ.
Add a token-count-based split policy:
async_moe_splitconnector_extra_config with values"request"(default, preserves PCP behavior) and"token".sp_local_ubatch_slices) so model-side stage slicing works when sequence parallelism shards tokens across TP ranks.ubatch_sp.pyand keep the forward orchestration indeepseek_v2_async_cam_forward.pyminimal.Startup validation fail-fast:
async_moe_split="token"on unsupported topologies."request"on a topology that supports"token".Tests cover request-boundary vs token-balanced selection, TP-size alignment, padded/odd token counts, SP-local token mapping, and topology validation.
Purpose
Implement the token-balanced async MoE microbatch split for non-PCP DP+TP/SP topologies, as described in #149. The goal is to avoid heavily imbalanced pipeline stages when request lengths are skewed, while keeping the existing PCP request-boundary behavior unchanged.
Issue
Scope
async_moe_splitconfig contract.Implementation Notes
afd_plugin.v1.worker.npu.ubatch_utils.create_async_moe_ubatch_slices, which returns both the slices and the applied policy string (request_boundaryortoken_balanced_tp).enable_token_balanced_async_moe_split.afd_plugin.model_executor.models.npu.ubatch_sp.build_async_moe_stage_inputs; the forward orchestration only consumes the resulting stage tensors and slice metadata.Test Plan
tests/unit/v1/worker/test_npu_runtime.py— ubatch planning, SP-local slice mapping, validation warnings/errors.tests/unit/model_executor/models/test_forward_context.py— forward orchestration structure assertions.async_moe_ubatching=true, two microbatches.Test Result
py_compile,ruff check,ruff format.Docs Impact
connector_extra_config.async_moe_split.Essential PR Checklist