多头注意力 MHA#
我们在前面展开过:标准 Transformer 使用多头注意力机制,
个注意力头各自拥有独立的 Q、K、V 投影矩阵:

而其中每个头独立学习不同的注意力模式。最终的输出是
个头的拼接:

这本身是为了增加表达能力的合理设置,但 KV Cache 出现后,KV Cache 需要为每个头单独存储一份 K 和 V。这一结构设计带来了较大的内存压力。

  1. 多查询注意力 MQA#
    19 年,Shazeer(就是 SwiGLU 那位)在 Fast Transformer Decoding: One Write-Head is All You Need 提出了一个激进方案,即多查询注意力(Multi-Query Attention,MQA)。

在 MQA 中,
个 Query Head 共享同一组 K 和 V,只有一个 K 头和一个 V 头:

意思是无论有多少个 Query Head,它们查的都是同一份 K 和 V。
这样,KV Cache 的大小瞬间降到 MHA 的
。对于 64 头的模型,直接省了 98.4% 的 KV Cache 内存。

但代价也很明显:不同 Query Head 已经被证明会关注不同模式,把它们绑定到同一份 K、V 上,必然损失表达能力。

实验结果也印证了这一点:MQA 的训练更不稳定,在质量敏感的任务上效果有明显下降。

  1. 分组查询注意力 GQA#
    目前的主流方案来自 23 年的论文 GQA: Training Generalized Multi-Query Transformer for Multi-Head Attention ,它其实更像是前两个方案的折中:


个 Query Head 分成
组,每组共享一个 K 头和一个 V 头。
是一个可调参数。

这其实是把质量与效率的权衡变成了一个连续可调的超参数:你想省多少显存,就设置多少组。

举个例子,假设
,那么其对应关系即如下:

Query Head 使用的 KV Head
Q₀ KV₀
Q₁ KV₀
Q₂ KV₁
Q₃ KV₁
Q₄ KV₂
Q₅ KV₂
Q₆ KV₃
Q₇ KV₃
于是注意力实际上是这样的:

然后,所有组的输出再拼接到一起:

看得出来,GQA 的改动非常小,它只改变了 K 和 V 的投影矩阵列数,简单对比如下:

MHA:


GQA:


GQA 的 K、V 列数从
缩小到
,Q 保持不动。这意味参数量节省了
,同时 KV Cache 也相应缩小。

而从实现角度看,现代框架通常不会真的复制 K、V。而是在进入注意力计算前,先针对头索引
构造一个映射:

然后计算时直接索引:

这样来实现只共享内存,不会真的复制数据。

4a5bce63-6377-4c21-8dee-533d469cd3a1.png

  1. 大模型中的实际配置#
    GQA 在提出之后迅速成为主流方案。如今绝大多数开源大模型都已经放弃传统 MHA,转而采用 GQA 来控制 KV Cache 的规模。

一些代表性开源模型如下:

模型 KV Head Query Head Q:KV
LLaMA 2 70B 8 64 8:1
LLaMA 3 8B 8 32 4:1
LLaMA 3 70B 8 64 8:1
LLaMA 3 405B 8 128 16:1
Mistral 7B 8 32 4:1
Mixtral 8x7B 8 32 4:1
Qwen 2.5 72B 8 64 8:1
Gemma 2 9B 8 16 2:1
值得一提的是: 8 个 KV Head 几乎成为行业默认值。

这是因为对于常见的
个 Query Head 而言,8 个 KV Head 已经能够保留足够丰富的注意力模式,同时又能让 KV Cache 缩小到原来的

左右,这是大量实践下的优解。

不过事情并没有在这里结束,但随着模型规模继续增大,研究者们又有了新发现:

KV Cache 的瓶颈不仅来自 Head 数量,还来自每个 Head 内部庞大的特征维度。

于是 DeepSeek 在 V2 中提出了多头潜在注意力(Multi-head Latent Attention, MLA)。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐