Repository navigation
moe rebase and refactor - #4394
Conversation
Co-authored-by: zanzhang <zanzhang@amd.com> Co-authored-by: lalala-sh <Jiaxing.Wen@amd.com> Co-authored-by: XingerZhu <233663585+XingerZhu@users.noreply.github.com> Co-authored-by: Felix Li <felix.li@amd.com> Co-authored-by: yanboshao <yashao@amd.com>
🏷️ CI GuideRuns automatically on every PR:
Extended tests (opt-in via labels):
|
There was a problem hiding this comment.
Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit
ruff
Do not perform function call fx.Stream in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable
Do not perform function call fx.Stream in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable
Import block is un-sorted or un-formatted
aiter/aiter/ops/flydsl/kernels/mxfp4_preshuffle_gfx1250_tdm.py
Lines 6 to 29 in cafce66
Local variable SA_SUPERS is assigned to but never used
Unnecessary dict() call (rewrite as a literal)
Local variable N_ELEM is assigned to but never used
Use a single if statement instead of nested if statements
aiter/aiter/ops/flydsl/kernels/mxfp4_preshuffle_gfx1250_tdm.py
Lines 467 to 468 in cafce66
Use X | None for type annotations
aiter/aiter/ops/flydsl/moe_kernels.py
Line 1760 in cafce66
Use X | None for type annotations
aiter/aiter/ops/flydsl/moe_kernels.py
Line 1761 in cafce66
Use X | None for type annotations
aiter/aiter/ops/flydsl/moe_kernels.py
Line 1762 in cafce66
Use X | None for type annotations
aiter/aiter/ops/flydsl/moe_kernels.py
Line 1763 in cafce66
Use X | None for type annotations
aiter/aiter/ops/flydsl/moe_kernels.py
Line 1764 in cafce66
Use X | None for type annotations
aiter/aiter/ops/flydsl/moe_kernels.py
Line 1765 in cafce66
Use X | None for type annotations
aiter/aiter/ops/flydsl/moe_kernels.py
Line 1766 in cafce66
Use X | None for type annotations
aiter/aiter/ops/flydsl/moe_kernels.py
Lines 1896 to 1898 in cafce66
Use X | None for type annotations
aiter/aiter/ops/flydsl/moe_kernels.py
Line 1899 in cafce66
Use X | None for type annotations
aiter/aiter/ops/flydsl/moe_kernels.py
Line 1900 in cafce66
Use X | None for type annotations
aiter/aiter/ops/flydsl/moe_kernels.py
Line 1901 in cafce66
Use X | None for type annotations
aiter/aiter/ops/flydsl/moe_kernels.py
Line 1902 in cafce66
Use X | None for type annotations
aiter/aiter/ops/flydsl/moe_kernels.py
Line 2281 in cafce66
Use X | None for type annotations
aiter/aiter/ops/flydsl/moe_kernels.py
Line 2282 in cafce66
Use X | None for type annotations
aiter/aiter/ops/flydsl/moe_kernels.py
Line 2283 in cafce66
Replace the low-level MLIR/scf/ArithValue construction with flydsl expr if/select, SharedAllocator struct for the double-buffered scan, and _lds_load/_lds_store helpers. Behaviour unchanged. Co-authored-by: Cursor <cursoragent@cursor.com>
…_port_rebase # Conflicts: # aiter/aot/flydsl/grouped_moe.py # aiter/ops/flydsl/grouped_moe_gfx1250.py # aiter/ops/flydsl/kernels/gemm_common_gfx1250.py # aiter/ops/flydsl/kernels/gemm_mxscale_gfx1250.py # aiter/ops/flydsl/kernels/kernels_common.py # aiter/ops/flydsl/kernels/moe_contiguous_psum.py # aiter/ops/flydsl/kernels/moe_fused_route_quant_scatter.py # aiter/ops/flydsl/kernels/moe_gather_reduce.py # aiter/ops/flydsl/kernels/moe_grouped_gemm_mxscale_gfx1250.py # aiter/ops/flydsl/kernels/moe_route_maps.py # aiter/ops/flydsl/moe_kernels.py # op_tests/test_flydsl_grouped_gemm_gfx1250.py # op_tests/test_moe_ep.py
…er into dev/450ep_felix_tdm_port_rebase
…er into dev/450ep_felix_tdm_port_rebase
…it-K The default fp8-blockscale 2-stage fused MoE returns wrong output whenever get_ksplit() asks for model_dim / 256 splits, one 256-wide K tile each. This happens at small decode batches on gfx942 (cu_num 304), for example at one token for (model_dim, inter_dim) = (4096, 256) with 288 experts and top-8, (7168, 128) with 257 experts and top-9, and (2048, 384) with 128 experts and top-8. Every output element differs from the reference, and the values change from run to run. ck_moe_stage1_gemm turns the requested number of splits into CK's KBatch, the number of KPerBlock tiles each split covers: K / (splitk * KPerBlock). With one tile per split that is 1, which DeviceMoeGemmBlockScale reads as "no split": it runs a single z-block over the whole K and skips zeroing the output. The split-K instance still accumulates into that output atomically, and fused_moe allocates it with torch.empty. StrideE also keys the split-K layout (2 * N per row) on KBatch > 1, so the rows overlap as well. ROCm#3997 fixed this in ck_moe_stage1() by turning split-K off for such requests, and the MoE refactor in ROCm#4394 dropped that guard. This fix sits at the KBatch conversion instead, so no caller reaches KBatch == 1 through split-K, whether the split comes from get_ksplit(), a tuned CSV or AITER_KSPLIT. It also keeps the split rather than turning it off: when splitk would leave fewer than two tiles per split, stage 1 uses fewer splits of at least two tiles, KBatch = 2 or the smallest divisor of the tile count that is at least 2. At the (4096, 256, E=288, top-8) one-token shape the operator then takes 32.1 us, against 41.1 us without split-K. A K of a single tile cannot be split and now fails with an error. Requests that already give two or more tiles per split are unchanged. Signed-off-by: Jin Tao <jintao12@amd.com>
…it-K (#5979) The default fp8-blockscale 2-stage fused MoE returns wrong output whenever get_ksplit() asks for model_dim / 256 splits, one 256-wide K tile each. This happens at small decode batches on gfx942 (cu_num 304), for example at one token for (model_dim, inter_dim) = (4096, 256) with 288 experts and top-8, (7168, 128) with 257 experts and top-9, and (2048, 384) with 128 experts and top-8. Every output element differs from the reference, and the values change from run to run. ck_moe_stage1_gemm turns the requested number of splits into CK's KBatch, the number of KPerBlock tiles each split covers: K / (splitk * KPerBlock). With one tile per split that is 1, which DeviceMoeGemmBlockScale reads as "no split": it runs a single z-block over the whole K and skips zeroing the output. The split-K instance still accumulates into that output atomically, and fused_moe allocates it with torch.empty. StrideE also keys the split-K layout (2 * N per row) on KBatch > 1, so the rows overlap as well. #3997 fixed this in ck_moe_stage1() by turning split-K off for such requests, and the MoE refactor in #4394 dropped that guard. This fix sits at the KBatch conversion instead, so no caller reaches KBatch == 1 through split-K, whether the split comes from get_ksplit(), a tuned CSV or AITER_KSPLIT. It also keeps the split rather than turning it off: when splitk would leave fewer than two tiles per split, stage 1 uses fewer splits of at least two tiles, KBatch = 2 or the smallest divisor of the tile count that is at least 2. At the (4096, 256, E=288, top-8) one-token shape the operator then takes 32.1 us, against 41.1 us without split-K. A K of a single tile cannot be split and now fails with an error. Requests that already give two or more tiles per split are unchanged. Signed-off-by: Jin Tao <jintao12@amd.com>
Motivation
Technical Details
Test Plan
Test Result
Submission Checklist