Skip to content

Grouped-query and latent attention

Cutting the cache without cutting quality

Chapter 11 of 21 · III. Fast attention and inference · about 35 minutes. Builds on: 8. Position and rotary embeddings, 10. Generating text: the KV cache and inference cost.

Chapter 10 showed that the cache size is 2 × layers × KV heads × head size per token. Standard multi-head attention (MHA) has as many key/value heads as query heads. Reducing that number cuts memory and the bytes streamed each decode step.

Multi-query attention (MQA) keeps all query heads but shares a single key head and a single value head across them. The cache shrinks by the number of heads, with some quality loss. Grouped-query attention (GQA) interpolates: partition the hh query heads into gg groups, and give each group one key/value head. g=hg = h is MHA, g=1g = 1 is MQA. The paper also shows an existing MHA model can be converted by averaging the heads in each group and then training briefly.

GQA is the default in current dense models: Llama 3 uses 8 key/value heads at all three sizes , and gpt-oss-120b has 64 query heads sharing 8 key/value heads .

DeepSeek-V2 took a different route: keep distinct keys and values for every head, but compress them. Each token’s hidden state hh is projected down to a small latent vector cc, and keys and values are reconstructed from it by up-projection matrices:

c=WDKV hkC=WUK c,vC=WUV cqC=WUQ cq,cq=WDQ h\begin{aligned} c&=W_{DKV}\,h\\ k_C&=W_{UK}\,c,\qquad v_C=W_{UV}\,c\\ q_C&=W_{UQ}\,c_q,\qquad c_q=W_{DQ}\,h \end{aligned}

Here cc has dcd_c numbers and is what gets cached; kCk_C and vCv_C are the content keys and values for all heads, computed from cc; queries are compressed too.

In DeepSeek-V3, hh has 7,168 numbers, cc has dc=512d_c = 512, there are 128 heads with 128-dimensional content keys and values, and queries are compressed to 1,536 . Per token and layer, MLA caches 512 + 64 numbers (the 64 are the rotary key below), against 128×(192+128)=40,960128\times(192+128)=40{,}960 for a plain multi-head design with the same head sizes. The DeepSeek-V2 paper tabulates cache elements per token and layer as: MHA 2nhdh2n_hd_h, GQA 2ngdh2n_gd_h, MQA 2dh2d_h, and MLA dc+dhR≈4.5 dhd_c+d_h^{R}\approx4.5\,d_h, and reports MLA performing better than MHA in its ablations.

Rebuilding every cached key from its latent at every step would waste the saving. But the content part of a score is

qC⋅kC=qC⋅(WUK c)=(WUK⊤qC)⋅cq_C\cdot k_C=q_C\cdot\bigl(W_{UK}\,c\bigr)=\bigl(W_{UK}^{\top}q_C\bigr)\cdot c

so WUKW_{UK} can be folded into the query: compute q′=WUK⊤qCq' = W_{UK}^{\top}q_C once for the new token, and take dot products directly against the cached latents. The same works on the value side: ∑jaj⋅(WUV⋅cj)=WUV⋅(∑jaj⋅cj)\sum _{j}a_{j}\cdot (W_{UV}\cdot c_{j}) = W_{UV}\cdot (\sum _{j} a_{j}\cdot c_{j}), and WUVW_{UV} can then be merged into the output matrix WOW_O. Full-size keys and values never have to be materialized. Verify numerically, then watch what happens when position information enters:

RoPE (Chapter 8) rotates the key by an angle that depends on its position nn. If it is applied to the expanded key, the score becomes qC⊤⋅R(n−m)⋅WUK⋅cq_C^{\top} \cdot R(n-m) \cdot W_{UK} \cdot c. The position-dependent matrix RR now sits between qCq_C and WUKW_{UK}, so WUKW_{UK} can’t be folded into a fixed query; each cached token would need its own folded query, and the savings disappear (the second table in the widget shows the different folded queries). DeepSeek’s solution is decoupled RoPE: add a small extra query and key, qRq_{R} = RoPE(WQRcqW_{QR}c_{q}) per head and kRk_{R} = RoPE(WKRhW_{KR}h) shared by all heads, of dimension 64 in V3. The final per-head query and key are the concatenations [qCq_{C}; qRq_{R}] and [kCk_{C}; kRk_{R}], so a score is the sum of a position-free content term (absorbable) and a position-aware term (cheap, small). Scores are scaled by 1/128+641 / \sqrt{128 + 64}. Only cc and kRk_{R} are cached.

DesignCache per token per layerUsed by
Multi-head2 · heads · head dimoriginal transformer
Multi-query2 · head dimfast-decoding models
Grouped-query2 · groups · head dimLlama 3, gpt-oss
Latent (MLA)dc+dRd_c+d_R (512 + 64 in V3)DeepSeek-V2, V3, V3.2; Kimi Linear’s full-attention layers

For the numbers in context, open the KV-cache calculator in Chapter 10 and switch between the three presets: 128 KiB per token for Llama 3 8B, about 70 KB per token for DeepSeek-V3.

For 32 query heads and 8 KV heads, by what factor does GQA shrink the cache versus MHA?

4×.

What would break if RoPE were applied directly to the expanded keys in MLA?

The rotation matrix, which depends on position, would sit between the query and WUKW_{UK}, preventing WUKW_{UK} from being absorbed into a single fixed folded query; keys would have to be re-expanded for every cached token at every step.

Which matrices does the MLA absorption trick fold together?

WUKW_{UK} into the query side (WUK⊤qW_{UK}^{\top}q) and WUVW_{UV} into the output projection WOW_O.

  • Multi-query attention.
  • Grouped-query attention.
  • MLA: section 2.1 and its appendix on absorption.
  • The V3 dimensions used above.