Skip to content

[Feat] Fuse MoE activation FP8 quantization kernels - #2089

Open
qiyueliuhuo23 wants to merge 5 commits into
InternLM:mainfrom
qiyueliuhuo23:ws-dev
Open

qiyueliuhuo23 wants to merge 5 commits into
InternLM:mainfrom
qiyueliuhuo23:ws-dev

Conversation

@qiyueliuhuo23

Copy link
Copy Markdown

Summary

This PR fuses activation processing in the tile-wise FP8 MoE grouped GEMM path.

The original implementation reads the same BF16 activation multiple times for:

  • per_tile_quant
  • trans_per_block_quant_expand_128x or trans_per_tile_quant_expand_128x
  • standalone native_swiglu
  • standalone SwiGLU backward

The new Triton kernels reduce redundant BF16 memory traffic and kernel launches while preserving the
existing FP8 layouts and quantization semantics.

Changes

New implementation Replaced path Description
per_tile_quant_with_trans_per_block per_tile_quant + trans_per_block_quant_expand_128x One read of BF16 input, producing row-wise and transposed per-block FP8 layouts
per_tile_quant_with_trans_per_tile per_tile_quant + trans_per_tile_quant_expand_128x One read of BF16 gradient, producing dgrad and wgrad layouts
swiglu_per_tile_quant_with_trans_per_block native_swiglu + independent dual-layout quantization Fuses SiLU(gate) * up and W2 input quantization without materializing BF16 activation
swiglu_backward PyTorch native SwiGLU autograd Computes grad_gate_up in one Triton kernel

Additional integration changes:

  • Integrate the fused path into TileWiseFloat8GroupedLinear and MoEBlock.
  • Add Float8Config.enable_fused_moe_activation.
  • Add FUSED_MOE_ACTIVATION support to the GLM-5.2 example configuration.
  • Add correctness tests for dual-layout quantization, SwiGLU backward, grouped linear, and MoEBlock.
  • Keep the default behavior unchanged. The original implementation is used when the option is disabled.

Correctness

The fused outputs were compared with the original independent kernels on H200:

Check Result
Row-layout FP8 Bitwise equal
Transposed FP8 Bitwise equal
FP8 scales Bitwise equal
Expanded expert sizes Bitwise equal
SwiGLU backward vs native autograd Bitwise equal

The latest 35-step GLM-5.2 candidate run was checked with the standard CI checker. The values below are
the actual baseline-to-candidate comparison at the largest drift position, except TGS, which follows the
checker’s step 11--34 one-sided P80 rule.

Metric Baseline → candidate Difference Threshold Result
loss/local_loss 7.005492687 → 6.990004539 0.221086% (step 14) 1% PASS
loss/reduced_llm_loss 6.514832020 → 6.497645855 0.263801% (step 14) 1% PASS
grad_norm 10.159761429 → 7.160691738 29.519096% (step 24) 100% PASS
memory/max_memory_GB 85.636 → 85.121 0.601383% (step 1) 20% PASS
runtime_info/tgs Mean 1660.282014 → 1613.814901; worst step 30: 1698.927476 → 1556.265145 P80 degradation 5.423210% (max 8.397200%) 6% (P80) PASS
runtime_info/text_tokens 16359 → 16359 (step 1) Maximum absolute difference 0 0 PASS
loss/reduced_balancing_loss N/A → N/A Not recorded on either side 0.0001% N/A

Performance

Single-kernel benchmark

Measured on one H200, with 100 warm-up iterations and 300 measurement iterations. Values are p50;
the time column uses baseline / candidate in milliseconds.

Kernel Input shape Time (baseline / candidate, ms) Speedup
per_tile_quant_with_trans_per_block input [131072, 6144], 256 experts 3.436 / 1.125 3.06x
per_tile_quant_with_trans_per_tile input [131072, 6144], 256 experts 2.551 / 1.144 2.23x
swiglu_per_tile_quant_with_trans_per_block gate_up [32768, 4096] 0.599 / 0.170 3.52x
swiglu_backward gate_up [32768, 4096] 0.629 / 0.161 3.90x
swiglu_per_tile_quant_with_trans_per_block gate_up [131072, 8192], 256 experts 5.070 / 1.263 4.01x
swiglu_backward gate_up [131072, 8192], 256 experts 4.838 / 1.257 3.85x

End-to-end A/B benchmark

GLM-5.2 EP4, 16K pack, 30-step warm-up plus 100-step measurement. Baseline disables
enable_fused_moe_activation; candidate enables it. Other configuration remains unchanged.

Pair Step time (baseline / candidate, s) TGS (baseline / candidate, tokens/s) Peak memory (baseline / candidate, GB)
1 4.551550 / 4.530850 28462.325 / 28598.772 104.519 / 104.817
2 4.549550 / 4.539500 28491.152 / 28570.268 104.918 / 106.340
3 4.549850 / 4.532200 28473.462 / 28599.339 105.175 / 104.768

The end-to-end gain is smaller than the single-kernel speedup because the fused activation kernels account
for only about 36.8 ms of a roughly 4.55 s training step. Even if the entire target kernel time were removed,
the theoretical upper bound for this workload would be approximately 0.81%.

def _assert_equal(actual: torch.Tensor, expected: torch.Tensor, name: str) -> None:
assert actual.shape == expected.shape, f"{name}: shape {actual.shape} != {expected.shape}"
assert actual.dtype == expected.dtype, f"{name}: dtype {actual.dtype} != {expected.dtype}"
assert torch.equal(actual, expected), f"{name}: values differ"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

应该全部用bit-wise对齐?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

已将两个测试文件统一改为 bitwise 比较,重新单测均通过

)
input_block = tl.load(input_offsets, mask=input_mask, other=0.0).to(tl.float32)

reciprocal_fp8_max = 1.0 / FP8_MAX

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

(仅讨论,不是修改建议)量化这一段在融合kernel和独立kernel里的共同部分,是否考虑抽出作为inline调用?重复代码看起来不容易维护

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

将公共量化计算抽取到了 quantization.py 的三个 @triton.jit helper,并且替换了xtuner/tests/float8/triton_kernels下的所有量化操作

([0, 1, 127, 128, 129], 6144),
],
)
def test_per_tile_quant_with_trans_per_block_matches_reference(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

可以记录算子MFU、MBU指标,便于性能评测

@qiyueliuhuo23 qiyueliuhuo23 Sep 17, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

目前检查了 XTuner 的 tests/,没有找到单测中记录 MFU/MBU 的现成例子,我理解单测还是主要做数值对齐。是不是可以单独提供 benchmark 脚本,记录MFU、MBU等指标呢

wangshuo and others added 2 commits September 17, 2026 16:43
Reuse Triton row, column, and block quantization helpers across independent and fused kernels while preserving historical reduction and scale arithmetic.

Require byte-level equality in activation fusion tests. Validated on H200 with 17 passing tests and 164 tensors bitwise equal to pre-refactor outputs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants