Conversation
… ahead, speculative softmax
The gfx950 fwd_hd128_mxfp6 kernel's pre-shifted Region-B K-scale gather reads each token's E8M0 dword at a +1-byte offset, which runs 1 byte past the scale tensor on the final (token,head,batch). Re-home `scale` into a buffer with trailing slack so that read stays mapped (the pad byte is never consumed by the MFMA op_sel).
Rebuilt from asm/fmha_v3_fwd/mi350/fwd_hd128_bf16_woven.py (diffusion repo bb95bcf0). Verified: builds, deploys, MAE 0 vs known-good, ~1417 TFLOPS.
quantize_fp6_k_lds_order_triton now always emits the 17408B-per-tile K layout (16384B chunk-major fp6 data + a 1024B lane-major K-scale tail: Region A unshifted + Region B pre-shifted), returning a stride-136 k_view. The fwd_hd128_mxfp6 kernel reads the scale straight from the K-buffer tail (coalesced buffer_load lds:1), so the separate K-scale global-load stream -- which was stalling -- is gone. Drops the AITER_MXFP6_PACK_KSCALE_TAIL env knob. Consumers (bench_sage, xDiT attention_backend) use the returned k_view directly and auto-adapt to the new stride; there are no return_raw callers. Also updates the deployed fwd_hd128_mxfp6.co to the matching tail-consuming kernel (tail scale + bf16-MMA QK bias + address-gen hoist) so the packer and kernel stay coherent.
Replace the 32-iteration tl.static_range linear-search E2M3 encode in _pack_qk_fp6_kernel with a branchless round-half-even arithmetic encode. The E2M3 magnitude grid is a minifloat (2 exp bits, 3 mantissa bits, bias 1): normals (mag>=1) are 2^(exp2-1)*(1+m/8), subnormals (mag<1) are m/8. So the search collapses to (a) fp32 RNE-round-to-3-mantissa-bits for the normal range (add 0x7FFFF + kept-LSB, carry into exp) and (b) round-half-even of mag*8 for the subnormal range. Bit-identical to the search and the numpy packer (verified across scales). The pack kernel was compute-bound on the search (~360 GB/s, far below HBM); num_warps/BLOCK_N tuning was a wash. Result: fp6 pack 0.255ms -> 0.089ms; full mxfp6 e2e quant 0.496 -> 0.315ms, flipping mxfp6 e2e above fp8 (hq32 sq8192 1183->1462, hq5 sq65536 2537->2727). Kernel output bit-identical (cos 0.99745/0.99779). Drop the now-dead GRID constexpr param + call-site arg.
The arithmetic-encode _pack_qk_fp6_kernel is bandwidth/latency-bound on its permuted per-block gather, so many small single-warp programs hide the load latency better than fewer wide ones. Measured ~17-19% faster than 128/default-4 across shapes (bit-exact): e.g. N=382500 (H5 S76500) 0.127->0.104ms, N=262144 (H32 S8192) 0.090->0.073ms.
…slot Adds the f6f4 attention variant (fp6 Q/K, per-channel fp4 E2M1 V read via ds_read_b64_tr_b4) as a first-class kernel that coexists with the mainline f6f8 (fp6-QK / fp8-V) build instead of sharing/overwriting one .co slot. - sage_attention_quant_wrappers: add production sage_quant_mxfp6(..., f6f4=, v_fp4_packer=, q_packer=, k_packer=). Computes only the selected V operand (fp8 via sage_quant_v_kernel for f6f8, per-channel fp4 via the caller-supplied packer for f6f4). Q/K default to the in-tree Triton fp6 packers, but q_packer/k_packer can override (e.g. the bench's AITER_MXFP6_PACK swap / numpy fallback). - bench_sage: use the production sage_quant_mxfp6; keep the host-module (hp) Q/K packers (_build_fp6_qk_packer / _build_fp6_k_coalesced_packer via _load_host_fp6_pack, honoring AITER_MXFP6_PACK / AITER_MXFP6_QK_TRITON) and pass them as q_packer/k_packer; f6f4 packs V via the host Triton packer. - dispatch (asm_mha_fwd.cu): pick "f6f4bf16" vs "mxfp6bf16" by V dtype (fp4 uint8 vs fp8); treat f6f4bf16 as mxfp-packed with bf16 output. - mha_fwd.cu: accept f6f4bf16 in the fp6/descale path + v3 support check, and key the kernel cache by (symbol | .co path) so same-symbol/different-.co variants don't collide. - codegen.py: include co_name in the generated config-map key for the same reason. - fmha_fwd.csv: add the f6f4bf16 row -> fwd_hd128_f6f4.co (the .co is deployed separately, not tracked in git). Co-authored-by: Cursor <cursoragent@cursor.com>
| q_scale_mode: AttentionScaleMode, | ||
| k_scale_mode: AttentionScaleMode, | ||
| v_scale_mode: AttentionScaleMode, | ||
| softmax_scale: Optional[float] = None, |
There was a problem hiding this comment.
No! This exact change led to e2e regressions when it was applied to aiter.ops.mha recently. It messes with Inductor and no test is capturing the regression yet.
🏷️ CI GuideRuns automatically on every PR:
Extended tests (opt-in via labels):
|
Move the fused hd128 Hadamard rotation and MXFP4/MXFP6 packing kernels out of the DeepSeek-v4 rotate-quant module and into the module_fmha_v4_fwd ownership boundary. Add native at::Tensor declarations and pybind entries for the two preprocessors, compile the new mha_v4_quant.cu source with the existing v4 extension, and expose the wrappers from aiter.ops.mha_v4. Update bench_sage to consume the v4-owned API. Restore dsv4_rotate_quant.h, dsv4_rotate_quant.cu, rocm_ops.hpp, and aiter.ops.quant to their origin/main state so this PR no longer changes DeepSeek-specific or generic quant surfaces. Also remove the three unrelated a4w4 blockscale tuning rows inherited by the branch. The relocated kernels preserve the original GPU math and launch geometry. They were checked bit-for-bit against the prior generated DeepSeek binding for FP16 and BF16 inputs across multiple multipliers. Validation: python -m pytest op_tests/test_mha_v4.py -q (19 passed); Ruff and git diff checks pass; both relocated gfx950 quantizers build and launch successfully.
Make the native fmha_v4_fwd binding a void out-buffer mutator instead of returning the same storage as an apparently fresh tensor. Wrap it in an MHA v4-local torch.library custom op that marks only out as mutated, keeping the generic compile_ops machinery unchanged. This corrects Inductor's alias and buffer-lifetime model. The previous schema marked every tensor mutable and returned an undeclared alias of out, which produced block-scrambled output in a fully compiled Wan pipeline despite passing standalone numerical checks. Keep mha_v4_packed's public return contract by returning out from Python after the native launch. Add a schema regression test alongside the existing eager/fullgraph parity coverage. Validation: 20 focused MHA v4 tests pass; direct v4 FP8 generated a spatially coherent Wan video at 16.94s; focused Ruff and diff checks pass.
Add fused native K packing and explicit raw-layout helpers to MHA v4, reject incompatible packed layouts, and update the benchmark and tests for the new ABI.
Route the F4F4 row through MHA v4's canonical MXFP4 K buffer, enforce the packed-layout contract, and update benchmarks and tests.
| from enum import IntEnum | ||
| from typing import Optional | ||
|
|
||
| import torch | ||
| import triton | ||
| from torch import Tensor | ||
|
|
||
| from aiter import dtypes | ||
| from aiter.ops.triton._triton_kernels.quant.sage_attention_quant import ( | ||
| sage_quant_v_amax_finalize_kernel, | ||
| sage_quant_v_amax_partial_kernel, | ||
| sage_quant_v_kernel, | ||
| ) | ||
| from aiter.ops.triton.quant.mxfp6_fmha_pack import ( | ||
| fp6_k_raw_buffer_sizes, | ||
| fp6_k_lds_order_views_from_raw, | ||
| reorder_fp6_k_lds_order_triton, | ||
| ) | ||
| from aiter.ops.triton.quant.sage_attention_quant_wrappers import ( | ||
| fp4_v_padded_sequence, | ||
| fp4_v_raw_buffer_size, | ||
| pack_v_mxfp4_colmajor_raw, | ||
| ) | ||
|
|
||
| from ..jit.core import compile_ops | ||
| from ..jit.utils.chip_info import get_gfx | ||
|
|
||
|
|
||
| MHA_V4_LOG2E = 1.4426950408889634 |
There was a problem hiding this comment.
Import block is un-sorted or un-formatted
| from enum import IntEnum | |
| from typing import Optional | |
| import torch | |
| import triton | |
| from torch import Tensor | |
| from aiter import dtypes | |
| from aiter.ops.triton._triton_kernels.quant.sage_attention_quant import ( | |
| sage_quant_v_amax_finalize_kernel, | |
| sage_quant_v_amax_partial_kernel, | |
| sage_quant_v_kernel, | |
| ) | |
| from aiter.ops.triton.quant.mxfp6_fmha_pack import ( | |
| fp6_k_raw_buffer_sizes, | |
| fp6_k_lds_order_views_from_raw, | |
| reorder_fp6_k_lds_order_triton, | |
| ) | |
| from aiter.ops.triton.quant.sage_attention_quant_wrappers import ( | |
| fp4_v_padded_sequence, | |
| fp4_v_raw_buffer_size, | |
| pack_v_mxfp4_colmajor_raw, | |
| ) | |
| from ..jit.core import compile_ops | |
| from ..jit.utils.chip_info import get_gfx | |
| MHA_V4_LOG2E = 1.4426950408889634 | |
| from enum import IntEnum | |
| from typing import Optional | |
| import torch | |
| import triton | |
| from torch import Tensor | |
| from aiter import dtypes | |
| from aiter.ops.triton._triton_kernels.quant.sage_attention_quant import ( | |
| sage_quant_v_amax_finalize_kernel, | |
| sage_quant_v_amax_partial_kernel, | |
| sage_quant_v_kernel, | |
| ) | |
| from aiter.ops.triton.quant.mxfp6_fmha_pack import ( | |
| fp6_k_lds_order_views_from_raw, | |
| fp6_k_raw_buffer_sizes, | |
| reorder_fp6_k_lds_order_triton, | |
| ) | |
| from aiter.ops.triton.quant.sage_attention_quant_wrappers import ( | |
| fp4_v_padded_sequence, | |
| fp4_v_raw_buffer_size, | |
| pack_v_mxfp4_colmajor_raw, | |
| ) | |
| from ..jit.core import compile_ops | |
| from ..jit.utils.chip_info import get_gfx | |
| MHA_V4_LOG2E = 1.4426950408889634 |
| q_scale_mode: AttentionScaleMode, | ||
| k_scale_mode: AttentionScaleMode, | ||
| v_scale_mode: AttentionScaleMode, | ||
| softmax_scale: Optional[float] = None, |
| k_scale_mode: AttentionScaleMode, | ||
| v_scale_mode: AttentionScaleMode, | ||
| softmax_scale: Optional[float] = None, | ||
| out: Optional[Tensor] = None, |
| q_format: AttentionFormat, | ||
| k_format: AttentionFormat, | ||
| v_format: AttentionFormat, | ||
| softmax_scale: Optional[float] = None, |
| k_format: AttentionFormat, | ||
| v_format: AttentionFormat, | ||
| softmax_scale: Optional[float] = None, | ||
| out: Optional[Tensor] = None, |
There was a problem hiding this comment.
Import block is un-sorted or un-formatted
aiter/aiter/ops/triton/quant/sage_attention_quant_wrappers.py
Lines 1 to 22 in 50c3dfc
There was a problem hiding this comment.
Import block is un-sorted or un-formatted
aiter/op_tests/op_benchmarks/triton/bench_sage.py
Lines 1 to 71 in 50c3dfc
Motivation
Introduce an extensible, inference-only MHA v4 entrypoint for mixed low-precision ASM attention kernels, without overwhelming the existing
aiter.ops.mhamodule. In the future we can consider merging into the common entrypoint, but these kernels are best kept independent as they evolve.Q: why v4? A: IMO this is the closest thing to FAv4 on cdna3/4, also doing 1) conditional-softmax-rescaling, 2) exponential-approx/emu, 3) optimized pipelines for valu/mfma/loads utilization. Though I'm open for naming suggestions.
Replaces #3495 and #3186
Technical Details
aiter.ops.mha_v4as an extensible interface for future architectures, formats, output types, sparse attention, GQA, causal attention, head dimensions, etctorch.compileexecution and distributed overlap by separating Q/K/V preprocessing and safely encapsulating specialized packed layouts.Test Plan
Test Result
Current mi355x long-sequence dense ASM kernel throughput, excluding Q/K/V preprocessing:
Submission Checklist