[HIP] [GFX950]OPUS MHA Support LSE - #4877
Conversation
🏷️ CI GuideRuns automatically on every PR:
Extended tests (opt-in via labels):
PR title tags: |
There was a problem hiding this comment.
Pull request overview
This PR extends the gfx950 OPUS bf16 MHA forward path to optionally produce LSE (log-sum-exp) in fp32 (natural log) for both dense (batch) and group/varlen variants, plumbing the buffer from Python → pybind → host launcher → device kernels, and updating tests to validate LSE correctness and fully-masked-row behavior.
Changes:
- Add optional fp32 LSE output support to OPUS D=128 (batch) and D_QK=192/D_V=128 (batch + group/varlen) kernels and their host launchers/pybind bindings.
- Update Python wrappers/dispatch gating so OPUS can be selected when
return_lse=True(still disallowingreturn_softmax/ dropout mask). - Expand OPUS test coverage to assert routing + output correctness and validate LSE vs a reference (including cross-attention and fully-masked rows).
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| op_tests/test_mha.py | Refactors OPUS dense tests to cover LSE + cross-attention cases and assert OPUS routing via flash_attn_func. |
| op_tests/test_mha_varlen.py | Adds OPUS varlen/group tests validating output + LSE and KV-padding safety (NaN gap checks). |
| csrc/py_itfs_cu/fmha_fwd_bf16_opus_kernels.cu | Plumbs optional lse tensor through the shared launcher into both OPUS variants with shape/stride validation. |
| csrc/include/torch/fmha_fwd_bf16_opus.h | Documents the new optional LSE output contract and adds the optional argument to the API. |
| csrc/include/rocm_ops.hpp | Exposes lse as an optional pybind argument (default nullopt). |
| csrc/include/fmha_fwd_hd192_v128_bf16_opus_kernel.hpp | Implements optional LSE store (fp32, natural log) and refactors S/P fragments to support it. |
| csrc/include/fmha_fwd_hd192_v128_bf16_opus_defs.h | Extends kargs with optional LSE pointer + strides for batch/group modes. |
| csrc/include/fmha_fwd_hd128_bf16_opus_kernel.hpp | Implements optional LSE store for D=128 kernel. |
| csrc/include/fmha_fwd_hd128_bf16_opus_defs.h | Extends D=128 kargs with optional LSE pointer + strides. |
| aiter/test_mha_common.py | Adds OPUS-specific fp32 LSE reference and checking helper. |
| aiter/ops/mha.py | Adds return_lse/lse plumbing in OPUS wrappers and enables OPUS dispatch when return_lse=True. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Motivation
The OPUS gfx950 bf16 forward kernels were inference-only: with no LSE output,
return_lse=True— and therefore the whole autograd path, which assertsreturn_lsewheneveris_grad— fell back tofmha_v3/CK and lost the OPUS speedup. This adds LSE to both OPUS forward kernels (D=128 and D_QK=192/D_V=128, batch + group/varlen) and opens the dispatch gates so those callers keep it.Technical Details
m_rowis not the true row max (the running max is only refreshed pastRESCALE_THRESHOLD), butl_rowstays consistent with whatever base it holds and log-sum-exp is invariant to that base, solse = ln2 * (m_row + log2(l_row)). Fully-masked rows (bottom-right causal,seqlen_q > seqlen_kv) get-inf, matchingtorch.logsumexp.ptr_lse != nullptrrather than a traits flag: a scalar branch, no extra instantiations, and callers that skip LSE skip the allocation and the store. Costs 2 VGPR on D=192 / 1 on D=128, occupancy unchanged.[B, H, N], group[H, total_q]. In the APIlseis an out-param likeout; onlyreturn_lsechanges the return type.not return_lse(keepingnot return_softmax), which also makes the autograd path reachable, i.e. the OPUS forward now feeds the v3/CK backward. Test side: 5 OPUS test functions → 3, withseqlen_q != seqlen_kvfolded into the shared case lists.Test Plan
pytest op_tests/{test_mha,test_mha_varlen}.py -k opus. LSE is compared against an fp32 logsumexp reference, notattention_ref's — that one is cast back to the input dtype and at|lse| ~ 8is coarser than the kernels' own error.-Rpass-analysis=kernel-resource-usagebefore/after; perf viarun_perfteston the PR Add OPUS gfx950 bf16 fmha d192x128 kernel #4205 shapes (seqlen × batch = 16384, causal, bf16, nheads ∈ {16, 32}), LSE on vs off plus a rebuilt pre-LSE baseline.Test Result
-infrow patterns match exactly, no NaN. Grads within bf16 tolerance (causal: out 7.6e-3, dq 1.1e-2, dk 2.1e-2, dv 2.8e-2).VGPRs Spill: 0throughout.test_flash_attn_output[…192-128…]cases that now reroute to OPUS give an identical 160/160 split with and withoutAITER_DISABLE_FMHA_OPUS=1— those 160 failures are a pre-existing invalid parametrization (assert nheads % gqa_ratio == 0→6 % 8) that fails in the test's own setup on either backend.Submission Checklist