Multi-Query Attention
Decoding is bound by the bandwidth needed to re-read the KV cache each step. Share one K/V head across all query heads and that cache shrinks by the head count.
Standing
StaleLoad-bearing for understanding how the field arrived here, and replaced in practice by something on this list. Worth reading, not worth reaching for.
Kept for the argument it makes rather than for use: grouped-query attention recovers most of the quality it gave up, for most of the same saving.
judged as of 2026-09 · what the labels mean
Theory
At batch size 1 an autoregressive step performs a handful of matrix–vector products and re-reads the entire KV cache. Arithmetic intensity is therefore near 1, and the step time is a division: bytes read over memory bandwidth.
MQA sets ; grouped-query attention interpolates, sharing one K/V head per group of query heads. GQA at recovers essentially all of multi-head quality at an eighth of the cache, which is why it, rather than MQA, is what shipped.
Implementation
import torch
from torch import Tensor
import torch.nn.functional as F
def gqa(q: Tensor, k: Tensor, v: Tensor, mask=None) -> Tensor:
"""q: [B, H, N, D] k, v: [B, H_kv, M, D] H % H_kv == 0"""
h, h_kv = q.size(1), k.size(1)
if h != h_kv:
repeat = h // h_kv
k = k.repeat_interleave(repeat, dim=1)
v = v.repeat_interleave(repeat, dim=1)
return F.scaled_dot_product_attention(q, k, v, attn_mask=mask)repeat_interleave here is expository — it materialises the expansion. In a real
kernel the grouping is expressed as a stride of zero over the head dimension, so
the shared K/V head is read once and broadcast, which is the entire point of the
technique.