Rope dim - #172
Rope dim#172
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces an only_qv mode for Hopper (SM90) FlashAttention forward, plumbing a new flag from the Python interface through the C++/CUDA launch path into the SM90 mainloop so it can skip Q/K work and run the Qv path only (likely to support a “rope dim”/Qv-only score path).
Changes:
- Add
only_qvto the forward parameter structs and public torch/Python APIs, and validate it in C++ (only_qvrequiresq_v). - Extend the SM90 forward mainloop template with
OnlyQvto conditionally skip loading Q/K, skip K pipeline usage, and use Qv GEMM withzero_initwhen QK is omitted. - Update forward launch template dispatch to specialize kernels on the new
OnlyQvcompile-time flag.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| hopper/mainloop_fwd_sm90_tma_gmma_ws.hpp | Adds OnlyQv template flag and guards Q/K loads, barriers, pipeline usage, and QK GEMMs accordingly. |
| hopper/flash.h | Adds only_qv to Flash_fwd_params. |
| hopper/flash_fwd_launch_template.h | Threads OnlyQv into the SM90 collective and adds runtime dispatch on params.only_qv. |
| hopper/flash_attn_interface.py | Exposes only_qv in Python APIs and forwards it into the extension call; adjusts autograd wrappers. |
| hopper/flash_api.cpp | Adds only_qv argument, validates it requires q_v, and stores it into params. |
| hopper/flash_api_torch_lib.cpp | Extends torch library schema to include only_qv. |
| hopper/flash_api_stable.cpp | Extends stable API to include only_qv for fwd; also adds it to scheduler-metadata signature (currently inconsistent with stable schema/wrapper). |
Comments suppressed due to low confidence (1)
hopper/flash_attn_interface.py:450
FlashAttnVarlenFunc.backwardmust return one entry per input toforward. After addingonly_qv(and with the existingcp_rank/cp_tot_seqused_kargs), this return tuple is now too short and will raise at runtime. Add 2 moreNoneentries at the end to match the forward signature.
return dq, dk, dv, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| bool has_softcap, | ||
| int64_t num_splits, | ||
| std::optional<bool> pack_gqa_, | ||
| bool only_qv, | ||
| int64_t sm_margin) { |
| if softmax_scale is None: | ||
| softmax_scale = (q.shape[-1] + (qv.shape[-1] if qv is not None else 0)) ** (-0.5) | ||
| if only_qv: | ||
| softmax_scale = qv.shape[-1] ** (-0.5) | ||
| else: | ||
| softmax_scale = (q.shape[-1] + (qv.shape[-1] if qv is not None else 0)) ** (-0.5) |
| dk = dk[..., : dout.shape[-1]] | ||
| dv = dv[..., : dout.shape[-1]] | ||
| return dq, dk, dv, None, None, None, None, None, None, None, None, None, None, None, None, None, None | ||
| return dq, dk, dv, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None |
|
Under Can we use similar pattern as here: using TMA_Qv_ = decltype(make_tma_copy_A_sm90( /* ... */ ));
using TMA_Qv = std::conditional_t<HasQv, TMA_Qv_, std::nullptr_t>; TMA_Qv tma_load_Qv = [&] {
if constexpr (HasQv) {
return make_tma_copy_A_sm90(GmemTiledCopyQ{}, mQv, SmemLayoutQv{}, TileShape_MNK_QV{}, ClusterShape{});
} else {
return nullptr;
}
}();we can apply that pattern to Q, K and K_new with using TMA_Q = std::conditional_t<!OnlyQv, TMA_Q_, std::nullptr_t>;
using TMA_K = std::conditional_t<!OnlyQv, TMA_K_, std::nullptr_t>;
TMA_Q tma_load_Q = [&] {
if constexpr (!OnlyQv) { return make_tma_copy_A_sm90(GmemTiledCopyQ{}, mQ, SmemLayoutQ{}, TileShape_MNK{}, ClusterShape{}); }
else { return nullptr; }
}();
// same for tma_load_K (mK) and tma_load_K_new (conditional_return<AppendKV>(mKnew, mK))What needs to be done
|
|
Please add tests for the newly introduced kernel |
|
Please switch to the new |
| TORCH_CHECK(!params.only_qv || !k_new_.has_value(), | ||
| "head_size == 0 (NoPE) does not support appending k_new/v_new; " | ||
| "write the new KV to the cache before the call instead"); | ||
|
|
There was a problem hiding this comment.
Can you update to STD_TORCH_CHECK please
|
could you please fix remaining small issue and rebase onto current main? otherwise LGTM |
When q/k carry a zero-width head dim, all query content rides in q_v: the kernel skips Q/K loads and the QK GEMM, and the QV GEMM becomes zero-init. TMA descriptors for Q/K/K_new are never created (conditional nullptr types), avoiding cuTensorMapEncodeTiled zero-extent failures. NoPE + k_new append is rejected at the API. Signed-off-by: JaredforReal <w13431838023@gmail.com> Co-authored-by: Kimi Code <noreply@moonshot.cn>
FA_SKIP_TOOLCHAIN_PIN=1 skips the vendored nvcc 12.6 download (breaks with CUDA 13 torch builds); FLASH_ATTENTION_DISABLE_HDIMDIFF64 becomes env-overridable (default still off) so the hdim64_256/512 kernels that OnlyQv needs can be built standalone. Signed-off-by: JaredforReal <w13431838023@gmail.com> Co-authored-by: Kimi Code <noreply@moonshot.cn>
Varlen + paged-kvcache correctness vs a plain reference, a fresh-zero-width-tensor stderr assertion (guards the cuTensorMapEncodeTiled failure dump), and NoPE+k_new rejection. Drives the torch.ops fwd directly (FA3 is torch.ops-only now). Signed-off-by: JaredforReal <w13431838023@gmail.com> Co-authored-by: Kimi Code <noreply@moonshot.cn>
b9d1164 to
0340b52
Compare
|
LGTM @MatthewBonanni could you approve if it looks good to you aswell? |
No description provided.