Repository navigation
[Kernel][PA] Support BF16 vectorized KV with asymmetric K/V head dim - #1065
Conversation
There was a problem hiding this comment.
Pull request overview
This PR extends the tile-programming paged-attention decode kernel to support (1) BF16 vectorized-5D KV caches and (2) asymmetric head dimensions where Q/K head dim can differ from V/output head dim, with accompanying correctness tests.
Changes:
- Add a BF16 KV specialization (K16 BF16 MFMA path) alongside the existing FP8 path in
pa_decode_tile. - Generalize PV accumulation/output/storage to use
v_head_dim(derived from the physical value dimension) instead of assuminghead_dim. - Add focused GPU correctness tests covering BF16 vectorized-5D KV (V128/V192) and FP8 asymmetric value head dim (V128).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| kernels/attention/pa_decode_tile.py | Adds BF16 KV specialization and supports independent v_head_dim across the kernel and host wrapper validation/dispatch. |
| tests/kernels/test_pa_decode_tile.py | Adds correctness coverage for BF16 vectorized-5D KV and FP8 asymmetric value head dimensions with multi-partition reduction. |
Suppressed comments (1)
kernels/attention/pa_decode_tile.py:1191
query_group_size = num_q_heads // num_kv_headsuses integer division without validating divisibility. Ifnum_q_headsis not divisible bynum_kv_heads, the kernel will silently use the truncated group size and produce incorrect indexing.
assert context_lengths.dtype == torch.int32, f"context_lengths must be int32, got {context_lengths.dtype}"
query_group_size = num_q_heads // num_kv_heads
max_blocks_per_seq = block_tables.shape[1]
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| pmax_ptr: fx.Tensor, # [num_seqs*query_length, num_kv_heads, num_partitions, query_group_size] row max | ||
| psum_ptr: fx.Tensor, # [num_seqs*query_length, num_kv_heads, num_partitions, query_group_size] row sum | ||
| pout_ptr: fx.Tensor, # [num_seqs*query_length, num_kv_heads, num_partitions, query_group_size, head_dim] Q_DTYPE, normalized O_p/l_p | ||
| pout_ptr: fx.Tensor, # [num_seqs*query_length, num_kv_heads, num_partitions, query_group_size, v_head_dim] Q_DTYPE, normalized O_p/l_p |
There was a problem hiding this comment.
Fixed in ad712fb, The workspace comments now use [num_seqs, num_kv_heads, num_partitions, total_rows], with total_rows = query_length * query_group_size, matching both host allocation and flattened kernel indexing.
Besides, I also added host-side validation that num_q_heads is divisible by num_kv_heads before deriving the query group size.
4ea457e to
cc5bbdb
Compare
| per_token_kv: bool = False, | ||
| query_length: int = 1, | ||
| trans_v: bool = True, | ||
| bf16_kv: bool = False, |
There was a problem hiding this comment.
Thanks for your suggestions. In ab4e847 I've updated the compile-time API in from bf16_kv: bool to kv_dtype: str, validated as fp8 or bf16. The host derives it from the physical key-cache dtype, while the kernel uses an internal is_bf16_kv boolean for specialization branches. This describes the full KV storage/layout path rather than only the selected MFMA instruction.
|
also change pa_decode_ps_launch ? |
Signed-off-by: Xiake Sun <xiake.sun@amd.com>
… test_pa.py Signed-off-by: Xiake Sun <xiake.sun@amd.com>
Signed-off-by: Xiake Sun <xiake.sun@amd.com>
- Add docs for partition workspaces using the flattened total-row dimension that matches host allocation and kernel indexing. - Reject Q-head counts that are not divisible by the number of KV heads before deriving the query group size. Signed-off-by: Xiake Sun <xiake.sun@amd.com>
Signed-off-by: Xiake Sun <xiake.sun@amd.com>
Signed-off-by: Xiake Sun <xiake.sun@amd.com>
ad712fb to
53236d0
Compare
Thanks for your suggestions. In 53236d0, I've updated The scope of this PR is limited to BF16 asymmetric Paged Attention (PA) support for |
| @pytest.mark.parametrize( | ||
| "entrypoint", | ||
| ["tile", "ps-allocate", "ps-preallocated"], | ||
| ids=["direct", "ps-allocate", "ps-preallocated"], | ||
| ) |
| if max_context_partition_num <= 0: | ||
| raise ValueError("max_context_partition_num must be positive.") |
Port vector8 BF16 KV and K16 MFMA from ROCm/FlyDSL#1065 into the planned PA pipeline. Keep softmax and accumulation in FP32, split MTP queries to fit LDS, and distinguish KV precision in the native tuner cache. Validation: 109 tests pass on gfx942, native eager/graph tuning and cache-hit checks pass, and BF16 addressing beyond 2 GiB passes. Black, Ruff and diff checks pass.
Motivation
Based on #1064
Add BF16 vectorized-5D KV support and allow different Q/K and V/output head dimensions in
pa_decode_tilekernel.Technical Details
Extend FlyDSL PA kernel to support Models with different K/V head dim with Both FP8 and BF16 support.
E.g. MiMo-V2.5-Pro with Q/K D192 and V/O D128 does not need to physically pad V to 192.
The same tile PA path is also useful for native BF16 page-64 KV on gfx942 and gfx950.
from the physical value dimension.
Performance (gfx950)
Batch 32, query length 4, 16Q/1KV, Q/K D192, page 64:
Test Plan
Extend test_pa_decode_tile.py to covers BF16 QL1/QL4 with V128/V192, asymmetric FP8, symmetric FP8 D192, multi-partition reduction.
python -m pytest -q tests/kernels/test_pa.pyTest Result
Submission Checklist