Repository navigation
[HIP] Tune Qwen3.8-Flash-Next MXFP4 a4w4 MoE on gfx950 and add its aux shape - #6708
Conversation
… aux shape Qwen3.8-Flash-Next-Quark-MXFP4 (E=513 with the fused shared expert, topk 11, model_dim 2560, inter 640) had no tuned fused_moe rows and fell back to the heuristic FlyDSL kernels. Add (513, 2560, 768, 11) to the MXFP4 MoE aux shapes so the MXMOE port (inline sort/quant gemm1 + layout gemm2) can run it, and a tuned table for token 1-16384 picked by end-to-end timing of the production fused_moe path (real routing for token >= 1024). The rows are keyed on inter_dim 640, i.e. the unpadded expert layout that ATOM's Qwen4-Exp uses once its intermediate is no longer padded to 768. Co-authored-by: Cursor <cursoragent@cursor.com>
🏷️ CI GuideRuns automatically on every PR:
Extended tests (opt-in via labels):
One backend per PR: PR title tags & labels: |
|
vLLM A/B on MI355X, Qwen3.8-Flash-Next-Quark-MXFP4 at TP1: +4.6% output tok/s at TP1 (geomean of 11 points, +1.3% to +8.8%) and GSM8K unchanged. Scope. vLLM rounds the MXFP4 expert intermediate up to 128, so at TP1 the routed MoE reaches AITER as Setup.
GSM8K (5-shot, n = 1319, flexible-extract): stock 0.869 / 0.870, PR 0.877 / 0.879 (± 0.009). |
|
please resolve conflicts |
Resolve the MXFP4 MoE aux shape list conflicts in aiter/ops/moe_mxfp4_aux.py and csrc/kernels/mxfp4_moe/moe_aux/codegen/gen_instances.py by keeping the union: main's Qwen3.8 TP=8 (513, 8192, 256, 11) from #6468 and the GLM-5.3-Flash TP=2/4/8 shapes from #6435, plus this PR's Qwen3.8-Flash-Next TP=1 (513, 2560, 768, 11). Co-authored-by: Cursor <cursoragent@cursor.com>
|
@yzhou103 Conflicts are resolved. I merged
Details are under "Update after #6769" in the description. |
Summary
Qwen3.8-Flash-Next-Quark-MXFP4's routed MoE (E=513 incl. the fused shared expert, topk 11, model_dim 2560, inter 640, a4w4 per_1x32) had no tuned
fused_moerows on gfx950 and ran the heuristic FlyDSL v1 kernels. This PR adds(513, 2560, 768, 11)to the MXFP4 MoE aux shapes so the MXMOE port (flydsl_mxmoe_g1_a4w4_*with inline sort/quant +flydsl_moe2_layout_*) can run it, and a tuned table for token 1–16384. MoE kernel time per step drops 24% at the decode working point and 29% at the 16k prefill working point.The rows are keyed on
inter_dim=640, the unpadded layout. ATOM pads this model's experts to 768 today and MXMOE does not take an intermediate pad, so the table only takes effect together with ROCm/ATOM#2649 (keeps 640 unpadded at TP1). Without that PR nothing changes (no rows match 768). Running the model with MTP also depends on ROCm/ATOM#2606.Motivation
Qwen3.8-Flash-Next (
amd/Qwen3.8-Flash-Next-Quark-MXFP4) optimization on MI355X, https://github.com/wuhuikx/LLM-Booster/issues/263 (item 3, MoE tuning: "prefill stage2 is slow", tuned_fmoe for this shape).Changes
aiter/ops/moe_mxfp4_aux.py,csrc/kernels/mxfp4_moe/moe_aux/codegen/gen_instances.py: add(513, 2560, 768, 11)(aux key = inter rounded up to 256, like MiniMax-M3's 384 → 512). Rebuildsmodule_moe_mxfp4_aux(~18 s JIT).aiter/configs/model_configs/qwen3_8_flash_fp4_{tuned,untuned}_fmoe.csv: 15 rows, token 1, 2, 4, …, 16384 (get_padded_Mbuckets), gfx950 / cu_num 256. BM16 inline-quant gemm1 for token ≤ 512, BM64 for 1024–8192, BM128 +scattergemm2 for 16384.op_tests/test_mxfp4_moe_aux_codegen.py: CPU check that every entry ofMXFP4_MOE_SUPPORTED_SHAPEShas a generated aux instance (read viaast, no aiter import).How the table was tuned:
gemm_moe_tune.py's isolated stage timing did not match the production path for this shape (e.g. it reports 12 µs for a token-64 stage1 that must read ~600 MB of weights, and leaves outmoe_reduction/scatter_reduce), so the candidates (allMxfp4FlydslTuner._g1_variantsgemm1 configs × layout gemm2 with matching tile_m) were timed end to end throughaiter.fused_moe(sort + quant + both stages + reduce; CUDA graph replay for token ≤ 512), with ATOM's weight shuffle, the shared expert always selected, 6 rotating weight copies (so decode does not sit in MALL), and for token ≥ 1024 routing dumped from the real model on long coding prompts. Candidates with > 5% relative L2 error vs the default path were dropped. Theuscolumn is that end-to-end time.Accuracy
GSM8K (lm-eval, real MTP verification), TP1, MTP 3:
Performance
Test config: image
rocm/atom-dev:latest(566aa3dc9d5d), ATOM53e4fb524(+ #2606 + the ATOM PR above), AITER948dd267f+ this PR's diff (the 13 commits between948dd267fand this PR's base touch none of the files or kernels involved), MI355X, TP1, MTP 3, bf16 KV.Server profile under AgentX C16 load (torch profiler, 15 s window after 420 s warm-up). Decode = all pure decode steps replaying the bs=16 graph (
decode[bs=9/16 tok=36 d=9 spec=3]pads to it); prefill =prefill[bs=1 tok=16384 ctx=98304]. µs per step (48 MoE layers):(Prefill non-MoE kernels vary ±5% between servers; the MoE columns are the comparable part.)
Isolated
fused_moe(same weights layout as ATOM, shared expert always selected + 10 uniform routed, 6 rotating weight copies, µs per call):(The heuristic kernels at 640 unpadded take the same time as at 768 with
intermediate_pad=128within noise, e.g. decode 76.6 / 42.9 vs 75.9 / 43.6 µs for stage1 / stage2, so the gain here comes from the table.)AgentX C16:
Cache = GPU prefix, TP1, concurrency 16 for all rows. Runs were done two at a time on separate GPUs of one node (the "ATOM#2649 only" run and the second "+ aiter#6708" run ran side by side).
beforeruns differ by 7% in tput/GPU: that is the run-to-run noise.beforeruns. The extra 25% of KV blocks lifts the realized prefix hit from 62% to 84% on these long-prefix agentic traces, so far fewer prompt tokens are recomputed.beforeruns differ by only 1.3% there) matches the −10% decode-step kernel time; the tput gain is of the same size as the noise.How to use
No flags. AITER merges
aiter/configs/model_configs/*tuned_fmoe*.csvautomatically; the rows match once ATOM runs the model with unpadded inter 640.Test plan
black --check/ruff checkon the changed Python files.pytest op_tests/test_mxfp4_moe_aux_codegen.py: 3 passed (CPU).module_moe_mxfp4_auxrebuilt with the new shape; isolatedfused_moehits all 15 rows ([fused_moe] using 2stage (kernelName1='flydsl_mxmoe_g1_a4w4_…'), no heuristic fallback) and stays within the accuracy gate; full server: GSM8K and AgentX C16 above, server log shows the MXMOE configs for(…, 2560, 640, 513, 11, …).Limitations / follow-ups
uscolumn is from the isolated benchmark. Absolute times differ from the server (e.g. the heuristic 16k stage1 is 860 µs isolated vs 638 µs in the server, while the tuned one is ~365 µs in both), so the server profile above is the end-to-end reference.Update after #6769
Merged
origin/mainat31729e8dbinto this branch (merge commit722791eba, no rebase / force push).MXFP4_MOE_SUPPORTED_SHAPESinaiter/ops/moe_mxfp4_aux.pyandSHAPESincsrc/kernels/mxfp4_moe/moe_aux/codegen/gen_instances.py. Resolved as the union: main's entries and order are kept as they are ([HIP] [MoE] Qwen3.8 TP=8 MXFP4 MoE aux kernel codegen #6468's(513, 8192, 256, 11)and [HIP] [GLM-5.3-Flash] MXFP4 fused-MoE tuned configs for MI355X #6435's six GLM-5.3-Flash entries), and this PR's(513, 2560, 768, 11)goes right after main's Qwen3.8 TP=8 entry in both lists, so the two Qwen3.8 entries sit together.qwen3_8_flash_fp4_{tuned,untuned}_fmoe.csvhas the same header as the other fmoe tables on main; the extrantcolumn in [HIP] [GLM-5.3-Flash] MXFP4 fused-MoE tuned configs for MI355X #6435's GLM table is optional infused_moe.py. The mergedtuned_fmoefamily (54 files, 3414 rows) has no duplicate key.Validation (MI355X,
rocm/atom-dev:nightly_202610221638, ROCm 7.2.4, the merged tree with JIT built from scratch)op_tests/test_mxfp4_moe_aux_codegen.py: 3 passed.is_mxfp4_moe_shape_supported(513, 2560, 640, 11)is True.op_tests/test_moe_2stage.py --no-legacy --csv-filter flydsl_withAITER_CONFIG_FMOEset to this PR's table, which covers(2560, 640, 513, 11): 15/15 cases pass, logits_diff 4.9e-4 to 9.4e-4. Every case hits a tuned flydsl row, with no default fallback.5fea029d, includes fix(qwen4_exp): load unscaled Quark MTP weights as BF16 ATOM#2606) + perf(qwen4-exp): keep 128-aligned MXFP4 expert intermediate unpadded ATOM#2649, TP1, real MTP-3 verification. GSM8K (1319) 0.9788 ± 0.0040 (reference 0.9757–0.978), MTP acceptance 0.723 (3.17 tokens/fwd). WithAITER_LOG_TUNED_CONFIG=1, all 30 MXFP4 MoE lookups in the server hit tuned flydsl rows of this table, with no default fallback.hipb_mmon(16384, 10240, 2560), because the hipBLASLt solution index from [Config] [Perf] Add gfx950 a8w8 bpreshuffle and BF16 GEMM tunings for Qwen3.8 Flash Next #6769 does not exist in hipBLASLt 1.2.70204. That is unrelated to this PR and is fixed in [Config] [Perf] Tune gfx950 BF16 GEMMs for Qwen3.8-Flash-Next (TP1, MTP 3) #6711. For this run,AITER_CONFIG_GEMM_BF16pointed at the merged bf16 tables of [Config] [Perf] Tune gfx950 BF16 GEMMs for Qwen3.8-Flash-Next (TP1, MTP 3) #6711, and every other table came from this branch.