[Perf] Parallelize AttnRes long-sequence reduction - #1114
Conversation
There was a problem hiding this comment.
Pull request overview
This PR improves the CUDA Triton AttnRes implementation by parallelizing the long-sequence backward reduction over the flattened token dimension, reducing a serial bottleneck for large N while keeping the public API and dispatch behavior unchanged.
Changes:
- Added a split-
Nreduction path for backwarddq/dw/(dow)whereN >= 16384, using FP32 partial accumulation and a finalize kernel. - Stored per-token output RMSNorm inverse-std (
o_rstd) in forward and reused it in backward to avoid recomputation. - Removed the padded residual pointer-table (
L2) approach and specialized kernels directly onL.
馃挕 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| checkpoint_level=checkpoint_level, | ||
| ) | ||
| ctx.save_for_backward(query, rms_weight, output_rms_weight, o_pre, rstd, logit, lse, *residuals) | ||
| ctx.save_for_backward(query, rms_weight, output_rms_weight, o_pre, o_rstd, rstd, logit, lse, *residuals) |
There was a problem hiding this comment.
Thanks for checking this. The pre-existing implementation already saved optional output_rms_weight and o_pre values through save_for_backward; this PR adds o_rstd using the same supported None behavior. The output_rms_weight=None / checkpoint_level=1 paths are covered locally, including the new bf16 N=16384 case, and the updated H100 PyTorch 2.12 test-ops job passes.
30d5df9 to
26024c5
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Suppressed comments (2)
fla/ops/attnres/fused.py:154
- Same concern as in the fwd kernel: making
Latl.constexprhere can cause therange(tl.cdiv(L, BL))loops to be compile-time sized and potentially fully unrolled per-L, increasing compile time and kernel code size. If the intent is only to enable staticres[i]indexing, consider separating tuple length from the runtime loop bound to avoid unrolling the full residual-source dimension.
N,
L: tl.constexpr,
D: tl.constexpr,
eps: tl.constexpr,
scale: tl.constexpr,
fla/ops/attnres/fused.py:53
Lis now atl.constexprparameter. This makes loops likefor i_l in range(tl.cdiv(L, BL))compile-time sized, which can fully unroll the residual-source loop for each distinctLandBLconfig, significantly increasing Triton compile time / code size and multiplying cached variants (autotune key is also per-L). IfLcan vary across layers/models, consider keeping the outer loop runtime-sized (and bucketing the pointer tuple length separately) to reduce JIT overhead while still enabling static indexing intores[i].
This issue also appears on line 150 of the same file.
N,
L: tl.constexpr,
D: tl.constexpr,
eps: tl.constexpr,
scale: tl.constexpr,
|
Regarding the exact- |
| if len(residuals) == 0: | ||
| raise ValueError("residuals must contain at least one source") | ||
| if checkpoint_level not in (0, 1): | ||
| raise ValueError(f"checkpoint_level must be 0 or 1, got {checkpoint_level}") | ||
|
|
||
| output_shape = residuals[0].shape | ||
| D = output_shape[-1] | ||
| flat_residuals = tuple(r.reshape(-1, D).contiguous() for r in residuals) | ||
| residuals = tuple(residuals) |
|
Hi @zhiyuan1i, could you please review this PR when you have a chance? Thanks! |
Summary
Improve the default Triton AttnRes path as one cumulative source change:
dq/dwand optionaldowreductions over the flattened token dimension.For
N >= 16384, four programs accumulate FP32 partials and a separate kernel finalizesdq,dw, anddow; shorter inputs retain the single-program reduction. Public API, checkpoint semantics, backend dispatch, and accumulation precision are unchanged.Test plan
pytest tests/ops/test_attnres.py -q -k T16384: 2 passed, 16 deselectedpytest tests/ops/test_attnres.py -q: 17 passed, 1 skippedfused_attnres, bfloat16,fwdbwd, median latency; cleanmainbaseline and candidate measured serially with identical shapes and benchmark settingsGeometric-mean speedup: 1.1016441159813262x. Worst-row speedup: 1.032951402886971x.
Scope and limitations
The implementation change is limited to
fla/ops/attnres/fused.py; the regression coverage adds two bf16 threshold cases intests/ops/test_attnres.py. Forward math is unchanged, but the Triton forward path now uses exact-Lspecialization and storeso_rstdwhen output RMSNorm is enabled. The Gluon backend and short reduction topology are unchanged. The long path uses temporary FP32 accumulation buffers. Performance was measured only for the five bfloat16fwdbwdshapes above on B200; no broader hardware or end-to-end model speedup is claimed. Measurements are warmed steady-state timings; compile latency was not measured, and exact-Lspecialization can create more JIT/autotune variants when a model uses many distinct residual counts.Breaking changes
None.
Checklist