01 · 每个头都存一份历史,长上下文会发生什么
一个Attention头用自己的查询Q给历史Key打分,再按Softmax权重汇总Value。多个头可以学习不同关注方式。在普通MHA中,查询头和KV头通常一一对应;每个历史token要保存所有KV头的Key和Value。
自回归生成会不断追加历史。即使本轮只有一个新token,也要读取该层允许访问的历史KV。结构优化问的是“需要长期保存几份、什么形式的KV”,它与FlashAttention减少中间分数读写、分页KV安排存储位置是不同问题。
依据:Fast Transformer Decoding · MQA原始论文 ↗ · GQA · 原始论文与检查点转换训练 ↗
03 · 先算容量,不先猜加速比
简化假设:每请求历史N=4096,层数L=32,查询头Hq=32,K/V每头维度d=128,缓存每元素2B。MHA/GQA/MQA的原始KV字节为N×L×Hkv×(dK+dV)×字节数。这里不含分页余量、尺度、工作区和多设备复制。
| 结构参数 | 单请求原始缓存 | 相对MHA |
|---|---|---|
| MHA,Hkv=32 | 2048 MiB | 1 |
| GQA,Hkv=8 | 512 MiB | 1/4 |
| MQA,Hkv=1 | 64 MiB | 1/32 |
| MLA教学配置,dc=512、dR=64 | 144 MiB | 仅作存储账本对照 |
历史变长,各种KV表示要存多少?
查看32个查询头的共享映射
MLA这一行按潜在维度与独立位置Key计数,使用不同的结构参数;不是同质量、同参数量或同Attention得分维度的控制实验。容量减少可能允许更大batch,但不保证单请求延迟按同倍率降低。
张量并行时,KV头可能被分片,也可能因头数少而复制。不能直接把全模型缓存除以卡数,就宣称每卡实际占用。共享组、通信路径和后端布局都要核对。
04 · MLA:保存一个共同的潜在表示
潜在表示可以理解为一个较短、经过训练的特征向量c。MLA从当前隐藏向量生成c,多个头用各自的升维矩阵从c得到内容Key和Value。因此,历史上不必长期保存每头展开后的全部内容K/V。
列向量记法:
c_j = Wdown * hidden_j
k_content[h,j] = UK[h] * c_j
v[h,j] = UV[h] * c_j
# 每个历史位置j存c_j;UK/UV是全层共享的模型参数,不随历史增长。这不是把任意MHA的KV无损压成一个短向量的通用工具。低秩结构是模型定义的一部分,需要相应训练或适配;潜在维度约束了表达形式。模型结构变化与同一MLA模型内部的等价执行重组,应分开理解。
05 · 如果每次再展开全部KV,省存储却可能多算
只存c,然后每轮Decode把整段历史展开成所有头的K/V,虽能减少常驻缓存,却增加升维和临时存储。MLA可用矩阵乘法结合律改变执行位置,使历史一直以c参与主要内容计算。
内容得分:qᵀ (UK c_j) = (UKᵀ q)ᵀ c_j
先给当前查询算q_latent = UKᵀ q,再对历史c_j打分。
Value汇总:Σ_j p_j (UV c_j) = UV (Σ_j p_j c_j)
先加权汇总短向量,再对汇总结果升维。
# 各查询头的p_j仍独立;不能先把不同头的结果随意相加。自设UK=[[1,2],[0,1]]、q=[2,3]、c=[1,2]。展开Key为[5,2],q点积为16;吸收后的查询UKᵀq=[2,7],与c点积也为16。这验证同一组矩阵的代数重排,不验证把一个已有MHA换成MLA的质量。
真实实现还要比较潜在Attention维度、输出升维、Prefill大矩阵效率和工作区。最省缓存的Decode路径未必也是Prefill最快的路径。
06 · RoPE为什么需要单独处理
RoPE按位置旋转查询和Key,用来表达相对位置。若把位置相关旋转夹在内容升维与点积之间,不能随意与升维矩阵交换;因此不能照搬上面的固定矩阵吸收。
DeepSeek-V2的MLA把内容分支与位置分支拆开:内容得分使用潜在缓存,位置得分使用独立的RoPE查询和共享位置Key。历史需要保存c以及位置Key kR;“MLA只存c”忽略了这部分。
score[h,j] = (q_latent[h] · c_j + q_rope[h] · k_rope[j]) / scale
prob[h] = softmax(score[h])
latent_output[h] = Σ_j prob[h,j] * c_j
output[h] = UV[h] * latent_output[h]
# scale、投影、归一化与RoPE配置必须沿用具体模型。公式采用教学简写;在DeepSeek-V2定义中,缩放涉及内容和位置得分维度。不能因实现中查询变成潜在维度,就自行把原缩放改成sqrt(dc)。
07 · 先用小例子验证共享和吸收
下载脚本比较共享KV与显式复制KV的输出,再比较简化MLA的展开路径和吸收路径。MLA例子包含一个独立旋转的位置分支,检查得分和输出一致;省略真实模型中的Norm、查询低秩投影和最终多头输出投影,不模拟设备内核。
读取模型配置:查询头、KV头、头维度或潜在维度
确认权重结构与KV格式匹配
建立原生模型输出基线
验证共享头映射、位置与吸收路径
分别测Prefill和Decode、峰值缓存与临时缓冲
训练/转换后的模型另做质量评测GQA论文给出从MHA检查点转换并继续训练的路线;这说明结构转换不是无代价开关。研究硬件接口时,也要确认后端实际支持GQA或MLA路径,避免隐式展开后只看输入张量大小。
依据:GQA · 原始论文与检查点转换训练 ↗ · PyTorch · SDPA 后端与约束(main) ↗ · vLLM Ascend · 支持功能矩阵(main) ↗
08 · 结构质量和内核等价,分开验收
| 比较对象 | 需要的证据 |
|---|---|
| 同一GQA/MLA模型,不同执行路径 | 输出误差、位置/head映射、mask、量化尺度与布局。 |
| MHA转换为GQA/MLA等结构 | 适配/训练成本、任务质量、长上下文表现。 |
| 系统容量 | 有效KV、分页余量、复制、临时展开和workspace峰值。 |
| 实际速度 | 相同负载与资源,分别记录Prefill、Decode、吞吐和延迟。 |
- 为什么Q0/Q1共享K/V,却不必产生相同输出?
- 把GQA历史KV复制到每个查询头,会怎样影响存储收益?
- MLA的位置Key为什么也要算入缓存?
流程位置与关联方法
这个方法可能出现在多个位置;计算线包含模型计算与算子实现,执行线包含运行时、内存和通信。
资料与核查范围
原理依据以原始论文和官方文档为主;算例与时间线是教学推导。文档核查日期:2026-10-10。引用 main / latest 文档时,实际接口以安装版本为准。
- Fast Transformer Decoding · MQA原始论文 ↗
- GQA · 原始论文与检查点转换训练 ↗
- DeepSeek-V2 · MLA结构、矩阵吸收与解耦RoPE ↗
- PyTorch · SDPA 后端与约束(main) ↗
- vLLM Ascend · 支持功能矩阵(main) ↗
代码为接入片段或教学伪代码;本页没有声称完成 NVIDIA / 昇腾硬件实测。