[None][fix] Support DeepSeekV4 routing in perfect-router planner#14074
Conversation
|
/bot run --disable-fail-fast |
|
PR_Github #48126 [ run ] triggered by Bot. Commit: |
|
PR_Github #48126 [ run ] completed with state
|
|
/bot run --disable-fail-fast |
|
PR_Github #48171 [ run ] triggered by Bot. Commit: |
|
/bot run --disable-fail-fast |
|
PR_Github #48173 [ run ] triggered by Bot. Commit: |
…ew feedback) Per review feedback on PR NVIDIA#14074: instead of having the planner introspect routing_method.routing_impl vs routing_method directly to resolve n_group/topk_group, push the layout abstraction into the routing-method classes themselves. - DeepSeekV3MoeRoutingMethod gains @Property n_group / topk_group that delegate to self.routing_impl. - DeepSeekV4MoeRoutingMethod already stores them as direct attributes, no change needed. - DeepSeekV3PerfectRouterPlanner.get_cache_signature and create_logits now read routing_method.n_group / routing_method.topk_group directly. - Remove the now-redundant _resolve_group_config helper. This way the planner does not need to "recognize whether V3 or V4"; each routing method publishes the same public surface and the storage layout is an implementation detail. The unit regression test is renamed to test_grouped_routing_exposes_n_group_topk_group and asserts the properties directly on both routing-method classes; the end-to-end get_cached_perfect_router_logits test is unchanged and still covers the full planner pipeline for V3, V4 dense, and V4 hashed gates. Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
|
/bot run --disable-fail-fast |
|
PR_Github #48256 [ run ] triggered by Bot. Commit: |
0a93d10 to
118e7a5
Compare
DeepSeekV3PerfectRouterPlanner._resolve_group_config() only knew how to introspect DeepSeekV3MoeRoutingMethod, which nests n_group/topk_group on routing_impl. DeepSeekV4MoeRoutingMethod stores them directly on the outer object, so passing it in raised: ValueError: DeepSeekV3 perfect-router planning requires routing_method.routing_impl to provide n_group and topk_group at MoE construction time and crashed every executor rank when ENABLE_PERFECT_ROUTER=1 was set on DeepSeekV4 (e.g. DSv4 DEP=16 benchmarks). Fall back to the routing method itself when routing_impl is absent so both V3 (nested) and V4 (flat) layouts work, and add a CPU-only regression test that exercises both shapes through the planner. Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
DeepseekV4MoE.__init__ called precompute_common_perfect_router_logits() again after self.experts = create_moe(...) returned, but the call was missing the required routing_method argument and crashed: TypeError: precompute_common_perfect_router_logits() missing 1 required positional argument: 'routing_method' This was unreachable before the previous fix because the create_moe() call blew up first; now that create_moe() succeeds on DSv4, the dead call became reachable and broke init. Every MoE backend's base class (MoE in interface.py) already invokes _init_perfect_router() during __init__, which precomputes the cache with the correct dtype (_get_perfect_router_dtype() -> float32 for V3/V4 routing) and the correct ep_rank. The block here used the model dtype (e.g. bfloat16) and the default ep_rank=0, producing useless cache entries under wrong keys even when it did run. Drop the dead block and its now-unused import. Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
…oE.forward_MoE DeepseekV4MoE.forward_MoE replaced router_logits with cached "ideal" logits via _create_ideal_expert_load_balanced_logits() when ENABLE_PERFECT_ROUTER=1. The helper called get_cached_perfect_router_logits() without the required ep_rank and routing_method arguments: TypeError: get_cached_perfect_router_logits() missing 2 required positional arguments: 'ep_rank' and 'routing_method' This surfaced during warmup once the init-time precompute fix landed, because the runtime swap on this code path was never exercised before. The FusedMoE backend's own forward (interface.py: MoE.forward) already runs router_logits = self._maybe_get_perfect_router_logits(router_logits) as the very first step, using the correct ep_rank, routing_method, and dtype. ConfigurableMoE (returned by create_moe()) only overrides forward_impl/forward_fake, so MoE.forward still runs. The substitution in DeepseekV4MoE.forward_MoE was therefore both duplicated and broken; remove it together with the unused helper and import. Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
DeepseekV4Gate with is_hashed=True returns None from its bias callable (fetch_e_score_correction_bias() at modeling_deepseekv4.py:1304-1308), because hashed gates route via tid2eid instead of a learned correction bias. BasePerfectRouterPlanner._force_zero_routing_bias_in_place then crashed on: TypeError: zeros_like(): argument 'input' (position 1) must be Tensor, not NoneType The init-time precompute swallowed this in its per-batch-size try/except (see Warning: Failed to precompute logits for batch size N: zeros_like() ... entries in benchmark logs; the cache ends up at 0 entries). The runtime path through MoE.forward -> _maybe_get_perfect_router_logits has no try/except, so the first forward call after warmup crashes the executor on every rank. Mask-out is a no-op when there is no learned bias to mask. Return early in _force_zero_routing_bias_in_place when bias is None. Replace the narrow _resolve_group_config unit test with an additional end-to-end CPU test that drives get_cached_perfect_router_logits for V3, V4 dense, and V4 hashed routing methods. The hashed case fails without this fix; the V3 / V4-dense cases keep the prior coverage of the planner -> _resolve_group_config -> _force_zero_routing_bias_in_place chain. Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
The deployed DSv4-Pro checkpoint config has num_experts_per_tok=6 and
n_routed_experts=384 (verified against
/lustre/.../models/dsv4-pro/config.json). The previous test used
top_k=8 and num_experts=64, which mirror the older DSv3-R1 shape and do
not reflect the configuration that ENABLE_PERFECT_ROUTER=1 is actually
exercised under in DSv4-Pro DEP=16 disagg-serving benchmarks.
The bug fix itself does not depend on top_k, n_group, or topk_group
values; the planner constraint experts_per_token <= min(topk_group,
n_group) * (num_experts / n_group) is satisfied at top_k=6 with the
DSv4-Pro shape (6 <= 4 * 48 = 192). But routing the tests through
production-relevant values lets them catch any future regression that
is shape-sensitive.
Add a "shape" parametrize axis with two cases:
- small (num_experts=64, moe_ep_size=1): fast CPU coverage of the
three routing layouts.
- dsv4_pro_dep16 (num_experts=384, moe_ep_size=16): the exact shape
used by the disagg-serving benchmark that motivated this PR.
Crossed with the existing v3 / v4_dense / v4_hashed parameter, the
test now exercises both routing-method shapes against both expert
counts, covering all four bug surfaces fixed in this PR.
Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
…ew feedback) Per review feedback on PR NVIDIA#14074: instead of having the planner introspect routing_method.routing_impl vs routing_method directly to resolve n_group/topk_group, push the layout abstraction into the routing-method classes themselves. - DeepSeekV3MoeRoutingMethod gains @Property n_group / topk_group that delegate to self.routing_impl. - DeepSeekV4MoeRoutingMethod already stores them as direct attributes, no change needed. - DeepSeekV3PerfectRouterPlanner.get_cache_signature and create_logits now read routing_method.n_group / routing_method.topk_group directly. - Remove the now-redundant _resolve_group_config helper. This way the planner does not need to "recognize whether V3 or V4"; each routing method publishes the same public surface and the storage layout is an implementation detail. The unit regression test is renamed to test_grouped_routing_exposes_n_group_topk_group and asserts the properties directly on both routing-method classes; the end-to-end get_cached_perfect_router_logits test is unchanged and still covers the full planner pipeline for V3, V4 dense, and V4 hashed gates. Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
b80ff77 to
459224a
Compare
|
/bot run --disable-fail-fast |
|
PR_Github #48345 [ run ] triggered by Bot. Commit: |
|
PR_Github #48345 [ run ] completed with state
|
|
/bot run --disable-fail-fast |
|
PR_Github #48395 [ run ] triggered by Bot. Commit: |
|
PR_Github #48395 [ run ] completed with state
|
|
/bot run --disable-fail-fast |
|
PR_Github #48418 [ run ] triggered by Bot. Commit: |
|
PR_Github #48418 [ run ] completed with state |
Falls back to per-head RMS reshape when torch.ops.trtllm.deepseek_v4_q_norm is not registered (e.g., Python-only patched image w/o C++ rebuild). Lets us deploy PRs NVIDIA#14074 + NVIDIA#13975 via build_python_changes.sh without a full Docker rebuild. C++ rebuild later will pick up the perf benefit of the fused CUDA kernel automatically.
…DIA#14074) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com> (cherry picked from commit d178370) Signed-off-by: Fanrong Li <lfr-0531@users.noreply.github.com>
…DIA#14074) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com> (cherry picked from commit d178370) Signed-off-by: Fanrong Li <lfr-0531@users.noreply.github.com>
…DIA#14074) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com> (cherry picked from commit d178370) Signed-off-by: Fanrong Li <lfr-0531@users.noreply.github.com>
…DIA#14074) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com> (cherry picked from commit d178370) Signed-off-by: Fanrong Li <lfr-0531@users.noreply.github.com>
…DIA#14074) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
…DIA#14074) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
…DIA#14074) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
…DIA#14074) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com> (cherry picked from commit d178370) Signed-off-by: Fanrong Li <lfr-0531@users.noreply.github.com>
…DIA#14074) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com> (cherry picked from commit d178370) Signed-off-by: Fanrong Li <lfr-0531@users.noreply.github.com>
…DIA#14074) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com> (cherry picked from commit d178370) Signed-off-by: Fanrong Li <lfr-0531@users.noreply.github.com>
…DIA#14074) Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com> (cherry picked from commit d178370) Signed-off-by: Fanrong Li <lfr-0531@users.noreply.github.com>
Summary
DeepSeekV3PerfectRouterPlanner._resolve_group_config()only knew how to introspectDeepSeekV3MoeRoutingMethod, which nestsn_group/topk_grouponrouting_impl.DeepSeekV4MoeRoutingMethodstores them directly on the outer object, so passing it in raised at model-init time:This crashed every executor rank when
ENABLE_PERFECT_ROUTER=1was set on DSv4 (e.g.bm_deepseek-v4-pro-eplb-perfectrouter-sol-1024-1024-ratio08-...benchmarks). The error path went throughDeepseekV4MoE.__init__->ConfigurableMoE.__init__->_init_perfect_router()->precompute_common_perfect_router_logits()->planner.get_cache_signature()->_resolve_group_config(), hitting the same exception on the fallbackmodel_loader.load()retry.Change
Fall back to the routing method itself when
routing_implis absent. Both V3 (nested onrouting_impl) and V4 (flat on the outer object) layouts now resolve to the same(n_group, topk_group)tuple, and the error message is updated to mention both supported shapes.Add a CPU-only regression test
test_perfect_router_resolve_group_configparametrized over both routing classes that drives the planner directly.Impact
ENABLE_PERFECT_ROUTER=1on DSv4 (perfect-router load-balancer benchmarks).routing_implfirst.Test Plan
pre-commit runclean on both modified filespytest tests/unittest/_torch/modules/test_moe_routing.py::test_perfect_router_resolve_group_config(CI)