[feat] QAD 5090: Wire the Attn-QAT inference attention backend (8/12) - #1457
Conversation
Merge ProtectionsYour pull request matches the following merge protections and will not be merged until they are valid. 🟢 PR merge requirementsWonderful, this rule succeeded.
|
There was a problem hiding this comment.
Code Review
This pull request introduces support for a new attention backend, ATTN_QAT_INFER (modified SageAttention3 FP4), across the configuration, platform interface, and CUDA platform implementation. Feedback suggests wrapping the backend import and availability check in a try...except block to prevent potential runtime crashes and ensure a graceful fallback to Flash Attention, as well as removing an unused import.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| from fastvideo.attention.backends.attn_qat_infer import ( # noqa: F401 | ||
| AttnQatInferBackend, is_attn_qat_infer_available) | ||
| if is_attn_qat_infer_available(): | ||
| logger.info("Using Attn-QAT inference (modified SageAttention3 FP4) backend.") | ||
| return "fastvideo.attention.backends.attn_qat_infer.AttnQatInferBackend" | ||
| logger.info("Attn-QAT inference kernel is not built. Fall back to Flash Attention.") |
There was a problem hiding this comment.
To improve robustness, wrap the import and availability check of the ATTN_QAT_INFER backend in a try...except block. This prevents potential runtime crashes (such as AttributeError if the kernel is missing expected attributes, or OSError due to CUDA driver/toolkit mismatches) and ensures a graceful fallback to Flash Attention. Additionally, we can remove the unused AttnQatInferBackend import and its associated # noqa: F401 suppression.
try:
from fastvideo.attention.backends.attn_qat_infer import is_attn_qat_infer_available
if is_attn_qat_infer_available():
logger.info("Using Attn-QAT inference (modified SageAttention3 FP4) backend.")
return "fastvideo.attention.backends.attn_qat_infer.AttnQatInferBackend"
except Exception as e:
logger.info(e)
logger.info("Attn-QAT inference kernel is not built. Fall back to Flash Attention.")Make AttnQatTrainBackend (deadcode from #1358) selectable for quantization-aware finetuning, mirroring the inference wiring in #1457. The fake-quant-in-backward attention path becomes reachable via FASTVIDEO_ATTENTION_BACKEND=ATTN_QAT_TRAIN. - platforms/interface.py: add ATTN_QAT_TRAIN to AttentionBackendEnum. - platforms/cuda.py: dispatch ATTN_QAT_TRAIN -> AttnQatTrainBackend, guarded by is_attn_qat_train_available(). - attention/backends/attn_qat_train.py: add is_attn_qat_train_available() helper (mirrors is_attn_qat_infer_available()). - configs/models/dits/base.py: add ATTN_QAT_TRAIN to the default supported set. Config-driven, no monkey-patch module swapping. The training Triton kernel (fastvideo_kernel.triton_kernels.attn_qat_train) is not upstreamed yet, so for now selecting ATTN_QAT_TRAIN logs a warning and falls back to Flash Attention until a follow-up lands the kernel. Depends on #1457 (overlaps the enum / dispatch / supported-list files). Co-authored-by: William Lin <SolitaryThinker@users.noreply.github.com> Co-authored-by: Loay Rashid <42599591+loaydatrain@users.noreply.github.com> Co-authored-by: Kaiqin Kong <k1kong@ucsd.edu>
Provide a runnable example and docs for the inference half of the QAD recipe: NVFP4 linear (transformer_quant="NVFP4") plus the modified SageAttention3 FP4 attention backend (FASTVIDEO_ATTENTION_BACKEND=ATTN_QAT_INFER), as wired in by #1457. - examples/inference/optimizations/nvfp4_qat_wan2_1_1_3b.py: Wan2.1-T2V-1.3B 4-bit inference, with a --bf16 baseline and an nvfp4_qat option to match a QAT-distilled checkpoint. - docs/inference/optimizations.md: list the ATTN_QAT_INFER backend and add a NVFP4 + Attn-QAT section. The attn_qat_infer kernel hard-gates on sm_120 (RTX 5090); on other GPUs the backend falls back to Flash Attention. Depends on #1455 (kernel) and #1457 (backend wiring). Co-authored-by: William Lin <SolitaryThinker@users.noreply.github.com> Co-authored-by: Loay Rashid <42599591+loaydatrain@users.noreply.github.com> Co-authored-by: Kaiqin Kong <k1kong@ucsd.edu>
|
Hi @alexzms — automated review from Gob, one of @SolitaryThinker's AI reviewers. Findings aren't all human-verified; ping @SolitaryThinker if anything looks off. TL;DRThis activation-gate review found the slice-7 Verdict: request-changes
Carryover status from #1455 (slice 7 → slice 8 activation)
Prior gemini-code-assist concerns (status at
|
| Prior concern | Status at HEAD | Severity now |
|---|---|---|
| Wrap backend import in try/except for graceful fallback | Safe at HEAD: the selector import is inside the ATTN_QAT_INFER branch, and the backend lazily imports the kernel under try/except ImportError before returning unavailable |
n/a |
| Remove unused import | Lint-clean at HEAD: the import is retained with the same # noqa: F401 validation pattern used by sibling backend branches |
n/a |
Findings (formatted for upload)
[S1] sm_scale is still swallowed now that the backend is selectable
What: AttnQatInferImpl.forward() passes sm_scale=self.softmax_scale into the kernel wrapper, but sageattn_blackwell(... **kwargs) documents those extra arguments as ignored, and blockscaled_fp4_attn() recomputes softmax_scale = (qlist[0].shape[-1] * 2) ** (-0.5) before calling fp4attn_cuda.fwd(...).
Why it matters: After this PR, FASTVIDEO_ATTENTION_BACKEND=ATTN_QAT_INFER can select this backend for DiTs inheriting the default supported-backend list. Any model or attention site with a non-default scale will silently run with 1/sqrt(D) instead of the configured scale, producing a correctness or quality regression without an exception.
Suggested fix: Plumb the scale end-to-end: add an explicit sm_scale/softmax_scale parameter to sageattn_blackwell() and blockscaled_fp4_attn(), pass it to fp4attn_cuda.fwd(...), and keep the current 1/sqrt(D) computation only as the fallback when the caller passes None.
Evidence: fastvideo/attention/backends/attn_qat_infer.py:117-124, fastvideo-kernel/attn_qat_infer/api.py:140-144, fastvideo-kernel/attn_qat_infer/api.py:159, fastvideo/configs/models/dits/base.py:22-28
— Gob (@SolitaryThinker's AI reviewer). Full review (including S2/S3 items) is archived locally.
Activate the AttnQatInferBackend that #1358 landed as deadcode, now that its modified-SageAttention3 FP4 kernels are landing via #1455. - platforms/interface.py: add ATTN_QAT_INFER to AttentionBackendEnum. Its name matches AttnQatInferBackend.get_name(), so backend_name_to_enum() resolves the FASTVIDEO_ATTENTION_BACKEND=ATTN_QAT_INFER override. - platforms/cuda.py: dispatch ATTN_QAT_INFER -> AttnQatInferBackend, guarded by is_attn_qat_infer_available(); falls back to Flash Attention when the kernel is not built (non-Blackwell, or before #1455 merges). - configs/models/dits/base.py: add ATTN_QAT_INFER to the default _supported_attention_backends so Wan can select it. The training-side ATTN_QAT_TRAIN backend depends on a separate Triton kernel and is deferred to the training upstream. Verified on a Blackwell node with the #1455 kernel present: selecting ATTN_QAT_INFER returns AttnQatInferBackend; without the kernel it falls back to Flash Attention. Depends on #1455. Co-authored-by: William Lin <SolitaryThinker@users.noreply.github.com> Co-authored-by: Loay Rashid <42599591+loaydatrain@users.noreply.github.com> Co-authored-by: Kaiqin Kong <k1kong@ucsd.edu>
…_attn (#1457) Addresses the S1 finding from the PR #1457 gob review: the kernel wrapper silently discarded caller-provided sm_scale via **kwargs, so any model with a non-default softmax scale would silently run with 1/sqrt(D) instead. Now sageattn_blackwell takes sm_scale: float | None = None and forwards it to blockscaled_fp4_attn, which uses the computed (D * 2) ** -0.5 default only when sm_scale is None. Co-Authored-By: alexzms <26690162+alexzms@users.noreply.github.com>
04bde90 to
8996245
Compare
|
/merge |
|
Hi @alexzms — automated re-review from Gob, one of @SolitaryThinker's AI reviewers. Findings aren't all human-verified; ping @SolitaryThinker if anything looks off. TL;DRF1 is resolved at Verdict: approve-with-followup
Prior findings status (against rereview HEAD
|
| Prior finding | Status at HEAD | New severity |
|---|---|---|
| F1 [S1] sm_scale swallow → kernel hardcodes scale | ✅ RESOLVED in 8996245d |
n/a |
| F2 [S2] In-place k mutation via enable_smoothing_k=True | ⏸️ PERSISTENT, still latent because current caller does not pass enable_smoothing_k=True |
S2 follow-up |
| F3 [S2] Base-level opt-in broader than Wan-2.1 target | ⏸️ PERSISTENT, base default allow-list still includes ATTN_QAT_INFER |
S2 follow-up |
| F4 [S3] Missing Attn-QAT-Stack: 8/12 trailer | ⏸️ PERSISTENT | S3 |
| F5 [S3] Dispatch branch lacks unit test | ⏸️ PERSISTENT | S3 |
Address commit(s): 8996245d ("[bugfix]: plumb sm_scale through sageattn_blackwell + blockscaled_fp4_attn (#1457)").
The key fixed code in fastvideo-kernel/attn_qat_infer/api.py is:
def blockscaled_fp4_attn(qlist: Tuple,
klist: Tuple,
vlist: Tuple,
delta_s: torch.Tensor,
KL: int,
is_causal: bool = False,
per_block_mean: bool = True,
is_bf16: bool = True,
single_level_p_quant: bool = False,
sm_scale: float | None = None
):
softmax_scale = sm_scale if sm_scale is not None else (qlist[0].shape[-1] * 2) ** (-0.5)
return fp4attn_cuda.fwd(qlist[0], klist[0], vlist[0], qlist[1], klist[1], vlist[1], delta_s, KL, None, softmax_scale, is_causal, per_block_mean, is_bf16, single_level_p_quant)def sageattn_blackwell(q, k, v, attn_mask = None, is_causal = False, per_block_mean = True, single_level_p_quant = True, sm_scale: float | None = None, **kwargs): o_fp4 = blockscaled_fp4_attn(
qlist_from_cuda,
klist_from_cuda,
vlist_from_cuda,
delta_s,
KL,
is_causal,
per_block_mean,
is_bf16,
single_level_p_quant,
sm_scale
)[0][:, :, :QL, :].contiguous()Findings
No new S0/S1 findings surfaced in the differential re-review. I am moving the prior verdict up one tier because the prior S1 is fixed, but I am not marking this as full approve because F2 and F3 remain S2 follow-ups: preprocess_qkv() still contains the latent in-place k -= k.mean(...) path, and the backend remains enabled at the base DiT allow-list rather than scoped to Wan-only.
— Gob (@SolitaryThinker's AI reviewer). Full review (including S3 items + verification log) is archived locally.
Make AttnQatTrainBackend (deadcode from #1358) selectable for quantization-aware finetuning, mirroring the inference wiring in #1457. The fake-quant-in-backward attention path becomes reachable via FASTVIDEO_ATTENTION_BACKEND=ATTN_QAT_TRAIN. - platforms/interface.py: add ATTN_QAT_TRAIN to AttentionBackendEnum. - platforms/cuda.py: dispatch ATTN_QAT_TRAIN -> AttnQatTrainBackend, guarded by is_attn_qat_train_available(). - attention/backends/attn_qat_train.py: add is_attn_qat_train_available() helper (mirrors is_attn_qat_infer_available()). - configs/models/dits/base.py: add ATTN_QAT_TRAIN to the default supported set. Config-driven, no monkey-patch module swapping. The training Triton kernel (fastvideo_kernel.triton_kernels.attn_qat_train) is not upstreamed yet, so for now selecting ATTN_QAT_TRAIN logs a warning and falls back to Flash Attention until a follow-up lands the kernel. Depends on #1457 (overlaps the enum / dispatch / supported-list files). Co-authored-by: William Lin <SolitaryThinker@users.noreply.github.com> Co-authored-by: Loay Rashid <42599591+loaydatrain@users.noreply.github.com> Co-authored-by: Kaiqin Kong <k1kong@ucsd.edu>
Purpose
Continues the Attn-QAT upstreaming stack (#1225). Wires in the
AttnQatInferBackendthat #1358 landed as deadcode, now that its modifiedSageAttention3 FP4 kernels land in #1455. This makes the 4-bit attention path
selectable end-to-end for Wan-2.1 inference.
Changes
platforms/interface.py: addATTN_QAT_INFERtoAttentionBackendEnum. Thename matches
AttnQatInferBackend.get_name(), sobackend_name_to_enum()resolves the
FASTVIDEO_ATTENTION_BACKEND=ATTN_QAT_INFERoverride.platforms/cuda.py: dispatchATTN_QAT_INFER→AttnQatInferBackend, guardedby
is_attn_qat_infer_available(); falls back to Flash Attention when thekernel is not built (non-Blackwell, or before [kernel] QAD 5090: Add modified SageAttention3 FP4 inference kernels (7/12) #1455 merges).
configs/models/dits/base.py: addATTN_QAT_INFERto the default_supported_attention_backendsso Wan can select it.The training-side
ATTN_QAT_TRAINbackend depends on a separate Triton kerneland is deferred to the training upstream.
Test Plan / Test Results
name ↔ enumclosed:AttnQatInferBackend.get_name() == "ATTN_QAT_INFER"is a valid
AttentionBackendEnummember.get_attn_backend_cls(ATTN_QAT_INFER)returnsfastvideo.attention.backends.attn_qat_infer.AttnQatInferBackendFlashAttentionBackendNotes
is_attn_qat_infer_available()returns False on
main, so this safely no-ops to Flash Attention.sm_120(RTX 5090)–specific by kernel design.Part of #1225.