Repository navigation
[ROCm][MoE] Accumulate the shared-expert output in AITER's stage 2; fold routed scaling into top-k - #65207
[ROCm][MoE] Accumulate the shared-expert output in AITER's stage 2; fold routed scaling into top-k#65207micah-wil wants to merge 3 commits into
Conversation
Without shared-expert fusion, have the router fold routed_scaling_factor into the top-k weights instead of scaling the bf16 MoE output, and pass the factor to AITER's biased_grouped_topk, which applies it in-kernel, rather than multiplying the weights afterwards. Removes one elementwise kernel per MoE layer; the weights are bit-identical. Signed-off-by: Micah Williamson <micah.williamson@amd.com>
When the modular kernel's experts support it (AITER fused_moe with accumulate_output / output_ready_event), the routed experts take the shared-expert output as the stage-2 addend instead of the runner adding the two bf16 outputs after the MoE op. The aux-stream shared expert stays overlapped with sorting and stage 1: AITER waits on its ready event only right before stage 2. The runner then uses the single-output moe_forward op and falls back to an in-op add when the experts decline the output. Signed-off-by: Micah Williamson <micah.williamson@amd.com>
QuarkOCP_MX_MoEMethod.apply dropped shared_experts, so the modular kernel never saw them: no MK-internal overlap and no shared-output accumulation. Signed-off-by: Micah Williamson <micah.williamson@amd.com>
|
This pull request has merge conflicts that must be resolved before it can be |
|
Hi @micah-wil, we've been validating this on MiniMax-M3.1-Flash (Quark MXFP4, TP4, MI355X, DSpark 7 drafts, aiter 0.1.27 as pinned) and wanted to share measurements in case they help move it along. Commit 1 (fold
Commits 2 and 3 (addend fold into stage 2)
Suggestion: commit 1 stands on its own and doesn't depend on the aiter hook. Would you be open to splitting it into its own small PR so it can merge independently? We're happy to either open it from our branch (with you credited as co-author) or hand you our test ( (Measurements gathered with Claude Code assistance on a MI355X node.) |
Purpose
On ROCm with AITER MoE, the shared-expert output was added to the routed output by a separate bf16 elementwise add after the MoE op. This PR has the routed experts take the shared-expert output as the stage-2 addend instead, so AITER accumulates it in the GEMM2 epilogue and the add kernel goes away. Targets MiniMax-M3.1 (shared expert, no AITER shared-expert fusion), but nothing in the accumulate path is model-specific.
Three commits:
Fold routed scaling into the AITER top-k weights (
[ROCm][MiniMax-M3]).Without shared-expert fusion, the router folds
routed_scaling_factorinto the top-k weights (passed to AITER'sbiased_grouped_topk, which applies it in-kernel) instead of scaling the bf16 MoE output. The weights are bit-identical. This also removes one elementwise multiply per MoE layer.It is also a prerequisite for commit 2: with
apply_routed_scale_to_output=False,MoERunner.routed_scaling_factoris1.0, which is the condition the accumulate path requires. Applying the scale to the output would also scale the shared output once it is folded into the same tensor.Accumulate the shared-expert output in AITER's stage 2 (
[ROCm][MoE]).When the modular kernel's experts support it, the routed experts receive the shared-expert output as
addend(plus anaddend_readyevent) and AITER accumulates it in stage 2. The aux-stream shared expert still overlaps with sorting and stage 1; AITER waits on its ready event only right before stage 2. The runner then uses the single-outputmoe_forwardop, and falls back to an in-op add if the experts decline the output.Enabled only when all of these hold: experts report
supports_output_addend(), no routed input/output transform,routed_scaling_factor == 1.0, no naive dispatch/combine,pcp_size == 1, output not already reduced, no unpadded output / hidden-dim padding.Pass shared experts to the OCP MX MoE kernel (
[Quark][MoE]).QuarkOCP_MX_MoEMethod.applydroppedshared_experts, so the modular kernel never saw them (no MK-internal overlap, no accumulation). One-line fix, required for commit 2 to take effect on Quark MXFP4 checkpoints.Dependencies
fused_moe(accumulate_output=..., output_ready_event=...): TODO link AITER PR.rocm_aiter_ops.fused_moe_supports_accumulate_output(). On an AITER without it,supports_output_addend()is False and the existing separate-add path runs unchanged.Scope note
Commit 3 and the accumulate path are not MiniMax-specific. Any model on the Quark OCP MX + AITER modular-kernel path that has shared experts and a runner
routed_scaling_factor == 1.0will now take the accumulate path when AITER supports it. I only tested MiniMax-M3.1.Test Plan
tests/kernels/moe/test_rocm_aiter_moe.py,test_shared_fused_moe_routed_transform.py,test_rocm_aiter_topk.py,test_rocm_aiter_num_expert_group.py,test_fused_topk.py.Test Result
Unit tests: 1010 passed, 8 skipped. This is a fallback-path run with stock AITER. The accumulate fast path was only exercised end to end with the AITER branch.
Profile (rank 0, one decode step, 57 MoE layers). The "after" trace had every optimization in this series enabled, not this PR in isolation:
AUnaryFunctor<bf16, MulFunctor<float>>(routed-scale multiply)CUDAFunctor_add<bf16>(shared + routed add)The scale multiply can only come from commit 1. The attribution of the add kernels to commit 2 is by inference; I have not profiled this PR alone.
TODO: attach the trace screenshots.