Skip to content

[ROCm][Kimi-K3] Fuse MLA sigmoid-mul with per-token FP8 for o_proj - #55043

Open
rebklee wants to merge 5 commits into
vllm-project:mainfrom
rebklee:rebklee/k3-mla-mul-fp8-oproj
Open

rebklee wants to merge 5 commits into
vllm-project:mainfrom
rebklee:rebklee/k3-mla-mul-fp8-oproj

Conversation

@rebklee

@rebklee rebklee commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Purpose

Depends on #54248 (K3 o_proj becomes Fp8PtpcOnlineLinearMethod). Until this lands, this path is a no-op.

Fuse MLA attn_out * sigmoid(g_proj) with PTPC o_proj's per-token FP8 quant into one Triton kernel (replaces ATen sigmoid, ATen mul, and dynamic_per_token_scaled_quant).

Wrap (fp8, scale) as QuantizedActivation(kFp8DynamicTokenSym) so PTPC o_proj skips in-kernel quant. g_proj GEMM stays separate.

Not a duplicate. No other PR produces per-token FP8 from the MLA sigmoid gate. #50664 stops at BF16. #54254 is KDA.

Profile

128k/1k, conc=1, 8×MI355X, TP8, Kimi-K3 + DSpark, 50 decode steps. Image vllm/vllm-openai-rocm:nightly-7c5dc571cbd1064ecc8a9b1045637ff647aa22cb. Overlay is --quantization-config PTPC o_proj only.

Unfused

Sigmoid, mul, and per-token quant are still three launches.

Kernel Calls CUDA avg
vectorized_elementwise_kernel<8, sigmoid_kernel_cuda, BFloat16> 1200 3.977 µs
vectorized_elementwise_kernel<8, MulFunctor<float>, BFloat16> 1200 4.306 µs
aiter::dynamic_per_token_scaled_quant_kernel<fp8e4m3, 8> 4650 4.086 µs

(The 4650 quant launches are 1200 MLA + 3450 KDA.)

MLA-only epilogue ≈ 12.4 µs (4.0 + 4.3 + 4.1).

Fused (this PR)

Sigmoid, mul, and per-token quant are one launch. Kineto names the Triton kernel _kernel.kd.

Kernel Calls CUDA avg
_sigmoid_mul_fp8_per_token_kernel (_kernel.kd) 1200 4.079 µs
vectorized_elementwise_kernel<8, sigmoid_kernel_cuda, BFloat16> 0
vectorized_elementwise_kernel<8, MulFunctor<float>, BFloat16> 0
aiter::dynamic_per_token_scaled_quant_kernel<fp8e4m3, 8> 0

MLA epilogue 12.4 → 4.1 µs (−8.3 µs / MLA layer, ~0.20 ms/step × 24 MLA).

Accuracy

GSM8K lm_eval 5-shot, speculative decoding off, n=1319, temperature 0.

Filter exact_match
flexible-extract 0.9651 ± 0.0051
strict-match 0.9659 ± 0.0050

Tests

  • tests/models/kimi_k3/test_amd_mla_oproj_ptpc.py — fused vs sequential; decline without input_quant_key or on mismatched shapes; _gated_o_proj falls through to BF16 when the layer is not PTPC, and passes QuantizedActivation(kFp8DynamicTokenSym) when it is.
  • GPU: sigmoid_mul_fp8_per_token matches the torch reference (x * sigmoid(g) then per-token amax). Scale rtol/atol 1e-4; dequant rtol/atol 1e-2. Shapes include T=0 and TP8 K=1536.

Signed-off-by: Rebecca Lee <rebecca.lee@amd.com>
Signed-off-by: Rebecca Lee <rebecca.lee@amd.com>
@mergify mergify Bot added kimi k3 rocm Related to AMD ROCm labels Sep 3, 2026
@github-project-automation github-project-automation Bot moved this to Todo in AMD Sep 3, 2026
@mergify

mergify Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts that must be resolved before it can be
merged. Please rebase the PR, @rebklee.

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase label Sep 4, 2026
@mergify mergify Bot removed the needs-rebase label Sep 9, 2026
@rebklee
rebklee marked this pull request as ready for review September 9, 2026 17:07

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.


return self._gated_o_proj(attn_out, hidden_states)

def _gated_o_proj(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this here. the unit test won't call this ever, and it'll just confuse other callers

@simondanielsson simondanielsson left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

)
t, k = x.shape
_, fp8_max = get_fp8_min_max()
if not HAS_TRITON or t == 0 or k > _MAX_K:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Question: not sure how common k > 8192 is, but in that case is it still better to run the fused torch version rather than the unfused variant? Some perf numbers here would be great
  2. Suggestion: if we do point 1, can we drop the triton check here (also as its already in the maybe_fused_mla_oproj_ptpc). In that case we could also move _sigmoid_mul_fp8_torch to the test file and just have it as a reference implementation

rebklee added a commit to rebklee/vllm that referenced this pull request Sep 16, 2026
This branch carried its own copy of vllm-project#54248: the three aiter.py
input_quant_key() methods, the online/fp8.py QuantizedActivation
plumbing, and the contract test's AITER kernel registrations. Those
files now come from vllm-project#54248 alone, and this branch keeps only the KDA
gated-RMSNorm fusion, inert until vllm-project#54248 lands -- the same dependency
that vllm-project#55043 already has.

Signed-off-by: Rebecca Lee <rebecca.lee@amd.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

k3 kimi rocm Related to AMD ROCm

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

3 participants