Skip to content

feat(attention): enable GQA for NVFP4 attention sm120 - #4153

Open
zhougit86 wants to merge 4 commits into
flashinfer-ai:mainfrom
zhougit86:feature/sm120_nvfp4_gqa
Open

zhougit86 wants to merge 4 commits into
flashinfer-ai:mainfrom
zhougit86:feature/sm120_nvfp4_gqa

Conversation

@zhougit86

@zhougit86 zhougit86 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

📌 Description

Add GQA support to the SM120/SM121 NVFP4 attention path.

This PR allows q to use num_q_heads while k/v use num_kv_heads, with num_q_heads % num_kv_heads == 0. The kernel now maps each Q head to its shared KV head using q_head / h_h_k_ratio, while keeping outputs, LSE, Q scale, and qk_correction aligned with Q heads.

🔍 Related Issues

Related to #3809

🚀 Pull Request Checklist

Thank you for contributing to FlashInfer! Before we review your pull request, please make sure the following items are complete.

✅ Pre-commit Checks

  • I have installed pre-commit by running pip install pre-commit (or used your preferred method).
  • I have installed the hooks with pre-commit install.
  • I have run the hooks manually with pre-commit run --all-files and fixed any reported issues.

If you are unsure about how to set up pre-commit, see https://pre-commit.com/.

🧪 Tests

  • Tests have been added or updated as needed.
  • All tests are passing (unittest, etc.).

Added a GQA coverage case for nvfp4_attention_sm120.

Reviewer Notes

The main logic to review is the Q-head to KV-head mapping:

kv_head = q_head / h_h_k_ratio

q, q_scale, qk_correction, out, and lse stay aligned with Q heads; k, v, k_scale, and v_scale are aligned with KV heads.

Summary by CodeRabbit

  • New Features

    • Added grouped-query attention (GQA) support for SM120 NVFP4 attention, allowing query heads to exceed key/value heads.
    • Updated quantization, validation, scaling, and output handling for separate query and key/value head counts.
  • Bug Fixes

    • Corrected key/value tile selection and attention correction calculations for grouped head layouts.
  • Tests

    • Added accuracy coverage validating GQA quantization and forward-pass results.

xiaogang.zhou added 3 commits July 26, 2026 17:51
Signed-off-by: xiaogang.zhou <xiaogang.zhou@bytedance.com>
Signed-off-by: xiaogang.zhou <xiaogang.zhou@bytedance.com>
Signed-off-by: xiaogang.zhou <xiaogang.zhou@bytedance.com>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

SM120 NVFP4 attention now supports grouped-query attention by tracking query and key/value head counts separately through preprocessing, validation, quantization, CUDA parameter packing, KV tile loading, and accuracy tests.

Changes

Grouped-query attention support

Layer / File(s) Summary
Python GQA preprocessing and tensor contracts
flashinfer/nvfp4_attention_sm120.py
Preprocessing, quantization, correction tensors, input validation, output allocation, and log-sum-exp shapes now distinguish num_q_heads from num_kv_heads.
CUDA parameterization and KV loading
csrc/nvfp4_attention_sm120/..., include/flashinfer/attention/sm120/nvfp4_attention_sm120/...
The binding and collective mainloop propagate the query-to-KV head ratio and use remapped KV indices for K/V and FP4 scale tile loads.
Reference and accuracy validation
tests/attention/test_nvfp4_attention_sm120.py
The reference path expands KV heads for grouped queries, and a new SM120 GQA test checks tensor shapes and forward accuracy.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant QKV as QKV tensors
  participant Python as nvfp4_attention_sm120_quantize_qkv
  participant Binding as nvfp4_attention_sm120_fwd
  participant Mainloop as CollectiveMainloopFwd
  participant KVLoaders as KLoader and VLoader
  QKV->>Python: q, k, v with separate head counts
  Python->>Binding: quantized tensors, scales, qk_correction
  Binding->>Mainloop: h, h_k, h_h_k_ratio
  Mainloop->>KVLoaders: load KV tiles using bidkv
  KVLoaders-->>Binding: attention output and lse
Loading

Possibly related PRs

Suggested reviewers: saltyminty, yzh119, bkryu, nv-yunzheq, qsang-nv

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: enabling GQA for SM120 NVFP4 attention.
Description check ✅ Passed The description covers the change, related issue, checklist, tests, and reviewer notes, matching the template well.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/attention/test_nvfp4_attention_sm120.py (1)

194-202: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

GQA test config doesn't exercise multi-KV-head remapping.

With num_kv_heads=1, h_h_k_ratio = num_q_heads // num_kv_heads = 4, so bidkv = bidh // h_h_k_ratio is 0 for every valid bidh (0..3). This effectively tests MQA (single shared KV head), not general GQA — the new bidkv indexing logic in mainloop.cuh/load_k.cuh/load_v.cuh for bidkv > 0 (multiple distinct KV head groups) is left unverified by this test.

✅ Suggested config change to exercise multiple KV-head groups
-    batch, num_q_heads, num_kv_heads, seq_len, head_dim = 1, 4, 1, 256, 128
+    batch, num_q_heads, num_kv_heads, seq_len, head_dim = 1, 6, 2, 256, 128
🤖 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 `@tests/attention/test_nvfp4_attention_sm120.py` around lines 194 - 202, Update
the test configuration around the manual seed and tensor setup so num_kv_heads
is greater than 1 and still divides num_q_heads, such as selecting two KV heads
for four query heads. Preserve the existing tensor shapes and dtypes while
ensuring valid query heads map to both bidkv 0 and bidkv 1, exercising
multi-KV-head GQA remapping.
🤖 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.

Inline comments:
In `@flashinfer/nvfp4_attention_sm120.py`:
- Around line 377-379: Clarify the docstring describing q_fp4 and k_fp4 layouts
so q_fp4 uses num_q_heads while k_fp4 uses num_kv_heads, without grouping them
under a shared num_q_heads shape. Preserve the existing v_fp4_t and v_scale_t
transposed layout description.

---

Nitpick comments:
In `@tests/attention/test_nvfp4_attention_sm120.py`:
- Around line 194-202: Update the test configuration around the manual seed and
tensor setup so num_kv_heads is greater than 1 and still divides num_q_heads,
such as selecting two KV heads for four query heads. Preserve the existing
tensor shapes and dtypes while ensuring valid query heads map to both bidkv 0
and bidkv 1, exercising multi-KV-head GQA remapping.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 496e80b1-db38-4a5f-aa77-27edc0699601

📥 Commits

Reviewing files that changed from the base of the PR and between 290c091 and e80d0f3.

📒 Files selected for processing (7)
  • csrc/nvfp4_attention_sm120/nvfp4_attention_sm120_binding.cu
  • flashinfer/nvfp4_attention_sm120.py
  • include/flashinfer/attention/sm120/nvfp4_attention_sm120/api/launcher.h
  • include/flashinfer/attention/sm120/nvfp4_attention_sm120/compute/mainloop.cuh
  • include/flashinfer/attention/sm120/nvfp4_attention_sm120/compute/producer/load_k.cuh
  • include/flashinfer/attention/sm120/nvfp4_attention_sm120/compute/producer/load_v.cuh
  • tests/attention/test_nvfp4_attention_sm120.py

Comment on lines +377 to +379
``[batch, num_q_heads, seq_len, head_dim / 2]``; ``k_fp4`` uses
``num_kv_heads``. ``v_fp4_t`` and ``v_scale_t`` are stored transposed as
``[batch, num_kv_heads, head_dim, packed_seq_len]``.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Confusing docstring wording for q_fp4/k_fp4 layout.

The sentence says "q_fp4 and k_fp4 use layout [batch, num_q_heads, ...]; k_fp4 uses num_kv_heads" — it groups k_fp4 with the num_q_heads layout and then immediately contradicts that in the next clause.

✏️ Suggested docstring fix
     The packed tensors should be produced by
-    :func:`nvfp4_attention_sm120_quantize_qkv`. ``q_fp4`` and ``k_fp4`` use layout
-    ``[batch, num_q_heads, seq_len, head_dim / 2]``; ``k_fp4`` uses
-    ``num_kv_heads``. ``v_fp4_t`` and ``v_scale_t`` are stored transposed as
+    :func:`nvfp4_attention_sm120_quantize_qkv`. ``q_fp4`` uses layout
+    ``[batch, num_q_heads, seq_len, head_dim / 2]``; ``k_fp4`` uses the same
+    layout with ``num_kv_heads`` in place of ``num_q_heads``. ``v_fp4_t`` and
+    ``v_scale_t`` are stored transposed as
     ``[batch, num_kv_heads, head_dim, packed_seq_len]``.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
``[batch, num_q_heads, seq_len, head_dim / 2]``; ``k_fp4`` uses
``num_kv_heads``. ``v_fp4_t`` and ``v_scale_t`` are stored transposed as
``[batch, num_kv_heads, head_dim, packed_seq_len]``.
The packed tensors should be produced by
:func:`nvfp4_attention_sm120_quantize_qkv`. ``q_fp4`` uses layout
``[batch, num_q_heads, seq_len, head_dim / 2]``; ``k_fp4`` uses the same
layout with ``num_kv_heads`` in place of ``num_q_heads``. ``v_fp4_t`` and
``v_scale_t`` are stored transposed as
``[batch, num_kv_heads, head_dim, packed_seq_len]``.
🤖 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 `@flashinfer/nvfp4_attention_sm120.py` around lines 377 - 379, Clarify the
docstring describing q_fp4 and k_fp4 layouts so q_fp4 uses num_q_heads while
k_fp4 uses num_kv_heads, without grouping them under a shared num_q_heads shape.
Preserve the existing v_fp4_t and v_scale_t transposed layout description.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants