Grouped Query Attention › Converting MHA to GQA
Language AI HandbookAll chapters Grouped Query Attention › Converting MHA to GQAOne section · Sections in this chapter10 / 14 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
What if you have an existing MHA model and want the benefits of GQA? The LLaMA 2 paper describes a conversion process called "uptraining" that adapts pretrained MHA models to use GQA.
The conversion process works as follows:
- Mean pooling: Average the key and value projection weights across the heads that will share a KV representation
- Uptraining: Continue training the converted model on a small fraction (typically 5%) of the original training data
- Validation: Verify quality recovery on held-out benchmarks
def convert_mha_to_gqa(
mha_k_weight: torch.Tensor, # (d_model, num_heads * head_dim)
mha_v_weight: torch.Tensor, # (d_model, num_heads * head_dim)
num_heads: int,
num_kv_groups: int,
) -> tuple:
"""Convert MHA K,V weights to GQA by mean pooling within groups."""
d_model = mha_k_weight.shape[0]
head_dim = mha_k_weight.shape[1] // num_heads
heads_per_group = num_heads // num_kv_groups
# Reshape to (d_model, num_heads, head_dim)
k_reshaped = mha_k_weight.view(d_model, num_heads, head_dim)
v_reshaped = mha_v_weight.view(d_model, num_heads, head_dim)
# Reshape to (d_model, num_kv_groups, heads_per_group, head_dim)
k_grouped = k_reshaped.view(
d_model, num_kv_groups, heads_per_group, head_dim
)
v_grouped = v_reshaped.view(
d_model, num_kv_groups, heads_per_group, head_dim
)
# Mean pool within groups: (d_model, num_kv_groups, head_dim)
gqa_k_weight = k_grouped.mean(dim=2)
gqa_v_weight = v_grouped.mean(dim=2)
# Reshape to (d_model, num_kv_groups * head_dim)
gqa_k_weight = gqa_k_weight.view(d_model, num_kv_groups * head_dim)
gqa_v_weight = gqa_v_weight.view(d_model, num_kv_groups * head_dim)
return gqa_k_weight, gqa_v_weight
# Example conversion
d_model, num_heads, head_dim = 512, 8, 64
num_kv_groups = 2
# Simulate MHA weights
mha_k = torch.randn(d_model, num_heads * head_dim)
mha_v = torch.randn(d_model, num_heads * head_dim)
# Convert to GQA
gqa_k, gqa_v = convert_mha_to_gqa(mha_k, mha_v, num_heads, num_kv_groups)MHA to GQA Weight Conversion ================================================== Original MHA weights: K shape: torch.Size([512, 512]) V shape: torch.Size([512, 512]) Converted GQA weights: K shape: torch.Size([512, 128]) V shape: torch.Size([512, 128]) Parameter reduction: 4x for K,V projections



Mean pooling provides a reasonable initialization, but the converted model typically shows 2-5% quality degradation before uptraining. The uptraining phase allows the model to adapt its query projections to work effectively with the shared key-value representations. Research suggests that 5% of the original training compute is sufficient to recover most of the lost quality.