Pratham Patel
· 32 min read

Grouped-Query Attention: Fewer KV Heads, Same Quality

Building GQA from the ground up — from multi-head attention to multi-query attention to grouped-query attention — showing exactly how sharing KV heads across query groups reduces the KV cache by a factor of h/g while preserving nearly all of MHA's quality. Every formula derived, every number verified.

The previous blog established that autoregressive inference is memory-bandwidth-bound, and that the KV cache is the dominant memory load at long contexts. The formula was exact: bytes/token=Lh(dk+dv)2\text{bytes/token} = L \cdot h \cdot (d_k + d_v) \cdot 2. The factor hh — the number of KV heads — appears linearly. Reduce hKVh_\text{KV} and the cache shrinks proportionally.

This blog derives the two techniques that pull this lever: Multi-Query Attention (MQA, Shazeer 2019), which collapses all KV heads to one, and Grouped-Query Attention (GQA, Ainslie et al. 2023), which finds the sweet spot in between. We re-derive both from the vanilla formula, verify every number with our running model, and trace through the GQA paper’s key experimental results.


The Running Model

Same as every blog in this series:

  • dmodel=512d_\text{model} = 512
  • h=8h = 8 query heads
  • dk=dv=64d_k = d_v = 64
  • L=12L = 12 layers
  • fp16 (2 bytes per element)

All KV cache numbers are per-token unless stated otherwise.


Vanilla MHA: The Baseline to Beat

In standard multi-head attention, each head i{1,,h}i \in \{1, \ldots, h\} has its own query, key, and value projection:

Qi=XWQi,Ki=XWKi,Vi=XWViQ^i = X W_Q^i, \quad K^i = X W_K^i, \quad V^i = X W_V^i

where WQi,WKiRdmodel×dkW_Q^i, W_K^i \in \mathbb{R}^{d_\text{model} \times d_k} and WViRdmodel×dvW_V^i \in \mathbb{R}^{d_\text{model} \times d_v}. Each head computes attention independently:

Ai=softmax ⁣(QiKidk),oi=AiViA^i = \text{softmax}\!\left(\frac{Q^i {K^i}^\top}{\sqrt{d_k}}\right), \quad o^i = A^i V^i

The outputs are concatenated and projected:

MHA(X)=concat(o1,,oh)WO\text{MHA}(X) = \text{concat}(o^1, \ldots, o^h) \, W_O

Counting every parameter and byte

Let us be extremely precise about what MHA costs. We count three things: parameters, cache, and bandwidth.

Total attention parameters per layer. There are four categories of weight matrices:

  1. Query projections: hh matrices WQiRdmodel×dkW_Q^i \in \mathbb{R}^{d_\text{model} \times d_k}, each with dmodeldk=512×64=32,768d_\text{model} \cdot d_k = 512 \times 64 = 32{,}768 parameters. Total: hdmodeldk=8×32,768=262,144h \cdot d_\text{model} \cdot d_k = 8 \times 32{,}768 = 262{,}144.
  2. Key projections: same count. Total: 262,144262{,}144.
  3. Value projections: same count (dv=dkd_v = d_k). Total: 262,144262{,}144.
  4. Output projection: WOR(hdv)×dmodel=R512×512W_O \in \mathbb{R}^{(h \cdot d_v) \times d_\text{model}} = \mathbb{R}^{512 \times 512}. Total: dmodel2=262,144d_\text{model}^2 = 262{,}144.

Grand total per layer: 4×262,144=1,048,5761M4 \times 262{,}144 = 1{,}048{,}576 \approx 1\text{M} parameters.

Numerical check: This is 4dmodel2=4×5122=4×262,144=1,048,5764 \cdot d_\text{model}^2 = 4 \times 512^2 = 4 \times 262{,}144 = 1{,}048{,}576. Correct — MHA’s attention block has exactly 4dmodel24 d_\text{model}^2 parameters, independent of how those parameters are divided among heads.

KV parameters specifically. The KV projections are categories 2 and 3 above:

KV params per layer=hdmodel(dk+dv)=8×512×(64+64)=524,288\text{KV params per layer} = h \cdot d_\text{model} \cdot (d_k + d_v) = 8 \times 512 \times (64 + 64) = 524{,}288

As a fraction of total attention parameters: 524,288/1,048,576=0.5524{,}288 / 1{,}048{,}576 = 0.5. Exactly half of the attention parameters are in KV projections. This makes sense: Q and O each contribute dmodel2d_\text{model}^2 parameters, and K+V together also contribute hdmodel(dk+dv)=2dmodel2h \cdot d_\text{model} \cdot (d_k + d_v) = 2 d_\text{model}^2 in our running model where dk=dvd_k = d_v and hdk=dmodelh d_k = d_\text{model}.

KV cache per token per layer. At inference, for each processed token, we store one key vector and one value vector per head:

KV cache per token per layer=h(dk+dv)2=8×(64+64)×2=2,048 bytes\text{KV cache per token per layer} = h \cdot (d_k + d_v) \cdot 2 = 8 \times (64 + 64) \times 2 = 2{,}048 \text{ bytes}

Let us break this down further — element by element — to make sure we understand exactly what is stored:

  • Head 1: kt1R64k_t^1 \in \mathbb{R}^{64} (128 bytes) + vt1R64v_t^1 \in \mathbb{R}^{64} (128 bytes) = 256 bytes
  • Head 2: kt2R64k_t^2 \in \mathbb{R}^{64} (128 bytes) + vt2R64v_t^2 \in \mathbb{R}^{64} (128 bytes) = 256 bytes
  • Head 8: kt8R64k_t^8 \in \mathbb{R}^{64} (128 bytes) + vt8R64v_t^8 \in \mathbb{R}^{64} (128 bytes) = 256 bytes

Total: 8×256=2,0488 \times 256 = 2{,}048 bytes per token per layer. Across L=12L = 12 layers:

12×2,048=24,576 bytes=24 KB per token12 \times 2{,}048 = 24{,}576 \text{ bytes} = 24 \text{ KB per token}

KV memory bandwidth per step. At context length tt, generating the next token requires loading all tt cached K and V vectors from HBM (one full read of the entire cache per step):

bandwidthKV=Lh(dk+dv)2t=24,576t bytes\text{bandwidth}_\text{KV} = L \cdot h \cdot (d_k + d_v) \cdot 2 \cdot t = 24{,}576 \cdot t \text{ bytes}

At t=4,096t = 4{,}096: 24,576×4,096=100,663,29624{,}576 \times 4{,}096 = 100{,}663{,}296 bytes 96\approx 96 MB per step.

At t=128,000t = 128{,}000: 24,576×128,000=3,145,728,00024{,}576 \times 128{,}000 = 3{,}145{,}728{,}000 bytes 3\approx 3 GB per step.

These are the numbers to beat. Every variant in this blog reduces one or more of these costs.


Multi-Query Attention: The Extreme Case

Multi-Query Attention (MQA) was introduced by Shazeer (2019). The idea is the simplest possible attack on the KV cache: keep hh separate query heads, but use a single shared key head and a single shared value head.

Deriving MQA from MHA

Start from the MHA formula and make one change: instead of hh separate key matrices WK1,,WKhW_K^1, \ldots, W_K^h and hh separate value matrices WV1,,WVhW_V^1, \ldots, W_V^h, use a single shared WKW_K and a single shared WVW_V.

There is now one WKRdmodel×dkW_K \in \mathbb{R}^{d_\text{model} \times d_k} and one WVRdmodel×dvW_V \in \mathbb{R}^{d_\text{model} \times d_v}. Each query head still has its own WQiW_Q^i:

Qi=XWQii{1,,h},K=XWK,V=XWVQ^i = X W_Q^i \quad \forall\, i \in \{1, \ldots, h\}, \qquad K = X W_K, \qquad V = X W_V

Head ii computes attention using its own query against the shared key and value:

Ai=softmax ⁣(QiKdk),oi=AiVA^i = \text{softmax}\!\left(\frac{Q^i K^\top}{\sqrt{d_k}}\right), \quad o^i = A^i V

Every head uses the same KK and VV. The concatenation and output projection are unchanged:

MQA(X)=concat(o1,,oh)WO\text{MQA}(X) = \text{concat}(o^1, \ldots, o^h) \, W_O

Deriving the savings step by step

KV parameters per layer. We now have one WKW_K and one WVW_V instead of hh of each:

KV paramsMQA=dmodel(dk+dv)=512×(64+64)=65,536\text{KV params}_\text{MQA} = d_\text{model} \cdot (d_k + d_v) = 512 \times (64 + 64) = 65{,}536

Compare to MHA: 524,288524{,}288. The ratio:

KV paramsMHAKV paramsMQA=524,28865,536=8=h\frac{\text{KV params}_\text{MHA}}{\text{KV params}_\text{MQA}} = \frac{524{,}288}{65{,}536} = 8 = h

MQA uses h×h\times fewer KV parameters. The factor is exactly the number of heads, because we went from hh copies to 1 copy.

Total attention parameters per layer. Q projections are unchanged: hdmodeldk=262,144h \cdot d_\text{model} \cdot d_k = 262{,}144. KV projections: 65,53665{,}536 (down from 524,288524{,}288). Output projection: 262,144262{,}144 (unchanged).

Total: 262,144+65,536+262,144=589,824262{,}144 + 65{,}536 + 262{,}144 = 589{,}824.

Compare to MHA: 1,048,5761{,}048{,}576. Ratio: 1,048,576/589,824=1.781{,}048{,}576 / 589{,}824 = 1.78. MQA has 44%44\% fewer attention parameters — a significant reduction, but less than the 8×8\times cache reduction because the Q and O matrices are unchanged.

KV cache per token per layer. Only one K vector and one V vector are cached (shared across all heads):

KV cacheMQA=1(dk+dv)2=(64+64)×2=256 bytes\text{KV cache}_\text{MQA} = 1 \cdot (d_k + d_v) \cdot 2 = (64 + 64) \times 2 = 256 \text{ bytes}

Let us spell out exactly what is stored per token per layer in MQA:

  • Shared K: ktR64k_t \in \mathbb{R}^{64} (128 bytes)
  • Shared V: vtR64v_t \in \mathbb{R}^{64} (128 bytes)
  • Total: 256 bytes

Compare to MHA’s 2,048 bytes per token per layer. Ratio: 2,048/256=8=h2{,}048 / 256 = 8 = h. Exactly h×h\times smaller.

Across L=12L = 12 layers: 12×256=3,07212 \times 256 = 3{,}072 bytes =3= 3 KB/token.

Numerical check: MHA was 24 KB/token. 24/3=8=h24 / 3 = 8 = h. Correct.

Bandwidth per step at t=4,096t = 4{,}096:

3,072×4,096=12,582,912 bytes12 MB3{,}072 \times 4{,}096 = 12{,}582{,}912 \text{ bytes} \approx 12 \text{ MB}

Compare to MHA’s 96 MB — an 8×8\times reduction. At A100 bandwidth of 2 TB/s:

TKVMQA=12×1062×1012=6 microsecondsT_\text{KV}^\text{MQA} = \frac{12 \times 10^6}{2 \times 10^{12}} = 6 \text{ microseconds}

Compare to MHA’s 48 microseconds. The KV cache loading time dropped from 48 μ\mus to 6 μ\mus. This is the primary source of MQA’s inference speedup.

Bandwidth per step at t=128,000t = 128{,}000:

3,072×128,000=393,216,000 bytes375 MB3{,}072 \times 128{,}000 = 393{,}216{,}000 \text{ bytes} \approx 375 \text{ MB}

Compare to MHA’s 3 GB. Still 8×8\times smaller.

What MQA changes about the attention computation

This is the part that confuses almost everyone on first encounter. In MHA, each head’s attention scores are:

sji=(qi)kjidks_j^i = \frac{(q^i)^\top k_j^i}{\sqrt{d_k}}

Head ii‘s query qiq^i is dotted with head ii‘s keys kjik_j^i. Each head operates in its own subspace.

In MQA:

sji=(qi)kjdks_j^i = \frac{(q^i)^\top k_j}{\sqrt{d_k}}

Head ii‘s query qiq^i — which lives in a head-specific subspace defined by WQiW_Q^i — is dotted with the shared key kjk_j — which lives in a single subspace defined by the shared WKW_K.

The attention scores are different per head (because each qiq^i is different), so each head produces a different attention distribution aia^i. But the values being weighted are the same VV for all heads. So the output of each head is:

oi=jajivjo^i = \sum_j a_j^i \cdot v_j

Different heads produce different weighted combinations of the same value vectors. In MHA, different heads produce different weighted combinations of different value vectors.

Concrete example. Suppose at position tt, head 1 assigns attention weight 0.8 to token 5 and 0.2 to token 12, while head 3 assigns weight 0.5 to each. In MHA:

o1=0.8v51+0.2v121,o3=0.5v53+0.5v123o^1 = 0.8 \cdot v_5^1 + 0.2 \cdot v_{12}^1, \quad o^3 = 0.5 \cdot v_5^3 + 0.5 \cdot v_{12}^3

The two outputs differ in both the weights and the values. In MQA:

o1=0.8v5+0.2v12,o3=0.5v5+0.5v12o^1 = 0.8 \cdot v_5 + 0.2 \cdot v_{12}, \quad o^3 = 0.5 \cdot v_5 + 0.5 \cdot v_{12}

The outputs differ only in the weights. Both heads are selecting from the same “library” of value representations. This is a meaningful capacity reduction — the model can no longer represent different information per head in the value space.

The cost of MQA: empirical evidence

The GQA paper (Ainslie et al., 2023, Table 1) quantifies the quality cost on T5-XXL:

ModelAvg. qualityInference time (s/sample)
MHA-XXL47.21.51
MQA-XXL (uptrained)46.60.24

The quality drops by 0.6 points. The inference time drops by 6.3×6.3\times.

Is a 0.6-point quality drop acceptable? It depends on the application. For some tasks, 0.6 points is noise. For others — especially when the model is already near the state of the art — 0.6 points is the difference between best-in-class and second-tier.

The question becomes: can we find a middle ground that recovers most of the quality while keeping most of the speed?


Grouped-Query Attention: The Interpolation

Grouped-Query Attention (GQA) is the answer. It was introduced by Ainslie et al. (2023) as a generalization that places MHA and MQA at opposite ends of a single spectrum.

The idea

Divide the hh query heads into gg groups of equal size. Each group of h/gh/g query heads shares one key head and one value head. There are gg KV heads total.

Three boundary cases:

  • g=hg = h: every group has exactly one query head → every query head has its own KV head → this is MHA
  • g=1g = 1: all hh query heads are in one group → all share one KV head → this is MQA
  • 1<g<h1 < g < h: the intermediate case → this is GQA

Writing the formula explicitly

Let gg denote the number of KV groups. The number of query heads per group is h/gh/g (we require gg divides hh). The heads are partitioned into consecutive groups:

  • Group 1: query heads {1,2,,h/g}\{1, 2, \ldots, h/g\}
  • Group 2: query heads {h/g+1,,2h/g}\{h/g + 1, \ldots, 2h/g\}
  • Group gg: query heads {hh/g+1,,h}\{h - h/g + 1, \ldots, h\}

For our running model with h=8h = 8 and g=2g = 2: group 1 has query heads {1,2,3,4}\{1, 2, 3, 4\}, group 2 has query heads {5,6,7,8}\{5, 6, 7, 8\}. Each group has h/g=4h/g = 4 query heads sharing one KV head.

For KV group j{1,,g}j \in \{1, \ldots, g\}, compute the shared key and value:

Kj=XWKj,Vj=XWVjK^j = X W_K^j, \quad V^j = X W_V^j

For query head ii belonging to group j=ig/hj = \lceil i \cdot g / h \rceil, compute:

Qi=XWQiQ^i = X W_Q^i Ai=softmax ⁣(QiKjdk)A^i = \text{softmax}\!\left(\frac{Q^i {K^j}^\top}{\sqrt{d_k}}\right) oi=AiVjo^i = A^i V^j

The output is the same concatenation and projection as always:

GQA(X)=concat(o1,,oh)WO\text{GQA}(X) = \text{concat}(o^1, \ldots, o^h) \, W_O

Deriving the savings for general gg

KV parameters per layer. There are gg key matrices of size dmodel×dkd_\text{model} \times d_k and gg value matrices of size dmodel×dvd_\text{model} \times d_v:

KV paramsGQA=gdmodel(dk+dv)\text{KV params}_\text{GQA} = g \cdot d_\text{model} \cdot (d_k + d_v)

With g=2g = 2:

2×512×(64+64)=131,0722 \times 512 \times (64 + 64) = 131{,}072

With g=4g = 4:

4×512×(64+64)=262,1444 \times 512 \times (64 + 64) = 262{,}144

Numerical check of the reduction factor for g=2g = 2:

KV paramsMHAKV paramsGQA=524,288131,072=4=hg=82\frac{\text{KV params}_\text{MHA}}{\text{KV params}_\text{GQA}} = \frac{524{,}288}{131{,}072} = 4 = \frac{h}{g} = \frac{8}{2}

For g=4g = 4: 524,288/262,144=2=8/4524{,}288 / 262{,}144 = 2 = 8/4. Correct in both cases.

KV cache per token per layer. Each of the gg KV groups caches one K vector and one V vector:

KV cacheGQA=g(dk+dv)2\text{KV cache}_\text{GQA} = g \cdot (d_k + d_v) \cdot 2

Let us compute this for every possible gg in our h=8h = 8 model. Since gg must divide hh, the options are g{1,2,4,8}g \in \{1, 2, 4, 8\}:

g=1g = 1 (MQA): 1×128×2=2561 \times 128 \times 2 = 256 bytes per layer

g=2g = 2: 2×128×2=5122 \times 128 \times 2 = 512 bytes per layer

g=4g = 4: 4×128×2=1,0244 \times 128 \times 2 = 1{,}024 bytes per layer

g=8g = 8 (MHA): 8×128×2=2,0488 \times 128 \times 2 = 2{,}048 bytes per layer

Across L=12L = 12 layers:

ggbytes/token/layerbytes/token (all layers)KB/token
1 (MQA)2563,0723
25126,1446
41,02412,28812
8 (MHA)2,04824,57624

Numerical check: each row is exactly g/8g/8 of the MHA row. 3/24=1/83 / 24 = 1/8, 6/24=1/46 / 24 = 1/4, 12/24=1/212 / 24 = 1/2. Correct.

The general reduction formula

Dividing the MHA cache by the GQA cache:

KV cacheMHAKV cacheGQA=h(dk+dv)2g(dk+dv)2\frac{\text{KV cache}_\text{MHA}}{\text{KV cache}_\text{GQA}} = \frac{h \cdot (d_k + d_v) \cdot 2}{g \cdot (d_k + d_v) \cdot 2}

The (dk+dv)(d_k + d_v) factor appears in both numerator and denominator — it cancels. The factor of 2 (bytes per element) also cancels. What remains is:

hg\frac{h}{g} KV cache reduction factor=hg\boxed{\text{KV cache reduction factor} = \frac{h}{g}}

This is the central equation. The reduction depends only on the ratio of query heads to KV groups. Not on dkd_k, not on dvd_v, not on dmodeld_\text{model}, not on LL, not on the sequence length. Just h/gh/g.

Interpretation. This result says something powerful: regardless of model size, head dimension, or sequence length, GQA with gg groups reduces the KV cache by exactly h/gh/g. A model with 128 heads and 16 groups gets the same 8×8\times reduction as a model with 8 heads and 1 group (MQA). The formula is universal.

Bandwidth savings at every context length

The bandwidth per step for GQA at context length tt:

BWGQA(t)=Lg(dk+dv)2t\text{BW}_\text{GQA}(t) = L \cdot g \cdot (d_k + d_v) \cdot 2 \cdot t

For our model with g=2g = 2, at several context lengths:

Context ttMHA bandwidthGQA-2 bandwidthMQA bandwidth
51212 MB3 MB1.5 MB
1,02424 MB6 MB3 MB
4,09696 MB24 MB12 MB
16,384384 MB96 MB48 MB
128,0003,000 MB750 MB375 MB

Numerical check for GQA-2 at t=4,096t = 4{,}096: 6,144×4,096=25,165,8246{,}144 \times 4{,}096 = 25{,}165{,}824 bytes 24\approx 24 MB. 96/24=4=h/g96 / 24 = 4 = h/g. Correct.

At t=128,000t = 128{,}000: 6,144×128,000=786,432,0007506{,}144 \times 128{,}000 = 786{,}432{,}000 \approx 750 MB. 3,000/750=43{,}000 / 750 = 4. Correct.


Converting an MHA Checkpoint to GQA

A key practical contribution of the GQA paper is a recipe for converting existing MHA models to GQA without training from scratch. Pre-training from scratch costs millions of dollars. If we can convert an existing checkpoint, we save almost all of that cost.

The conversion problem

We have a trained MHA model with hh key projection matrices WK1,,WKhRdmodel×dkW_K^1, \ldots, W_K^h \in \mathbb{R}^{d_\text{model} \times d_k} and hh value projection matrices WV1,,WVhRdmodel×dvW_V^1, \ldots, W_V^h \in \mathbb{R}^{d_\text{model} \times d_v}. We want to produce g<hg < h key matrices and gg value matrices.

The query projections WQ1,,WQhW_Q^1, \ldots, W_Q^h and the output projection WOW_O remain unchanged. Only the KV projections change.

The mean-pooling conversion

The paper’s approach: for each group, average the original KV heads assigned to that group.

Step 1. Choose gg (must divide hh). Partition heads into gg groups of size h/gh/g.

Step 2. For group j{1,,g}j \in \{1, \ldots, g\}, let Gj={(j1)h/g+1,,jh/g}G_j = \{(j-1) \cdot h/g + 1, \ldots, j \cdot h/g\} be the set of original head indices in this group. Compute:

WK(j)=1GjiGjWKi=ghiGjWKiW_K^{(j)} = \frac{1}{|G_j|} \sum_{i \in G_j} W_K^i = \frac{g}{h} \sum_{i \in G_j} W_K^i WV(j)=1GjiGjWVi=ghiGjWViW_V^{(j)} = \frac{1}{|G_j|} \sum_{i \in G_j} W_V^i = \frac{g}{h} \sum_{i \in G_j} W_V^i

This is mean pooling — each element of the new weight matrix is the arithmetic mean of the corresponding elements from the original heads in the group. Matrix addition is elementwise: (A+B)ij=Aij+Bij(A + B)_{ij} = A_{ij} + B_{ij}.

Tracing the conversion for our running model

In our model with h=8h = 8 and g=2g = 2:

  • Group 1 (G1G_1): original heads {1,2,3,4}\{1, 2, 3, 4\}
  • Group 2 (G2G_2): original heads {5,6,7,8}\{5, 6, 7, 8\}

Each original WKiR512×64W_K^i \in \mathbb{R}^{512 \times 64} has 32,768 parameters. The mean-pooled group key:

WK(1)=14(WK1+WK2+WK3+WK4)R512×64W_K^{(1)} = \frac{1}{4}\left(W_K^1 + W_K^2 + W_K^3 + W_K^4\right) \in \mathbb{R}^{512 \times 64}

To see what happens at the element level, take element (r,c)(r, c) for row r{1,,512}r \in \{1, \ldots, 512\} and column c{1,,64}c \in \{1, \ldots, 64\}:

[WK(1)]rc=14([WK1]rc+[WK2]rc+[WK3]rc+[WK4]rc)[W_K^{(1)}]_{rc} = \frac{1}{4}\left([W_K^1]_{rc} + [W_K^2]_{rc} + [W_K^3]_{rc} + [W_K^4]_{rc}\right)

Suppose the four original values at position (1,1)(1, 1) are 0.12,0.05,0.08,0.030.12, -0.05, 0.08, 0.03. Then:

[WK(1)]1,1=0.12+(0.05)+0.08+0.034=0.184=0.045[W_K^{(1)}]_{1,1} = \frac{0.12 + (-0.05) + 0.08 + 0.03}{4} = \frac{0.18}{4} = 0.045

This is repeated for all 512×64=32,768512 \times 64 = 32{,}768 elements.

Counting the resulting parameters. Before conversion: 8×2×32,768=524,2888 \times 2 \times 32{,}768 = 524{,}288 KV parameters. After conversion: 2×2×32,768=131,0722 \times 2 \times 32{,}768 = 131{,}072 KV parameters. Reduction: 524,288/131,072=4=h/g524{,}288 / 131{,}072 = 4 = h/g. Correct.

Why mean pooling works best

The paper (Ainslie et al., 2023, Figure 4) compares three conversion methods for T5-Large uptrained to MQA with α=0.05\alpha = 0.05:

MethodPerformance score
Mean pooling55.6\approx 55.6
First head selection55.2\approx 55.2
Random initialization54.4\approx 54.4

Mean pooling averages all h/gh/g original heads in each group. It preserves the componentwise average signal across those heads, so it tends to retain the shared structure that multiple heads learned in common.

First head selection picks WK1W_K^1 and discards WK2,,WKh/gW_K^2, \ldots, W_K^{h/g}. It preserves one head’s learned features perfectly but completely loses the other h/g1h/g - 1 heads’ contributions. In our model with g=2g = 2, selecting the first head discards 3 out of 4 heads’ worth of learned representations.

Random initialization creates WK(j)W_K^{(j)} with random weights drawn from an initialization distribution. It discards all learned information and relies entirely on uptraining to learn new representations from scratch.

The ranking makes intuitive sense: more information preserved → better starting point → less work for uptraining → higher final quality.

Numerical argument for why mean beats first. Consider a toy case where each head’s key projection adds a different “feature direction” to the representation. Head 1 projects onto direction u1u_1, head 2 onto u2u_2, etc. The mean pooling result 14(u1+u2+u3+u4)\frac{1}{4}(u_1 + u_2 + u_3 + u_4) retains a component along all four directions — attenuated by 1/41/4, but present. First-head selection keeps only u1u_1 and has zero component along u2,u3,u4u_2, u_3, u_4. In this toy setup, the mean is a more balanced initialization because it preserves information from all four original directions rather than discarding three of them outright.

Uptraining: adapting to the new structure

After conversion, the model is pre-trained for an additional α\alpha fraction of the original pre-training steps. The paper uses α=0.05\alpha = 0.05 — just 5% of the original compute.

Why uptraining is necessary. After mean-pooling, the KV projections have changed. Head 1’s query WQ1W_Q^1 was trained to work with head 1’s key WK1W_K^1 — they learned complementary representations. Now head 1’s query must work with the group’s mean key WK(1)=14(WK1+WK2+WK3+WK4)W_K^{(1)} = \frac{1}{4}(W_K^1 + W_K^2 + W_K^3 + W_K^4). The dot products qt1kt(1)q_t^1 \cdot k_t^{(1)} will produce different attention patterns than qt1kt1q_t^1 \cdot k_t^1.

Let us trace this quantitatively. Before conversion, the attention score for head 1 between query position tt and key position ss is:

scorebefore=(xtWQ1)(xsWK1)=xt(WQ1WK1)xs\text{score}_\text{before} = (x_t W_Q^1)^\top (x_s W_K^1) = x_t^\top (W_Q^1 {W_K^1}^\top) x_s

After conversion (before uptraining):

scoreafter=(xtWQ1)(xsWK(1))=xt(WQ114i=14WKi)xs\text{score}_\text{after} = (x_t W_Q^1)^\top (x_s W_K^{(1)}) = x_t^\top \left(W_Q^1 \cdot \frac{1}{4}\sum_{i=1}^{4} {W_K^i}^\top\right) x_s

By the distributive law of matrix multiplication:

=14i=14xt(WQ1WKi)xs=14(score11+score12+score13+score14)= \frac{1}{4} \sum_{i=1}^{4} x_t^\top (W_Q^1 {W_K^i}^\top) x_s = \frac{1}{4}\left(\text{score}_{11} + \text{score}_{12} + \text{score}_{13} + \text{score}_{14}\right)

where score1i=xt(WQ1WKi)xs\text{score}_{1i} = x_t^\top (W_Q^1 {W_K^i}^\top) x_s is what head 1’s query would score against head ii‘s key.

The post-conversion score is the average of what head 1’s query would have scored against all four original keys. This is a reasonable starting point — but it is not what the model was optimized for. The score12,score13,score14\text{score}_{12}, \text{score}_{13}, \text{score}_{14} terms are “cross-head” interactions that the original model never trained on.

Uptraining allows WQ1W_Q^1 to adapt. It learns to produce queries that give useful attention patterns when scored against the mean key projection. With 5% uptraining (α=0.05\alpha = 0.05), this adaptation is sufficient to recover nearly all quality.

Uptraining cost. The paper reports approximately 600 TPUv3 chip-days for uptraining T5-XXL at α=0.05\alpha = 0.05. The original T5-XXL pre-training cost was roughly 12,000 chip-days. So 0.05×12,000=6000.05 \times 12{,}000 = 600 chip-days — consistent with the reported number. This is a one-time investment that converts an MHA model to a faster inference model.

How quality changes with uptraining proportion

The paper (Figure 5) shows performance as a function of α\alpha for T5-XXL with MQA and GQA-8:

α\alphaMQA qualityGQA-8 qualityMHA baseline
0 (no uptraining)~53.5~55.556.2
0.02~55.5~56.556.2
0.05~56.5~57.056.2
0.10~57.0~57.056.2

Two observations:

  1. GQA starts higher than MQA even at α=0\alpha = 0. The mean-pooled GQA checkpoint is a better starting point because it has g=8g = 8 distinct KV heads rather than just 1, preserving more of the original model’s representational capacity.

  2. Both reach diminishing returns around α=0.05\alpha = 0.05. Doubling the uptraining to α=0.10\alpha = 0.10 gives marginal improvement. The 5% threshold appears to be sufficient for the query projections to adapt.


The Quality-Speed Tradeoff: Tracing the Paper’s Results

The GQA paper’s central result (Figure 3, Table 1) shows the Pareto frontier of quality vs. inference speed. We trace the key data points in detail.

Experimental setup

The paper uses T5 models (Raffel et al., 2020) implemented in JAX with Flax:

  • T5-Large with standard MHA (baseline, small but fast)
  • T5-XXL with MHA (baseline, large and slow)
  • T5-XXL uptrained to MQA (α=0.05\alpha = 0.05)
  • T5-XXL uptrained to GQA-8 (α=0.05\alpha = 0.05, i.e., 8 KV groups out of 64 query heads)

Evaluation on summarization tasks (CNN/Daily Mail, arXiv, PubMed, MediaSum, MultiNews), translation (WMT), and question answering (TriviaQA).

Main results

ModelAttentionTinferT_\text{infer} (s)AverageCNNarXivPubMedMediaSumMultiNewsWMTTriviaQA
MHA-LargeMHA0.3746.042.944.646.235.546.627.778.2
MHA-XXLMHA1.5147.243.845.647.536.446.928.481.9
MQA-XXLMQA0.2446.643.045.046.936.146.528.581.3
GQA-8-XXLGQA-80.2847.143.545.447.736.347.228.481.6

Interpreting the numbers

GQA-8-XXL vs. MHA-XXL (the key comparison):

  • Quality: 47.1 vs. 47.2, a drop of just 0.1 points
  • Speed: 0.28s vs. 1.51s, a 5.4×5.4\times speedup

The quality difference is small on the reported tasks. On PubMed, GQA-8 actually outperforms MHA (47.7 vs. 47.5). On arXiv, GQA-8 loses 0.2 points (45.4 vs. 45.6). These per-task fluctuations are consistent with the average gap being small, though the paper does not report a formal significance test here.

MQA-XXL vs. MHA-XXL:

  • Quality: 46.6 vs. 47.2, a drop of 0.6 points
  • Speed: 0.24s vs. 1.51s, a 6.3×6.3\times speedup

MQA is faster than GQA-8 (0.24s vs. 0.28s) but loses more quality (0.6 vs. 0.1 points).

GQA-8-XXL vs. MHA-Large (the “free lunch” comparison):

  • Quality: 47.1 vs. 46.0, GQA-8-XXL is 1.1 points better
  • Speed: 0.28s vs. 0.37s, GQA-8-XXL is also faster

This comparison reveals GQA’s real power: a large model with GQA can be both higher quality and faster than a smaller model with full MHA. You get the quality of a large model at an inference cost below a smaller model. This helps explain why GQA became a common choice in production deployments of large models.

Why the speedup is 5.4×5.4\times and not 8×8\times

T5-XXL has h=64h = 64 query heads. GQA-8 uses g=8g = 8 KV groups, so the KV cache is 64/8=8×64/8 = 8\times smaller. But the end-to-end speedup is only 5.4×5.4\times.

We derived the formula in the previous blog:

speedup=Bweights+BKVMHABweights+BKVGQA\text{speedup} = \frac{B_\text{weights} + B_\text{KV}^\text{MHA}}{B_\text{weights} + B_\text{KV}^\text{GQA}}

The KV cache is not the only contributor to per-step time. Model weight loading, FFN computation, LayerNorm, and the output projection all contribute fixed costs that are the same for MHA and GQA. The BweightsB_\text{weights} term in both numerator and denominator pulls the speedup below h/gh/g.

At infinite context length, BweightsB_\text{weights} becomes negligible and the speedup approaches h/g=8h/g = 8. The T5-XXL experiments use moderate context lengths (512–2048 tokens for most tasks), where the weight load is still significant relative to the KV cache.

The effect of number of groups (Figure 6)

The paper varies gg from 1 (MQA) to 64 (MHA) for GQA-XXL and measures inference time per sample:

GQA groups ggTime per sample (s)Relative to MHA
1 (MQA)~0.246.3×6.3\times faster
4~0.265.8×5.8\times faster
8~0.285.4×5.4\times faster
16~0.43.8×3.8\times faster
32~0.72.2×2.2\times faster
64 (MHA)~1.511.0×1.0\times

The inference time increases roughly linearly with gg for small gg and then steeply as gg approaches hh. Going from 1 to 8 groups adds only 0.04s. Going from 8 to 64 groups adds 1.23s.

This non-linearity arises because the KV cache load is g\propto g, but the fixed costs (weights, FFN) create a floor below which the total time cannot drop regardless of gg. At small gg, the fixed costs dominate and changes in gg have little effect. At large gg, the KV cache dominates and changes in gg are proportionally expensive.


Why GQA Preserves Quality

This is the part that confuses almost everyone. Reducing KV heads from 64 to 8 is an 8×8\times reduction in the key-value capacity. Why doesn’t quality collapse?

Head redundancy

Research on attention head pruning has consistently found that many heads are redundant:

  • Voita et al. (2019) showed that in a 6-layer, 8-head Transformer, only 2–3 heads per layer are “important” for translation quality. The rest can be pruned with minimal quality loss.
  • Michel et al. (2019) demonstrated that for BERT, removing 20–40% of heads has negligible effect on downstream task performance.

The implication: in MHA with 64 heads, many heads learn overlapping or nearly identical key-value representations. When GQA groups these heads and replaces their individual K/V with a shared K/V, the information loss is small because the individual heads were not contributing unique information.

What the query heads learn to do

In GQA, the h/gh/g query heads within each group share one K and V. But each query head still has its own WQiW_Q^i. The query projections are free to learn different “questions” to ask of the shared key-value representation.

Think of it as a library analogy. In MHA, each head has its own library (K and V) and its own search query (Q). In GQA, groups of heads share a library but each head still has its own search query. If the individual libraries were mostly redundant copies of the same books, consolidating them into one shared library per group loses little — the search queries can still find different information by asking different questions.

The key insight: the diversity in attention comes more from the queries than from the keys and values. Different heads attend to different positions primarily because their query projections differ, not because their key projections differ. GQA preserves all query diversity while reducing key-value redundancy.

Mathematical argument

Consider two query heads i1i_1 and i2i_2 in the same group, sharing key KjK^j. Their attention distributions are:

ai1=softmax(Qi1Kjdk),ai2=softmax(Qi2Kjdk)a^{i_1} = \text{softmax}\left(\frac{Q^{i_1} {K^j}^\top}{\sqrt{d_k}}\right), \quad a^{i_2} = \text{softmax}\left(\frac{Q^{i_2} {K^j}^\top}{\sqrt{d_k}}\right)

Even though KjK^j is the same, the attention distributions differ because Qi1Qi2Q^{i_1} \neq Q^{i_2}. The query matrices project the input into different subspaces, producing different attention scores against the same keys.

The two heads will attend to different positions as long as WQi1W_Q^{i_1} and WQi2W_Q^{i_2} are sufficiently different. Since these query projections are not constrained to be similar (they are separate learned parameters), the model retains the ability to attend to multiple different features simultaneously — as many as there are query heads.


Deriving the Inference Time Improvement

We can predict the speedup from GQA analytically.

The speedup formula

Per-step inference time is dominated by memory bandwidth. The total bytes loaded per step:

Bstep=Bweights+BKV(t)B_\text{step} = B_\text{weights} + B_\text{KV}(t)

For MHA:

BstepMHA=Bweights+Lh(dk+dv)2tB_\text{step}^\text{MHA} = B_\text{weights} + L \cdot h \cdot (d_k + d_v) \cdot 2 \cdot t

For GQA with gg groups:

BstepGQA=Bweights+Lg(dk+dv)2tB_\text{step}^\text{GQA} = B_\text{weights} + L \cdot g \cdot (d_k + d_v) \cdot 2 \cdot t

The speedup ratio:

speedup(t)=BstepMHABstepGQA=Bweights+Lh(dk+dv)2tBweights+Lg(dk+dv)2t\text{speedup}(t) = \frac{B_\text{step}^\text{MHA}}{B_\text{step}^\text{GQA}} = \frac{B_\text{weights} + L \cdot h \cdot (d_k + d_v) \cdot 2 \cdot t}{B_\text{weights} + L \cdot g \cdot (d_k + d_v) \cdot 2 \cdot t}

Limiting behavior

Short context (t0t \to 0). Both numerator and denominator approach BweightsB_\text{weights}:

speedupBweightsBweights=1\text{speedup} \to \frac{B_\text{weights}}{B_\text{weights}} = 1

No speedup. The model spends all its time loading weights, which are the same for MHA and GQA.

Long context (tt \to \infty). The BweightsB_\text{weights} term becomes negligible:

speedupLh(dk+dv)2tLg(dk+dv)2t\text{speedup} \to \frac{L \cdot h \cdot (d_k + d_v) \cdot 2 \cdot t}{L \cdot g \cdot (d_k + d_v) \cdot 2 \cdot t}

The LL, (dk+dv)(d_k + d_v), 2, and tt all cancel:

speeduphg\text{speedup} \to \frac{h}{g}

The maximum achievable speedup is exactly h/gh/g — the same as the cache reduction factor.

Numerical verification at every context length

Using our running model (Bweights=72B_\text{weights} = 72 MB, g=2g = 2, h=8h = 8):

At t=512t = 512:

  • BKVMHA=24,576×512=12,582,91212B_\text{KV}^\text{MHA} = 24{,}576 \times 512 = 12{,}582{,}912 \approx 12 MB
  • BKVGQA=6,144×512=3,145,7283B_\text{KV}^\text{GQA} = 6{,}144 \times 512 = 3{,}145{,}728 \approx 3 MB
speedup=72+1272+3=8475=1.12×\text{speedup} = \frac{72 + 12}{72 + 3} = \frac{84}{75} = 1.12\times

At short context, almost no speedup.

At t=2,048t = 2{,}048:

  • BKVMHA=48B_\text{KV}^\text{MHA} = 48 MB
  • BKVGQA=12B_\text{KV}^\text{GQA} = 12 MB
speedup=72+4872+12=12084=1.43×\text{speedup} = \frac{72 + 48}{72 + 12} = \frac{120}{84} = 1.43\times

At t=4,096t = 4{,}096:

  • BKVMHA=96B_\text{KV}^\text{MHA} = 96 MB
  • BKVGQA=24B_\text{KV}^\text{GQA} = 24 MB
speedup=72+9672+24=16896=1.75×\text{speedup} = \frac{72 + 96}{72 + 24} = \frac{168}{96} = 1.75\times

At t=16,384t = 16{,}384:

  • BKVMHA=384B_\text{KV}^\text{MHA} = 384 MB
  • BKVGQA=96B_\text{KV}^\text{GQA} = 96 MB
speedup=72+38472+96=456168=2.71×\text{speedup} = \frac{72 + 384}{72 + 96} = \frac{456}{168} = 2.71\times

At t=128,000t = 128{,}000:

  • BKVMHA=3,000B_\text{KV}^\text{MHA} = 3{,}000 MB
  • BKVGQA=750B_\text{KV}^\text{GQA} = 750 MB
speedup=72+3,00072+750=3,072822=3.74×\text{speedup} = \frac{72 + 3{,}000}{72 + 750} = \frac{3{,}072}{822} = 3.74\times

Approaching the theoretical maximum of h/g=4×h/g = 4\times.

Context ttSpeedup% of theoretical max (4×4\times)
5121.12×1.12\times28%
2,0481.43×1.43\times36%
4,0961.75×1.75\times44%
16,3842.71×2.71\times68%
128,0003.74×3.74\times93%

The speedup grows monotonically with context length, approaching h/gh/g asymptotically. At 128K tokens, we achieve 93% of the theoretical maximum. GQA’s value increases with context length — precisely when inference is most expensive.


Since the GQA paper, modern language models have explored different points on the MHA-GQA-MQA spectrum. We trace a few concrete choices made by major architectures.

LLaMA 2 70B (Meta, 2023): h=64h = 64 query heads, g=8g = 8 KV groups. Cache reduction: 64/8=8×64/8 = 8\times. At dmodel=8,192d_\text{model} = 8{,}192 and L=80L = 80, the MHA cache would be 4×80×8,192=2.54 \times 80 \times 8{,}192 = 2.5 MB/token. With GQA-8: 2.5/8=312.52.5 / 8 = 312.5 KB/token. At 128K tokens: 312.5×128,000=40312.5 \times 128{,}000 = 40 GB instead of 320 GB.

Mistral 7B (Mistral AI, 2023): h=32h = 32 query heads, g=8g = 8 KV groups. Cache reduction: 32/8=4×32/8 = 4\times. Combined with sliding window attention (w=4,096w = 4{,}096), the cache is bounded at g(dk+dv)2Lwg \cdot (d_k + d_v) \cdot 2 \cdot L \cdot w bytes regardless of sequence length. This is Lever 1 (GQA) and Lever 3 (sliding window) composed.

Gemma (Google, 2024): uses different KV-head choices by model size rather than one uniform GQA setting. Gemma 2B uses MQA (num_kv_heads=1\text{num\_kv\_heads} = 1), while Gemma 7B uses full MHA (num_kv_heads=16\text{num\_kv\_heads} = 16). This is a useful reminder that modern models do not all choose the same point on the MHA-GQA-MQA spectrum; the right choice depends on size, quality targets, and serving constraints.

Across these examples, architects are clearly optimizing the same tradeoff between KV-cache size and quality, even when they land on different points of the spectrum. LLaMA 2 70B and Mistral 7B both use GQA, while Gemma spans MQA and MHA across sizes. The broader pattern is that KV-head sharing became a central deployment design choice after GQA made the tradeoff explicit.


The Unified View: MHA, GQA, MQA as One Formula

All three variants — MHA, GQA, and MQA — are a single attention mechanism parameterized by gg:

Attentiong(X)=concat(o1,,oh)WO\boxed{\text{Attention}_{g}(X) = \text{concat}(o^1, \ldots, o^h) \, W_O}

where for query head ii with group index j=ig/hj = \lceil i \cdot g / h \rceil:

Qi=XWQi,Kj=XWKj,Vj=XWVjQ^i = X W_Q^i, \quad K^j = X W_K^j, \quad V^j = X W_V^j oi=softmax ⁣(QiKjdk)Vjo^i = \text{softmax}\!\left(\frac{Q^i {K^j}^\top}{\sqrt{d_k}}\right) V^j

The only thing that varies is gg. Everything else — the query projections, the output projection, the softmax, the scaling — is identical.

ggNameKV headsKV cache per tokenQuery heads per KV head
hhMHAhh uniqueLh(dk+dv)2L \cdot h \cdot (d_k + d_v) \cdot 21
1<g<h1 < g < hGQA-gggg sharedLg(dk+dv)2L \cdot g \cdot (d_k + d_v) \cdot 2h/gh/g
11MQA1 sharedL(dk+dv)2L \cdot (d_k + d_v) \cdot 2hh

There is no structural difference between these three methods. They are the same formula with different values of one integer parameter. GQA is the general family. MHA (g=hg = h) and MQA (g=1g = 1) are boundary cases.

This unified view makes clear that choosing gg is a single design decision with a clean tradeoff: smaller gg → smaller cache → faster inference → potentially lower quality. The engineering challenge is finding the gg that maximizes inference speed while keeping quality within tolerance. The GQA paper showed this gg exists and is easy to find.


Summary

The KV cache during autoregressive inference costs Lh(dk+dv)2L \cdot h \cdot (d_k + d_v) \cdot 2 bytes per token. Multi-Query Attention (MQA) collapses all hh KV heads to 1, reducing the cache by h×h\times at the cost of a measurable quality drop (0.6 points on T5-XXL). Grouped-Query Attention (GQA) generalizes this to gg KV groups, each shared by h/gh/g query heads, reducing the cache by exactly h/gh/g. The GQA paper showed that with g=8g = 8 on T5-XXL, quality is within 0.1 points of full MHA while inference is 5.4×5.4\times faster. Existing MHA checkpoints can be converted to GQA by mean-pooling KV heads within each group and uptraining for just 5% of the original pre-training compute. The inference speedup approaches h/gh/g at long context lengths and is most impactful exactly when inference is most expensive. MHA, GQA, and MQA are not three separate inventions — they are a single formula parameterized by the number of KV groups gg.


Previous: The KV Bottleneck Explained Deeply
Next: Mathematical Prerequisites for DeepSeek-V2

Enjoyed this post?

Subscribe to get notified when I publish new posts. No spam, unsubscribe anytime.