[#13061][bugfix] Add rotate_activation to DSA fused_cat_fp8 path - #15158
[#13061][bugfix] Add rotate_activation to DSA fused_cat_fp8 path#15158waynehacking8 wants to merge 5 commits into
Conversation
The DSA sparse attention indexer's _prep_q_or_k method calls fused_cat_fp8 to concatenate [qk_pe, qk_nope] and quantize to FP8 in a single fused kernel. However, DSA requires a Hadamard rotation (rotate_activation) between concatenation and quantization. The fused kernel cannot accommodate an intermediate transform, so this unfuses the FP8 path into: cat → rotate_activation → fp8_quantize_1x128. The scale transpose follows the reference in test_fused_cat_fp8.py. The FP4 path has the same gap but needs a standalone FP4 quantize op to unfuse — left as a follow-up (noted in docstring). rotate_activation gracefully falls back to identity when fast-hadamard-transform is not installed, so this change is backward-compatible for environments without the optional dependency. Signed-off-by: WEI CHENG CHIU <waynehacking8@gmail.com>
📝 WalkthroughWalkthroughThis change fixes the FP8 quantization path in DSA (Dense Sparse Attention) by inserting Hadamard rotation before quantization. The method now concatenates Q/K tensors, applies rotation, quantizes with ChangesFP8 Quantization with Hadamard Rotation
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
tensorrt_llm/_torch/attention_backend/sparse/dsa.py (1)
2345-2350: 💤 Low valueConsider extracting scale normalization to a shared helper.
The scale normalization logic here duplicates
fp8_quantize_1x128_sf_transposefromtensorrt_llm/quantization/utils/fp8_utils.py. To reduce duplication, consider either:
- Adding a
use_ue8m0parameter to the existingfp8_quantize_1x128_sf_transposefunction, or- Extracting just the scale normalization into a small helper that both call sites can use.
Not blocking since the current implementation is correct and matches the reference pattern from context snippet 2.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tensorrt_llm/_torch/attention_backend/sparse/dsa.py` around lines 2345 - 2350, The scale normalization block in dsa.py duplicates logic from fp8_quantize_1x128_sf_transpose in tensorrt_llm/quantization/utils/fp8_utils.py; refactor by extracting the normalization into a shared helper (e.g., normalize_fp8_scale(scale, combined_2d, head_dim, padded_block=128)) or by adding a use_ue8m0 parameter to fp8_quantize_1x128_sf_transpose and reusing it from this module; update the code in tensorrt_llm/_torch/attention_backend/sparse/dsa.py to call the shared helper (or the extended fp8_quantize_1x128_sf_transpose) instead of reimplementing the slicing, padding and transpose logic so both call sites use the same implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@tensorrt_llm/_torch/attention_backend/sparse/dsa.py`:
- Around line 2345-2350: The scale normalization block in dsa.py duplicates
logic from fp8_quantize_1x128_sf_transpose in
tensorrt_llm/quantization/utils/fp8_utils.py; refactor by extracting the
normalization into a shared helper (e.g., normalize_fp8_scale(scale,
combined_2d, head_dim, padded_block=128)) or by adding a use_ue8m0 parameter to
fp8_quantize_1x128_sf_transpose and reusing it from this module; update the code
in tensorrt_llm/_torch/attention_backend/sparse/dsa.py to call the shared helper
(or the extended fp8_quantize_1x128_sf_transpose) instead of reimplementing the
slicing, padding and transpose logic so both call sites use the same
implementation.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: c1e815b4-dcc0-46d7-a462-b9b9228512b2
📒 Files selected for processing (1)
tensorrt_llm/_torch/attention_backend/sparse/dsa.py
… inline copy Replaces the duplicated scale normalization logic with a direct call to fp8_quantize_1x128_sf_transpose from fp8_utils, which already implements the exact same op+scale-transpose sequence. Simpler and avoids maintaining two copies. Signed-off-by: WEI CHENG CHIU <waynehacking8@gmail.com>
|
Status check: this PR has been mergeable and review-ready since 06-09 (coderabbit pass addressed at open time). Could a maintainer trigger CI ( |
|
@waynehacking8, |
…p_q_or_k The fp8_utils import and the fp8_quantize_1x128_sf_transpose call in _prep_q_or_k did not match the repo's isort/yapf style, failing the pre-commit CI check. Reformat to the canonical style (backslash-continued single import; closing paren on the last-argument line). Signed-off-by: waynehacking8 <waynehacking8@gmail.com>
|
Thanks @karljang — addressed in e570480: the |
|
Add @lfr-0531 to review as well. thanks |
| from tensorrt_llm.quantization.utils.fp8_utils import \ | ||
| fp8_quantize_1x128_sf_transpose | ||
| combined = torch.cat([qk_pe, qk_nope], dim=-1) | ||
| combined = rotate_activation(combined) |
There was a problem hiding this comment.
Replied in detail in a top-level comment — TL;DR: this isn't a revert. #11899 was a [perf] fusion, and fusedCatFp8.cu only does concat + FP8 quantize (no Hadamard), so the rotation was dropped unintentionally (that's #13061). I've restored the pre-#11899 cat → rotate → quantize path verbatim (same rotate_activation, same fp8_utils.fp8_quantize_1x128_sf_transpose). Happy to fold the rotation into the kernel as a perf follow-up.
There was a problem hiding this comment.
I find a comment about it: #11899 (comment), which says:
Yes, I intentionally removed it.
hadamard_transformwas not used, and previous verification shows that it's safe to remove with no accuracy drop.
@waynehacking8 Can you show us a case that accuracy drop for a benchmark without Hadamard rotation?
Mirror the implementation NVIDIA#11899 replaced when it fused this path: use maybe_compiled_cat + self.head_dim + fp8_utils.fp8_quantize_1x128_sf_transpose instead of torch.cat / combined.shape[-1] / a local import. Behavior is unchanged (same rotate_activation Hadamard rotation and same quantizer); this only restores the upstream idiom for a cleaner, verbatim-style diff. Signed-off-by: WEI CHENG CHIU <waynehacking8@gmail.com>
|
@yuxianq @PerkzZheng Thanks for the careful review. I looked into the history — this isn't an intentional revert of a design choice, it's restoring a regression: #11899 was This PR restores the pre-#11899 fp8 path. I've aligned the fp8 branch to mirror the original implementation verbatim — The cost is that un-fusing gives up #11899's kernel speedup. Happy to follow up by folding the rotation into |
Replace the multi-line docstring (which carried PR/issue history, not idiomatic in this file) with the terse one-liner the file uses, and move the unfuse rationale + FP4 follow-up note to inline comments where they apply. No behavior change. Signed-off-by: WEI CHENG CHIU <waynehacking8@gmail.com>
|
@yuxianq Thanks — kaiyux's #11899 comment is the decisive context. I worked through it and his call holds. The indexer logit is I can't produce a config with an actual accuracy drop (no GPU / DSV3.2 weights on my side), and given the cancellation I don't expect one for the FP8 path. So I'll defer to the verification and close this — #13061 is really a question, not a regression. If FP4's larger quant error ever turns out to move top-k, that'd be the place to revisit. Thanks all for the quick reviews. |
Summary
Fixes #13061 — the DSA sparse attention indexer's
_prep_q_or_kmethod callsfused_cat_fp8to concatenate[qk_pe, qk_nope]and quantize to FP8 in a single fused kernel, but skipsrotate_activation(Hadamard rotation) which DSA requires between concatenation and quantization.fused_cat_fp8is a single CUDA kernel that does cat+quant atomically — there's no way to inject the rotation in between.torch.cat → rotate_activation → fp8_quantize_1x128. The scale transpose logic follows the reference implementation intest_fused_cat_fp8.py.rotate_activationgracefully returns identity whenfast-hadamard-transformis not installed (existing warning).fused_cat_fp4) has the same issue but needs a standalone FP4 quantize-only kernel to unfuse — noted in the docstring as a follow-up.Code flow (before → after)
Before (buggy):
After (fixed):
Test plan
rotate_activationfallback: returns identity when fast-hadamard-transform is missing — no regression for existing setupsNot run in my environment (no GPU build / no DeepSeek V3.2 weights) — flagged for CI / reviewer validation:
test_fused_cat_fp8.py: thefused_cat_fp8CUDA kernel is unchanged by this PR (the FP8 path now reaches the quantizer viafp8_quantize_1x128_sf_transposeafter the Hadamard rotation), so the kernel test is unaffected.fast-hadamard-transform).Closes #13061
PR Checklist
Please review the following before submitting your PR:
PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.
PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.
Test cases are provided for new code paths (see test instructions)
If PR introduces API changes, an appropriate PR label is added - either
api-compatibleorapi-breaking. Forapi-breaking, includeBREAKINGin the PR title.Any new dependencies have been scanned for license and vulnerabilities
CODEOWNERS updated if ownership changes
Documentation updated as needed
Update tava architecture diagram if there is a significant design change in PR.
The reviewers assigned automatically/manually are appropriate for the PR.
Please check this after reviewing the above items as appropriate for this PR.
GitHub Bot Help
To see a list of available CI bot commands, please comment
/bot help.Summary by CodeRabbit