在自回归推理中,每生成一个新 token,都要读取历史 token 的 Key 和 Value。上下文越长、batch 越大,KV Cache 带来的显存占用和内存带宽压力就越明显。
MQA 和 GQA 通过减少完整 KV head 的数量来缓解这个问题;MLA 则进一步改变缓存对象,只保存能够生成多头 K、V 的低维 latent。本文先从 Single-Head Attention、MHA、MQA 和 GQA 的关系出发,再解释 MLA 的低秩压缩、矩阵吸收与解耦 RoPE。
从 Single-Head Attention 到 GQA
Single-Head Attention
从最基础的 Single-Head Attention 计算公式开始,假设输入序列为 X ∈ R n × d X\in \mathbb{R}^{n\times d} X ∈ R n × d ,特征矩阵为 W Q ∈ R d × d q W_Q \in \mathbb{R}^{d\times d_q} W Q ∈ R d × d q 、W K ∈ R d × d k W_K \in \mathbb{R}^{d\times d_k} W K ∈ R d × d k 和 W V ∈ R d × d v W_V \in \mathbb{R}^{d\times d_v} W V ∈ R d × d v 。其中:
n n n 表示序列长度
d d d 表示每个 token 的特征维度
d q d_q d q 、d k d_k d k 、d v d_v d v 分别表示 Q、K、V 的特征维度
为简化后续记号,本文将 Q、K、V 的列维度统一用 d h d_h d h 表示 。
维度记号
根据 Q K T QK^T Q K T 的计算要求,d q d_q d q 和 d k d_k d k 必须一致;而当前主流 LLM 实现通常进一步令 d v = d q = d k d_v=d_q=d_k d v = d q = d k 。因此,本文统一用 d h d_h d h 表示每个头中 Q Q Q 、K K K 、V V V 的列维度。
则 Attention 的计算公式可表示为:
Q = X W Q , K = X W K , V = X W V Q = XW_Q, \quad K = XW_K, \quad V = XW_V Q = X W Q , K = X W K , V = X W V
Attention ( Q , K , V ) = softmax ( Q K T d h ) V \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_h}}\right)V Attention ( Q , K , V ) = softmax ( d h Q K T ) V
然而,对于 Single-Head Attention 来说,Q、K、V 只能在一个子空间中进行注意力计算,这可能限制模型的表达能力。MHA 将这个总宽度切成多个子空间,让不同注意力头学习不同的关系。
MHA:更丰富的表达能力
在 MHA 中,我们把表达空间划分成多个子空间:
Q i = X W Q i , K i = X W K i , V i = X W V i , i = 1 , 2 , … , n h Q_i=XW_{Q_i}, \quad K_i=XW_{K_i}, \quad V_i=XW_{V_i},
\quad i=1,2,\ldots,n_h Q i = X W Q i , K i = X W K i , V i = X W V i , i = 1 , 2 , … , n h
为了与总宽度为 d d d 的 Single-Head Attention 对齐,常见实现令:
n h d h = d , Q = Concat ( Q 1 , … , Q n h ) ∈ R n × d n_h d_h=d,\qquad
Q=\operatorname{Concat}(Q_1,\ldots,Q_{n_h})\in\mathbb{R}^{n\times d} n h d h = d , Q = Concat ( Q 1 , … , Q n h ) ∈ R n × d
K 和 V 同理。也就是说,MHA 不是复制 n h n_h n h 份宽度为 d d d 的 Q、K、V,而是把总宽度 d d d 切成 n h n_h n h 份,每份宽度为 d h d_h d h 。
每个头都有独立的注意力矩阵:
head i = softmax ( Q i K i T d h ) V i \text{head}_i=\text{softmax}\left(\frac{Q_iK_i^T}{\sqrt{d_h}}\right)V_i head i = softmax ( d h Q i K i T ) V i
最终再拼接所有头的输出,并通过一个线性变换得到最终的输出:
Output = Linear ( [ head 1 ; head 2 ; … ; head n h ] ) \text{Output} = \text{Linear}\left(\left[\text{head}_1; \text{head}_2; \ldots; \text{head}_{n_h}\right]\right) Output = Linear ( [ head 1 ; head 2 ; … ; head n h ] )
MHA 通过多个独立的注意力头丰富了不同子空间中的表达能力,但每个头都需要保存自己的 Key 和 Value。由于总宽度仍是 n h d h = d n_h d_h=d n h d h = d ,它并没有减少 KV Cache。
在长上下文场景下,这会带来较大的显存占用与内存带宽压力。为了解决这一问题,作为 KV Cache 优化方案的 Multi-Query Attention(MQA)便被正式提出。
MQA:所有 Query head 共享一组 K、V
在 MQA 中,所有注意力头共享同一组 Key 和 Value:
Q i = X W Q i , K = X W K , V = X W V , i = 1 , 2 , … , n h Q_i=XW_{Q_i}, \quad K=XW_K, \quad V=XW_V,
\quad i=1,2,\ldots,n_h Q i = X W Q i , K = X W K , V = X W V , i = 1 , 2 , … , n h
后续的计算与 MHA 相同,不再赘述。
MQA 让所有 Query head 共享同一组 Key 和 Value,虽然显著降低了 KV Cache,但也可能带来一定的表达能力损失。为在推理效率与模型质量之间取得更好的平衡,Grouped-Query Attention(GQA)被提出。
GQA:MHA 和 MQA 的折中
GQA 在 MQA 的基础上引入了介于 1 和 Query head 数量之间的多个 KV head:每组 Query head 共享一组 K、V。
Q i = X W Q i , K j = X W K j , V j = X W V j , i = 1 , 2 , … , h q , j = 1 , 2 , … , h k Q_i=XW_{Q_i},\quad K_j=XW_{K_j},\quad V_j=XW_{V_j},
\quad i=1,2,\ldots,h_q,\quad j=1,2,\ldots,h_k Q i = X W Q i , K j = X W K j , V j = X W V j , i = 1 , 2 , … , h q , j = 1 , 2 , … , h k
其中,h q h_q h q 表示 Query head 的数量,h k h_k h k 表示 Key/Value head 的数量。GQA 中通常满足:
h q = g h k h_q = g h_k h q = g h k
其中,g = h q h k g=\frac{h_q}{h_k} g = h k h q 表示每个 Key/Value head 对应的 Query head 数量。也就是说:
Q ( j − 1 ) g + 1 , … , Q j g 共享 K j , V j Q_{(j-1)g+1},\ldots,Q_{jg}
\quad\text{共享}\quad
K_j,V_j Q ( j − 1 ) g + 1 , … , Q j g 共享 K j , V j
在这个统一表示下,MQA 与 MHA 都是 GQA 的边界情况 。
边界情况
在统一的表示下,MQA 可以看作 GQA 在 h k = 1 h_k=1 h k = 1 时的特例,而 MHA 则对应 h k = h q h_k=h_q h k = h q 的情况。
KV head 数量如何决定缓存量
具体而言,Single-Head Attention、MHA、MQA 与 GQA 的 Q、K、V 关系如下图所示:
Single-Head Attention、MHA、MQA 与 GQA 的 Q、K、V 关系。结构参考并改绘自 Ray, “Learn and Code MHA, MQA, and GQA” 。
从 MHA 到 MQA、GQA,优化 KV Cache 的方式都是减少需要保存的 KV head 数量:MHA 为每个 Query head 保留一组独立的 K、V,MQA 让所有 Query head 共享一组 K、V,而 GQA 则介于两者之间。
对于长度为 n n n 的序列,统一记 KV head 数量为 h k h_k h k ,则每层需要缓存的元素数量为:
N K V = 2 n h k d h N_{\mathrm{KV}}=2n h_k d_h N KV = 2 n h k d h
因此,MHA 对应 h k = h q h_k=h_q h k = h q ,MQA 对应 h k = 1 h_k=1 h k = 1 ,GQA 则取 1 < h k < h q 1<h_k<h_q 1 < h k < h q 。
需要注意的是,KV Cache 保存的不是权重矩阵 W K W_K W K 和 W V W_V W V ,而是每一层为历史 token 计算出的 Key 和 Value。接下来讨论的缓存量,都以这些中间结果所包含的元素数量为准。
MLA:进一步压缩 KV Cache
MQA 和 GQA 通过共享完整的 K、V 来减少缓存,但共享程度越高,越可能限制不同注意力头的表达能力。DeepSeek 团队在《DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model 》中提出了另一种思路:不再继续减少 KV head 的数量,而是把所有头的 Key 和 Value 联合压缩到一个低维 latent 中。这就是多头潜在注意力机制(Multi-Head Latent Attention,MLA)。
MLA 的基本思路
先看 MHA 需要缓存什么。设第 t t t 个 token 在当前注意力层的输入为 h t ∈ R 1 × d h_t\in\mathbb{R}^{1\times d} h t ∈ R 1 × d ,共有 n h n_h n h 个注意力头,每个头的维度为 d h d_h d h 。所有头拼接后的总宽度为 n h d h n_h d_h n h d h ;在常见的 MHA 实现中它通常等于 d d d ,但这并不是数学上的必要条件。该 token 的 Key 和 Value 分别为:
k t = Concat ( k t , 1 , … , k t , n h ) , v t = Concat ( v t , 1 , … , v t , n h ) k_t=\operatorname{Concat}(k_{t,1},\ldots,k_{t,n_h}),\qquad
v_t=\operatorname{Concat}(v_{t,1},\ldots,v_{t,n_h}) k t = Concat ( k t , 1 , … , k t , n h ) , v t = Concat ( v t , 1 , … , v t , n h )
其中 k t , v t ∈ R 1 × n h d h k_t,v_t\in\mathbb{R}^{1\times n_h d_h} k t , v t ∈ R 1 × n h d h 。因此,对于长度为 n n n 的序列,MHA 每层需要缓存的元素数量为:
N M H A = 2 n n h d h N_{\mathrm{MHA}}=2n\,n_h d_h N MHA = 2 n n h d h
MLA 不再直接保存这些完整的 Key 和 Value,而是先把 h t h_t h t 下投影为一个共享的 KV latent:
c t K V = h t W D K V , W D K V ∈ R d × d c , c t K V ∈ R 1 × d c c_t^{KV}=h_tW^{DKV},\qquad
W^{DKV}\in\mathbb{R}^{d\times d_c},\qquad
c_t^{KV}\in\mathbb{R}^{1\times d_c} c t K V = h t W D K V , W D K V ∈ R d × d c , c t K V ∈ R 1 × d c
然后,每个注意力头再通过各自的上投影,从同一个 c t K V c_t^{KV} c t K V 中得到所需的 Key 和 Value:
k t , i C = c t K V W i U K , v t , i C = c t K V W i U V , i = 1 , 2 , … , n h k_{t,i}^{C}=c_t^{KV}W_i^{UK},\qquad
v_{t,i}^{C}=c_t^{KV}W_i^{UV},
\qquad i=1,2,\ldots,n_h k t , i C = c t K V W i U K , v t , i C = c t K V W i U V , i = 1 , 2 , … , n h
其中 W i U K , W i U V ∈ R d c × d h W_i^{UK},W_i^{UV}\in\mathbb{R}^{d_c\times d_h} W i U K , W i U V ∈ R d c × d h 。虽然所有头共享同一个 latent,但每个头仍然拥有独立的上投影,因此 MLA 并不等同于让所有头直接共享同一组完整的 K、V。
从整个序列看,令 C K V ∈ R n × d c C^{KV}\in\mathbb{R}^{n\times d_c} C K V ∈ R n × d c 表示所有 token 的 KV latent,并将各头的上投影矩阵横向拼接为 W U K W^{UK} W U K 和 W U V W^{UV} W U V ,则:
K C = C K V W U K , V C = C K V W U V , rank ( K C ) , rank ( V C ) ≤ d c K^C=C^{KV}W^{UK},\qquad V^C=C^{KV}W^{UV},\qquad
\operatorname{rank}(K^C),\operatorname{rank}(V^C)\le d_c K C = C K V W U K , V C = C K V W U V , rank ( K C ) , rank ( V C ) ≤ d c
也就是说,MLA 假设所有头的内容 K、V 都可以由同一个低维 latent 表示生成。这是模型训练时学习到的低秩约束,并不是对任意 MHA K、V 的无损压缩。
这里的压缩关系是:
d c ≪ n h d h d_c\ll n_h d_h d c ≪ n h d h
d c d_c d c 比较的是所有注意力头拼接后的宽度 n h d h n_h d_h n h d h ,而不是单个头的宽度 d h d_h d h 。事实上,DeepSeek-V2 设置的是 d c = 4 d h d_c=4d_h d c = 4 d h ;它依然远小于所有头拼接后的总宽度。
MHA 直接缓存每个 head 的完整 K、V;MLA 在内容分支中只缓存共享的 dc 维 KV latent,并通过 nh 组上投影在概念上还原各头 K、V。图中不包含后续单独讨论的 RoPE 位置分支。
为什么只需要缓存 KV latent?
由上面的上投影关系可知,保存 c j K V c_j^{KV} c j K V 足以恢复 MLA 自身生成的内容 K、V。MLA 的关键并不是无法恢复这些 K、V,而是推理时不必真的把它们恢复出来。采用解耦 RoPE 时,位置分支的 Key 还需要单独缓存,后文再讨论。
如何通过结合律避免恢复完整 K/V?
继续只看内容分支。对于第 i i i 个头,有:
K i C = C K V W i U K , V i C = C K V W i U V K_i^{C}=C^{KV}W_i^{UK},\qquad
V_i^{C}=C^{KV}W_i^{UV} K i C = C K V W i U K , V i C = C K V W i U V
整个序列的 内容 Query Q i C Q_i^C Q i C 与 Key 的分数矩阵可以重新结合为:
Query 低秩投影
DeepSeek-V2 还对 Query 使用低秩投影:C Q = X W D Q C^Q=XW^{DQ} C Q = X W D Q 、Q C = C Q W U Q Q^C=C^QW^{UQ} Q C = C Q W U Q 。这主要用于减少训练时的激活内存,并不会进一步减少推理时的 KV Cache。
Q i C ( K i C ) T = ( Q i C ( W i U K ) T ) ( C K V ) T Q_i^{C}(K_i^{C})^T
=\left(Q_i^{C}(W_i^{UK})^T\right)(C^{KV})^T Q i C ( K i C ) T = ( Q i C ( W i U K ) T ) ( C K V ) T
因此,W i U K W_i^{UK} W i U K 可以预先并入 Query 一侧的投影,计算注意力分数时直接读取 C K V C^{KV} C K V ,不必显式恢复完整的 Key。
记 A i ∈ R n × n A_i\in\mathbb{R}^{n\times n} A i ∈ R n × n 为第 i i i 个头经过 Softmax 和因果掩码后的注意力矩阵。标准 Value 路径为:
H i = A i V i C ⟹ H i = A i C K V W i U V H_i=A_iV_i^{C}
\quad\Longrightarrow\quad
H_i=A_iC^{KV}W_i^{UV} H i = A i V i C ⟹ H i = A i C K V W i U V
令
W b l k U V = BlockDiag ( W 1 U V , … , W n h U V ) , W O ′ = W b l k U V W O W^{UV}_{\mathrm{blk}}
=\operatorname{BlockDiag}
\left(W_1^{UV},\ldots,W_{n_h}^{UV}\right),
\qquad
W'_O=W^{UV}_{\mathrm{blk}}W_O W blk U V = BlockDiag ( W 1 U V , … , W n h U V ) , W O ′ = W blk U V W O
则所有注意力头的输出可以写成:
O = Concat ( A 1 C K V , … , A n h C K V ) W O ′ O
=\operatorname{Concat}
\left(A_1C^{KV},\ldots,A_{n_h}C^{KV}\right)W'_O O = Concat ( A 1 C K V , … , A n h C K V ) W O ′
因此,W i U V W_i^{UV} W i U V 可以预先与 W O W_O W O 合并;运行时只需对缓存的 C K V C^{KV} C K V 做注意力加权聚合,无需显式恢复完整的 Value。
解耦 RoPE:单独保留位置信息
RoPE(Rotary Position Embedding)通过位置相关的旋转矩阵,将位置信息注入 Query 和 Key。对于位置 t t t 的 Query 与位置 j j j 的 Key,可简写为:
q ^ t = q t R t , k ^ j = k j R j \widehat q_t=q_tR_t,\qquad \widehat k_j=k_jR_j q t = q t R t , k j = k j R j
其中 R t R_t R t 和 R j R_j R j 分别表示对应位置的旋转矩阵。内积 q ^ t k ^ j T \widehat q_t\widehat k_j^T q t k j T 中包含 R t R j T R_tR_j^T R t R j T ,因此能够体现 token 之间的相对位置关系。
如果直接对 MLA 的内容 Key 使用 RoPE,注意力分数应为:
s t j i f u l l = ( q t , i C R t ) ( c j K V W i U K R j ) T = q t , i C R t R j T ( W i U K ) T ( c j K V ) T s_{tji}^{\mathrm{full}}
=\left(q_{t,i}^{C}R_t\right)
\left(c_j^{KV}W_i^{UK}R_j\right)^T
=q_{t,i}^{C}R_tR_j^T(W_i^{UK})^T(c_j^{KV})^T s t j i full = ( q t , i C R t ) ( c j K V W i U K R j ) T = q t , i C R t R j T ( W i U K ) T ( c j K V ) T
这种写法保留了完整内容 Key 的 RoPE,但 R j R_j R j 随历史位置 j j j 变化,使 Query 侧的变换也依赖 j j j 。因此,W i U K W_i^{UK} W i U K 无法预先吸收到一个与历史位置无关的 Query 投影中。DeepSeek 在 MLA 中做出的取舍是:不再对内容分支的 Key 直接使用 RoPE,而是增加一条独立的位置分支:
q t , i = Concat ( q t , i C , q t , i R ) , k j , i = Concat ( k j , i C , k j R ) q_{t,i}=\operatorname{Concat}(q_{t,i}^{C},q_{t,i}^{R}),\qquad
k_{j,i}=\operatorname{Concat}(k_{j,i}^{C},k_{j}^{R}) q t , i = Concat ( q t , i C , q t , i R ) , k j , i = Concat ( k j , i C , k j R )
其中 q t , i R , k j R ∈ R 1 × d h R q_{t,i}^{R},k_j^{R}\in\mathbb{R}^{1\times d_h^R} q t , i R , k j R ∈ R 1 × d h R 使用 RoPE,k j R k_j^{R} k j R 由所有注意力头共享。因此,注意力分数可以拆成内容相似度与位置相似度两部分:
q t , i k j , i T = q t , i C ( k j , i C ) T + q t , i R ( k j R ) T q_{t,i}k_{j,i}^{T}
=q_{t,i}^{C}(k_{j,i}^{C})^{T}
+q_{t,i}^{R}(k_j^{R})^{T} q t , i k j , i T = q t , i C ( k j , i C ) T + q t , i R ( k j R ) T
将各位置的 q t , i q_{t,i} q t , i 和 k j , i k_{j,i} k j , i 沿序列维度堆叠为 Q i Q_i Q i 和 K i K_i K i ,最终的注意力矩阵为:
A i = softmax ( Q i K i T d h + d h R + M ) A_i=\operatorname{softmax}\left(
\frac{Q_iK_i^T}{\sqrt{d_h+d_h^R}}+M
\right) A i = softmax d h + d h R Q i K i T + M
其中 M M M 是因果掩码。这就是前文 Value 路径中使用的 A i A_i A i :解耦 RoPE 改变了注意力权重的生成方式,但不影响 Value 侧的矩阵吸收。
这并不是对 s t j i f u l l s_{tji}^{\mathrm{full}} s t j i full 的等价展开,而是 MLA 的结构性取舍:内容分支不使用 RoPE,以保留 latent 缓存和矩阵吸收优化;位置分支单独承担位置建模,并额外缓存 k j R k_j^{R} k j R 。这就是“解耦 RoPE”的含义。
MLA 的 KV Cache 节省效果
以 DeepSeek-V2 的配置为例:
n h = 128 , d h = 128 , d c = 512 = 4 d h , d h R = 64 n_h=128,\qquad d_h=128,\qquad d_c=512=4d_h,\qquad d_h^R=64 n h = 128 , d h = 128 , d c = 512 = 4 d h , d h R = 64
MHA 每个 token、每层需要缓存完整的多头 Key 和 Value:
N M H A = 2 n h d h = 2 × 128 × 128 = 32768 N_{\mathrm{MHA}}=2n_h d_h
=2\times128\times128=32768 N MHA = 2 n h d h = 2 × 128 × 128 = 32768
MLA 需要缓存 KV latent 和解耦 RoPE 的位置 Key:
N M L A = d c + d h R = 512 + 64 = 576 N_{\mathrm{MLA}}=d_c+d_h^R
=512+64=576 N MLA = d c + d h R = 512 + 64 = 576
因此,MLA 的缓存量约为 MHA 的:
N M L A N M H A = 576 32768 ≈ 1.76 % \frac{N_{\mathrm{MLA}}}{N_{\mathrm{MHA}}}
=\frac{576}{32768}\approx1.76\% N MHA N MLA = 32768 576 ≈ 1.76%
也就是说,在这一配置下,理论缓存量约减少 98.24 % 98.24\% 98.24% 。论文中的实际模型对比如下:
模型规模 MHA KV Cache MLA KV Cache 减少比例 小型 MoE 110.6 K 110.6\mathrm{K} 110.6 K 15.6 K 15.6\mathrm{K} 15.6 K 85.9 % 85.9\% 85.9% 大型 MoE 860.2 K 860.2\mathrm{K} 860.2 K 34.6 K 34.6\mathrm{K} 34.6 K 96.0 % 96.0\% 96.0%
此外,相比 DeepSeek 67B,DeepSeek-V2 的整体 KV Cache 减少了 93.3 % 93.3\% 93.3% 。
小结
MHA、MQA、GQA 与 MLA 解决的是同一个 KV Cache 问题,但路径不同:MQA/GQA 减少完整 KV head 的数量,MLA 则改变缓存对象 ,把所有头的内容 K、V 联合压缩到共享的 KV latent 中。
在 MLA 内部,c j K V c_j^{KV} c j K V 足以生成模型自身的内容 K、V;推理时再利用矩阵乘法的结合律,把 W U K W^{UK} W U K 吸收到 Query 侧、把 W U V W^{UV} W U V 吸收到输出投影侧,从而避免显式恢复完整 K、V。解耦 RoPE 则用一条额外的位置分支换取这些吸收关系,最终每个 token、每层只需缓存 d c + d h R d_c+d_h^R d c + d h R 个元素。
参考资料
MHA · Ashish Vaswani, Noam Shazeer, Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N. Gomez, Łukasz Kaiser, and Illia Polosukhin. 2017. Attention Is All You Need . arXiv:1706.03762.
MQA · Noam Shazeer. 2019. Fast Transformer Decoding: One Write-Head is All You Need . arXiv:1911.02150.
GQA · Joshua Ainslie, James Lee-Thorp, Michiel de Jong, Yury Zemlyanskiy, Federico Lebrón, and Sumit Sanghai. 2023. GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints . arXiv:2305.13245.
MLA · DeepSeek-AI et al. 2024. DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model . arXiv:2405.04434.
引用博客 · Ray. 2025. Learn and Code MHA, MQA, and GQA: A Guide to Efficient Attention Mechanisms in Transformers . Medium, February 7, 2025.