Skip to content

[Perf] [AMD] Qwen4-Exp HC: fuse decode-sized hyper-connection norm and inject into FlyDSL mix - #48648

Open
amd-cgilli wants to merge 1 commit into
sgl-project:mainfrom
amd-cgilli:perf/amd-qwen4-fused-hc-decode
Open

amd-cgilli wants to merge 1 commit into
sgl-project:mainfrom
amd-cgilli:perf/amd-qwen4-fused-hc-decode

Conversation

@amd-cgilli

@amd-cgilli amd-cgilli commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

On Qwen3.8-Flash-Next (qwen4_exp_text), each hyper-connection (HC) site at decode runs the per-branch Gemma RMSNorm, the mix and the combine's inject GEMV as separate launches. At decode-sized batches these sites are launch- and memory-bound on MI355X.

Modifications

  • kernels/ops/gemm/hc_fused_flydsl.py (new): FlyDSL kernels that fold the per-branch RMSNorm and the inject GEMV into the HC mix (hc_fused_mix); the combine becomes one elementwise kernel (hc_apply_inject) that also returns the sums of squares of its output. The inject logits travel in the gate-partials slot. Both are registered as gemm.hc_fused_mix / gemm.hc_apply_inject (FlyDSL, HIP).
  • layers/hyperconnection.py: GatedResidual uses them on gfx950 for HC sites with <= 128 rows; larger batches keep the existing path unchanged.
    • combine_and_normalize returns the combine's sums of squares in place of the next norm, and the next fused mix takes them as normalized_input. Without them (first layer, PLE layers) the down kernel computes them.
    • Weight shapes are checked once at init (hc_fused_shapes_supported); a site with unsupported shapes stays on the existing path.
    • Per call, the site reuses flydsl_hc_mix_supported from [Perf] [AMD] Qwen3.8: AITER FlyDSL hc_mix for Qwen3.8 hyper-connections on gfx950 #41880 (bf16, contiguous, 16-B aligned, 1-128 rows) and skips the fused path under torch.compile.
  • environ.py: SGLANG_OPT_QWEN4_FUSED_HC (default off).
  • test/registered/kernels/ops/gemm/test_hc_fused_flydsl.py (MI35x suite): kernels vs the unfused reference, including the mix -> combine -> mix chain that passes the sums of squares.

Co-authored with Nikolai Protasov.

Accuracy Tests

Not bit-exact: the normed input and (1 + w) are no longer rounded to BF16 separately. On MI355X, fused vs unfused for M = 1-128: combine outputs within 1 BF16 ulp, with the same error against an fp32 reference as the unfused path; M = 129 falls back and is bit-exact; CUDA-graph replay equals eager.

GSM8K (1319, real MTP verification, Qwen3.8-Flash-Next TP1): 96.3% with SGLANG_OPT_QWEN4_FUSED_HC=1 vs 96.6% with it off (same upstream main, same AITER).

Speed Tests and Profiling

MI355X, per HC site (K=10240, R=320), mix + combine, CUDA graph over 16 layers:

M Unfused (us) Fused (us) Speedup
1 38.2 12.7 3.0x
24 34.3 17.1 2.0x
96 41.8 24.5 1.7x
128 41.6 29.3 1.4x

Related: #46881 (AMD Triton seam fusion, draft), #40552 (SM100 HC), ROCm/aiter#5913 (two-stage FlyDSL gated residual).

Checklist

amd-cgilli added a commit to amd-cgilli/sglang that referenced this pull request Nov 5, 2026
… (11 + 16); PR links with state badges in the tables
…d inject into FlyDSL mix

On gfx950, behind SGLANG_OPT_QWEN4_FUSED_HC, HC sites with <= 128 rows fold
the per-branch Gemma RMSNorm and the combine's inject GEMV into a FlyDSL HC
mix (down split-K -> reduce + SiLU -> up + gate). The mix hands its combine
the inject logits as gate partials, so the combine is one elementwise kernel
that also returns the sums of squares the next mix needs;
combine_and_normalize passes them on in place of the next norm, and the next
mix takes them as its normalized_input.

Qwen K=10240, R=320, mix + combine per site: 33 -> 11 us at M=1,
34 -> 15 us at M=24, 45 -> 25 us at M=96. Not bit-exact (BF16 rounding
points of the normed input and (1 + w) move).

Co-authored-by: Nikolai Protasov <nprotaso@amd.com>

@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.

@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Required checks failed on ac68749; this PR cannot be merged until they pass.

PR title (run)

PR title must use "[Type] scope: title" or "[Type] [Hardware] scope: title". Type must be one of: Feat, Fix, Refactor, Perf, Doc, Test, CI, Chore. Scope is required and may be any module or model name, with unrestricted letter case (letters, numbers, dots, underscores, slashes, or hyphens). Hardware is optional; use a single tag without spaces. Use uppercase hardware tags (AMD, NVIDIA, NPU, MI300X), except for exactly these four spellings: Intel, Apple, Huawei, Ascend. Reverts must use GitHub's default format: Revert "original title". Use one space between fields and after the colon, with a non-empty title and no leading or trailing whitespace. Examples: "[Fix] attention: Fix KV cache indexing", "[Feat] qwen3: Add model support", "[Perf] [AMD] flash-attn: Optimize decode performance".
Edit the title; the check reruns on its own.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant