Add optional forward LSE output#886
Open
AakarshAMD wants to merge 4 commits into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
return_lse=True.sm_scale * m + ln(l)return_lse=False.(Q, K, LSE)without storing the full attention matrix.Details
Kernel implementation
Files:
kernels/attention/flash_attn_utils.pykernels/attention/flash_attn_generic.pykernels/attention/flash_attn_gfx950.pyThe implementation adds a
RETURN_LSEcompile-time trait to the generic and gfx950 dualwave kernel configurations.Because it is a compile-time trait:
return_lse=True._make_lse_rsrccreates a bounded buffer-resource descriptor for each batch's[H, Sq]slice of the float32 LSE tensor.Three LSE store paths are implemented:
GenericStoreHelper.store_lse-inffor fully masked rows.DualwaveStoreHelper.store_lse_from_mlm_row * ln(2) + ln(l_row).DualwaveSplitKCombineHelper.store_lseAll paths use a single-writer-per-row scheme. Invalid rows and non-writer lanes are redirected to an out-of-bounds sentinel index, which is safely discarded by the bounded buffer resource.
Upstream integration
The change was rebased onto the latest
origin/main, including the new gfx942 flash-attention optimizations.The conflict resolution preserves:
skip_kv_pad_maskreturn_lseis threaded through every new recursive builder and dispatch path, so the upstream implementation remains the structural baseline with LSE added as an independent option.The rebased LSE code follows the updated typed-value style and does not reintroduce the deprecated
ArithValuewrapper.Low-level safety guards
The generic and gfx950 launch/compile entry points raise an error when a kernel compiled with
RETURN_LSE=Trueis invoked without an LSE output tensor:This protects direct low-level builder users from accidentally writing LSE into a placeholder tensor.
Public API
File:
kernels/attention/flash_attn_interface.pyThe public function gains:
Default behavior remains unchanged:
With LSE enabled:
The returned LSE tensor is:
float32[B, H, Sq]For packed variable-length attention, its shape is
[B, H, max_seqlen_q]; padded rows are undefined.Unsupported combinations fail explicitly:
return_lse=Truereturn_lse=TrueThe public API allocates the tensor only when requested:
It returns
(out, lse)when enabled and the originalouttensor otherwise.Compatibility
return_lsedefaults toFalse.Diff
Test Plan
Tested on AMD Instinct MI350X (
gfx950) using ROCm.Correctness
External LSE correctness suite:
The suite covers:
All official performance-test rows passed with:
Performance methodology
gfx950)FLYDSL_PERFTEST_USE_EVENTSunsetorigin/mainreturn_lse=True--compareharnessPerformance
Values are latency / TFLOPS.
Performance conclusion
Known follow-up
The public API currently allocates a fresh LSE tensor for every call with
return_lse=True.A future optional
lse=output parameter, matching the existingout=convention, would allow latency-sensitive callers to reuse a preallocated buffer and remove that API-level allocation cost. This is not part of this change.