[AMD] Let the diffusion AITer backend take grouped-query K/V (fix Cosmos3-Nano startup) (#34485)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Michael <michaelzhang-ai@users.noreply.github.com>
This commit is contained in:
Michael
2026-08-19 00:17:40 -07:00
committed by GitHub
co-authored by Cursor Agent Michael
parent c0c87e0547
commit f4158719d1
2 changed files with 49 additions and 3 deletions
@@ -128,9 +128,14 @@ class AITerImpl(AttentionImpl):
dropout_p: float = 0.0,
**extra_impl_args,
) -> None:
if num_kv_heads is not None and num_kv_heads != num_heads:
raise NotImplementedError(
"AITer backend does not support Grouped Query Attention yet."
# aiter's mha entry points take GQA/MQA K/V directly (they broadcast
# each KV head across its group of query heads), so the only
# requirement is an even split. The FP8 ASM path is MHA-only and
# already routes grouped shapes back to BF16 below.
if num_kv_heads is not None and num_heads % num_kv_heads != 0:
raise ValueError(
f"AITer backend requires num_heads ({num_heads}) to be a "
f"multiple of num_kv_heads ({num_kv_heads})."
)
self.causal = causal
self.dropout_p = dropout_p
@@ -0,0 +1,41 @@
# SPDX-License-Identifier: Apache-2.0
"""AITer attention impl construction guards (ROCm-only; skipped elsewhere)."""
import pytest
HEAD_SIZE = 128
def _impl_cls():
# `aiter` ships with ROCm only, and importing the backend module needs it.
pytest.importorskip("aiter", reason="AITer is a ROCm-only dependency")
from sglang.multimodal_gen.runtime.layers.attention.backends.aiter import AITerImpl
return AITerImpl
def _build(num_heads: int, num_kv_heads: int | None):
return _impl_cls()(
num_heads=num_heads,
head_size=HEAD_SIZE,
softmax_scale=HEAD_SIZE**-0.5,
num_kv_heads=num_kv_heads,
)
@pytest.mark.parametrize("num_kv_heads", [32, 8, 1, None])
def test_accepts_grouped_and_multi_query_kv_heads(num_kv_heads):
# aiter's mha entry points broadcast each KV head across its group of
# query heads, so Cosmos3-style GQA cross-attention is supported.
assert _build(32, num_kv_heads).softmax_scale == pytest.approx(HEAD_SIZE**-0.5)
def test_rejects_kv_heads_that_do_not_divide_the_query_heads():
with pytest.raises(ValueError, match="multiple of num_kv_heads"):
_build(32, 5)
if __name__ == "__main__":
import sys
sys.exit(pytest.main([__file__, "-v"]))