Repository navigation
[ROCm][Perf][Kimi-K3] Specialized decode for Kimi-K3 on MI355X - #60683
Conversation
|
Great work! Please use the main switch |
Fangzhou-Ai
left a comment
There was a problem hiding this comment.
can we follow the #60397 with a more organized way for all these kernel files? Putting everything under a common folder make it harder to identify a higher abstract for all mono kernels in the future.
| ), | ||
| # Kimi-K3 decode on MI355X as two persistent FlyDSL launches a layer | ||
| # (vllm/models/kimi_k3/amd/mono). Default off | ||
| "VLLM_ROCM_MONO_K3": lambda: bool(int(os.getenv("VLLM_ROCM_MONO_K3", "0"))), |
There was a problem hiding this comment.
sure will unify the env settings
|
gms8k at conc1 is not sufficient to justify this PR, please use the maximal conc you can take for mono kernel to test. On top of that please do SBS GPQA-Diamond, AIME and NIAH evaluation as well. |
|
@Fangzhou-Ai thank you for your valuable comments. I have updated the followings:
could you plz check if the updates are aligned with your expectation? |
|
Ran a eval suite in parallel. (C=1) Kimi-K3 mono decode (
|
| Eval | Protocol | Score | Mean accept len |
|---|---|---|---|
| GSM8K | 5-shot, 1319 q, temp 0 | strict 0.9697 ± 0.0047 / flexible 0.9689 | 4.72 |
| RULER NIAH single_1 | 40 samples/len, greedy, thinking on | 32K 1.000 · 128K 1.000 · 256K 1.000 | 2.36 |
| RULER NIAH multikey_2 | 40 samples/len, greedy, thinking on | 32K 1.000 · 128K 1.000 · 256K 1.000 | 2.61 |
| RULER NIAH multikey_3 | 40 samples/len, greedy, thinking on | 32K 1.000 · 128K 1.000 · 256K 1.000 | 2.62 |
| GPQA-Diamond, Moonshot settings | 198 q × 2 orders, temp 1.0, top_p 0.95, 128K, effort max | mean 0.9040 over 1 seeds; min 0.9040 / max 0.9040 | 2.62 |
| GPQA-Diamond, Moonshot settings (re-extracted) | same samples, case-sensitive / bold / boxed answer extraction | mean 0.9268 over 1 seeds; empty responses 0/396 | |
| AIME25 | 30 q, boxed, temp 0.6, top_p 0.95, 64K, effort max (K3 tokenizer default) | mean 0.9333 over 4 seeds (σ 0.0000); min 0.9333 / max 0.9333 | 3.16 |
GPQA-Diamond with Moonshot's settings (effort max, temperature 1.0, top_p 0.95; no token limit is stated, so I used 128K) scores 92.7 ± 1.7 after re-grading. Moonshot's official number is 93.5, so the gap is −0.8, about half a standard error. No answer came back empty.
Moonshot publishes no official Kimi-K3 numbers for AIME, GSM8K or RULER/NIAH. For reference, Kimi K2.5 reports 96.1 on AIME25 (96K budget, 32 runs averaged). Of the 8 AIME25 misses (2 per seed), problem 23 got 150 instead of 149 on all four seeds. Problems 21 and 28 were each wrong once with a boxed but incorrect answer. Problems 8 and 13 each came back empty once, likely because the reasoning ran out of the 64K budget.
|
This pull request has merge conflicts that must be resolved before it can be |
1fc98fb to
9c6c96d
Compare
K1 (KDA layers: AttnRes, in_proj, f_b, spec conv, KDA recurrence, gated RMSNorm) and K2 (o_proj + in-kernel all-reduce + MLP AttnRes + latent MoE) for MI355X, under vllm/models/kimi_k3/amd/specialized_decode/mono. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hyukjlee <hyukjlee@amd.com>
Opt in with additional_config={"decode_backend": "latency_specialized"}
(RFC vllm-project#60904, the vllm-project#61867 / vllm-project#60889 shape, layer mode). Everything lives in
vllm/models/kimi_k3/amd/specialized_decode; the Kimi-K3 model files only
call in. Refuses unsupported deployments at startup with every reason;
plan() picks the kernels per step; every TP rank fail-stops at the same
step once a rank gave up an in-kernel wait.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: hyukjlee <hyukjlee@amd.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hyukjlee <hyukjlee@amd.com>
mkdocs-autorefs read kof[slot][t] as a reference link and failed the strict docs build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hyukjlee <hyukjlee@amd.com>
…ut FlyDSL The NVIDIA Kimi K3 job collects tests/models/kimi_k3 too; the KDA cache check reads the kernel's head constants, which import FlyDSL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hyukjlee <hyukjlee@amd.com>
989829c to
b070811
Compare
|
/ci run |
|
✅ Triggered Buildkite CI #96326 for commit ℹ️ This PR is 58 commits behind upstream |
Extend the Kimi-K3 MI355X specialized decode (vllm-project#60683) past 8 rows: - widths: every whole-request width up to 16 rows, plus 18, 20, 24, 28, 30 and 32 rows (those measured faster than vLLM's decode) - K1: 16-row token tiles of whole requests, 32 state rows a task and in_proj weights cached in LDS at the measured shapes (kda.tuned) - K2: compact route table and per-expert pick lists past 16 rows, streamed AttnRes at 8 block sources, 16-row front panels from 28 rows, producer-side latent quantization (layer.tuned) - from 30 rows a KDA layer runs vLLM's AttnRes and in_proj, then K1's KDA stages (kda_post, one CTA a request and head) No weight is copied; every new wait goes through the health-checked mailbox. Tests extend the existing amd_specialized_decode suite; no new CI step. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: jiacao-amd <jiahui.cao@amd.com>
…ernel) Opt-in TP2 decode for Qwen3.8-Flash-Next (amd/Qwen3.8-Flash-Next-Quark-MXFP4) on MI355X/gfx950 following the specialized decode layout of RFC vllm-project#60904: vllm/models/qwen4_exp/amd/specialized_decode/, enabled with --monokernel, step mode, Model Runner V2 only. A decode step of 1-16 rows runs four persistent FlyDSL launches a layer: the attention hyper-connection front, the GDN block (vLLM's QSA attention on the QSA layers), the o_proj block and the MoE block (after the MLP front). The o_proj and MoE blocks fold the HC combine into their all-reduce epilogue and hand the next front the state's sums of squares. Prefill, mixed, PIECEWISE and wider steps run vLLM's forward. Unsupported deployments are refused at config, model and cache bind, each stage listing every reason, the TP ranks agreeing. The MXFP4 GDN projections are read in the layout of whichever AITER FP4 GEMM vLLM picked for the shape (ASM or Triton), quantizing their inputs as that GEMM does. The kernels build on the Kimi-K3 decode's helpers (vllm-project#60683; hyukjlee, after ROCm/ATOM): its mailbox with bounded waits and health words, peer memory and GEMV stages. A rank whose wait gives up marks itself failed and flags the output rank; FailStop reads the failed word after every step without blocking and the TP ranks raise together, so the engine stops instead of hanging. Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: Mikko Tukiainen <Mikko.Tukiainen@amd.com> Co-authored-by: Cursor <cursoragent@cursor.com>
…ernel) Opt-in TP2 decode for Qwen3.8-Flash-Next (amd/Qwen3.8-Flash-Next-Quark-MXFP4) on MI355X/gfx950 following the specialized decode layout of RFC vllm-project#60904: vllm/models/qwen4_exp/amd/specialized_decode/, enabled with --monokernel, step mode, Model Runner V2 only. A decode step of 1-16 rows runs four persistent FlyDSL launches a layer: the attention hyper-connection front, the GDN block (vLLM's QSA attention on the QSA layers), the o_proj block and the MoE block (after the MLP front). The o_proj and MoE blocks fold the HC combine into their all-reduce epilogue and hand the next front the state's sums of squares. Prefill, mixed, PIECEWISE and wider steps run vLLM's forward. Unsupported deployments are refused at config, model and cache bind, each stage listing every reason, the TP ranks agreeing. The MXFP4 GDN projections are read in the layout of whichever AITER FP4 GEMM vLLM picked for the shape (ASM or Triton), quantizing their inputs as that GEMM does. The kernels build on the Kimi-K3 decode's helpers (vllm-project#60683; hyukjlee, after ROCm/ATOM): its mailbox with bounded waits and health words, peer memory and GEMV stages. A rank whose wait gives up marks itself failed and flags the output rank; Kimi-K3's FailStop (now taking the model's name and fallback hint for its error) reads the failed word after every step without blocking and the TP ranks raise together, so the engine stops instead of hanging. Signed-off-by: Mikko Tukiainen <Mikko.Tukiainen@amd.com> Co-authored-by: Cursor <cursoragent@cursor.com>
…1), DCP8 On top of vllm-project#60683's Kimi-K3 specialized decode on MI355X: - K1 / K2 serve up to 16 rows (MAX_ROWS; the route table sized for 64), faster K2 at every served width. - M1: the MLA layers' prologue (M1a: q/kv GEMMs, RoPE, fp8 KV write, the decode query) and epilogue (M1b: split / peer LSE combine, W_UV, gate, in K2's launch). Layers that cannot run M1 (non-fp8 KV, FP4BMM off) run vLLM's attention ops, then K2. - M1c: FlyDSL MLA decode attention in K2's launch at DCP1, qlen 4 / 8, at the widths whose KV splits share out over the requests; other widths and DCP8 run AITER's asm decode. - DCP8: M1a gathers the query over peer memory, M1b combines the ranks' LSE. TP8, MI355X, vllm-project#60683's matrix, TPOT p50 (ms), vllm-project#60683 on -> this, DCP1: c1 k7 8k 4.35 -> 3.60, c1 k7 64k 4.47 -> 3.81, c2 k3 8k 16.79 -> 14.23, c4 k1 8k 22.18 -> 13.63, c8 k1 8k 32.58 -> 17.06. GSM8K (1319, DCP1, k7): 0.967 strict / 0.967 flexible. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: seungrokj <seungrok.jung@amd.com>
Add an opt-in specialized decode for Muse Spark Open at TP8 on MI355X (gfx950) following RFC vllm-project#60904 (layer mode). On a pure decode step (or a pure DSpark verify step) of at most 8 rows, every decoder layer whose routed experts run AITER's MXFP4 x MXFP4 MoE (layers 1..60 of the Quark checkpoint) becomes one persistent FlyDSL launch (K2: 256 CTAs x 512 threads, one a CU) covering o_proj + its all-reduce, the attention boundary, the fp32 router and top-8 routing, the pooler, the pre-expert norm and MXFP4 quant, the routed experts, the column-owner expert reduce, the post-expert norm, the route weights and the unpooler. vLLM's attention runs up to o_proj's input (Phase A). The kernels read vLLM's loaded weights in place. - Switch: --monokernel or additional_config decode_backend=latency_specialized; off by default and inert when off. - Refusals in three stages (config, loaded model, KV caches), each listing every reason; default-deny; every TP rank agrees on each verdict. - Fail-stop: bounded in-kernel waits; all ranks stop at the same step. - Code lives in vllm/models/muse_spark/amd/specialized_decode/ and amd/model_state.py; amd/model.py only calls in. - Tests: CPU runtime/spec/layout tests, a GPU-less compile gate, 1-GPU stage probes, 8-GPU numerics/graph-replay/fail-stop/speed tests and a served engine-fault test; CI steps for MI355. MI355X x8, TP8, 2048 in / 1024 out: median TPOT 8.95 -> 5.10 ms at c1 (1.76x), 9.90 -> 6.47 ms at c4 (1.53x), 11.19 -> 8.59 ms at c8 (1.30x); GSM8K at parity (c8: 95.15 vs 95.30, McNemar p=0.86). FlyDSL helpers adapted from the Kimi-K3 AMD specialized decode (vllm-project#60683), itself adapted from ROCm/ATOM atom/mono (MIT). Signed-off-by: Oxana Korzh <okorzh@amd.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ernel) Opt-in TP2 decode for Qwen3.8-Flash-Next (amd/Qwen3.8-Flash-Next-Quark-MXFP4) on MI355X/gfx950 following the specialized decode layout of RFC vllm-project#60904: vllm/models/qwen4_exp/amd/specialized_decode/, enabled with --monokernel, step mode, Model Runner V2 only. A decode step of 1-16 rows runs four persistent FlyDSL launches a layer: the attention hyper-connection front, the GDN block (vLLM's QSA attention on the QSA layers), the o_proj block and the MoE block (after the MLP front). The o_proj and MoE blocks fold the HC combine into their all-reduce epilogue and hand the next front the state's sums of squares. Prefill, mixed, PIECEWISE and wider steps run vLLM's forward. Unsupported deployments are refused at config, model and cache bind, each stage listing every reason, the TP ranks agreeing. The MXFP4 GDN projections are read in the layout of whichever AITER FP4 GEMM vLLM picked for the shape (ASM or Triton), quantizing their inputs as that GEMM does. The mailbox with bounded waits and health words, the peer memory, the GEMV stage and FailStop are copies of the Kimi-K3 decode's (vllm-project#60683; hyukjlee, after ROCm/ATOM), trimmed to what these kernels use, so the package imports nothing of Kimi-K3's. A rank whose wait gives up marks itself failed and flags the output rank; FailStop reads the failed word after every step without blocking and the TP ranks raise together, so the engine stops instead of hanging. Signed-off-by: Mikko Tukiainen <Mikko.Tukiainen@amd.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Purpose
An opt-in specialized decode for Kimi-K3 on MI355X (gfx950), TP8, following RFC #60904. It uses the same
specialized_decodeshape as #61867 (Kimi-K3, NVIDIA) and #60889 (GLM-5.2, ROCm), in layer mode. It is enabled withadditional_config={"decode_backend": "latency_specialized"}and has no other options.A pure spec-verify decode step of at most 8 rows runs each MoE decoder layer as persistent FlyDSL MonoKernels. The TP all-reduces run in-kernel over peer memory:
The kernels read vLLM's loaded weights and KDA states in place. Every other step (prefill, mixed, wider and PIECEWISE steps) runs vLLM's layers. With
decode_backend=auto(the default) nothing changes.Layout: no common code
The existing Kimi-K3 files only call into the folder (26 added lines):
linear.py:specialized_decode_config()in__init__before any module allocates weights,plan_specialized_decode()inforward,(step.layer(i) or layer)(...)in the layer loop, andafter_specialized_decode_step()incompute_logits.model.py:get_model_state_cls.mla.py:skip_o_proj, which returns o_proj's input for the MLA layers' K2.Outside
vllm/models/kimi_k3/the only change is one Buildkite step.Refusal and steps
ValueErrorthat lists every reason. Refusals run in three stages: the config in__init__, the loaded weights when the model state builds the executor, and the KV caches at every bind. Every TP rank agrees on each verdict. It is default-deny for PP/DP/EP/EPLB/PCP, DBO, LoRA, KV connectors, routed-expert capture, sleep mode, CPU offload, weight updates, adaptive or dynamic speculative decoding, ReplaySSM/RecoverSSM, the V1 runner,STOCK_TORCH_COMPILE, other model shapes, and other GPUs or partitioned GPUs.plan()runs once per step. It picks the kernels for pure spec-verify steps of whole uniform requests at a built width, i.e. multiples ofk+1up to 8 rows.Fail-stop
Every in-kernel wait gives up after 10 s. The rank records it in its sticky health words, so a stalled peer fails every rank instead of hanging them. In
compute_logitseach rank queues a non-blocking copy of itsFAILEDword. Every 16 steps the TP ranks agree on what has landed over the TP CPU group, and then every rank raises at the same step. This keeps all ranks out of the next collective.Detection takes up to about 16 steps. A zero-delay check through a core hook can follow in a separate PR.
Not a duplicate
kimi_k3/amd/.Test Plan
plan()routing (PIECEWISE, too wide, prefill, PP input, unbound or re-bound KV cache), weight-view refusals.Kimi-K3, TP8, DCP8, DSpark MTP, fp8 KV,
--stream-interval 10, MI355X, FULL CUDA graphs, Model Runner V2. "Off" means the same image, tree and flags withdecode_backend=auto.Test Result
This revision ran on 8x MI355X with
vllm/vllm-openai-rocm:nightly-rocm100-1b2a6663, which is 20 commits behind this branch's base with nokimi_k3, mamba,gdn_attnor model-state changes in between. This branch'svllm/models/kimi_k3/was mounted over the image.tests/models/kimi_k3: 420 passed, 0 failed (89 skipped). This covers the new suite and every existing Kimi-K3 test.ValueErrorwith all three reasons.decode_backend="fast"is rejected.Kimi-K3 specialized decode: 92 layers, widths [8], 30 builds.Accuracy, previous revision (same kernels, ISA byte-identical)
The kernel path serves steps of at most 8 rows, so these configs fuse every decode step (conc x (k+1) <= 8):
Paired GSM8K (1319 q, c4/k1): 18 right only with the kernels on, 27 right only with them off, McNemar exact p = 0.23.
Performance, previous revision
vllm bench serve, random, 1024 output tokens, ignore-eos, 2 seeds. TPOT p50 in ms:* Synthetic acceptance length 1.0, so TPOT is the decode step time at that width. c1/k7 uses the CI's synthetic acceptance length 3.84.
Per-layer time (graph-replayed, profiler): K1 36.7 us (vs about 54 us plus gaps for vLLM's ops), K2 104.8 us (vs about 178 us).
AI assistance (Claude) was used to develop this change.
🤖 Generated with Claude Code