想象你正在组织一场班级聚会,规则是:每个人必须和到场的每一位同学单独聊一遍天,确认对方是不是自己需要找的人。10 个人,90 次对话就能结束;100 个人,要聊 9900 次;1000 个人,接近 100 万次——聚会还没开始,时间就爆炸了。这就是 Transformer 模型读长文章时的困境:每个词都要“看一眼”所有词,词一多,开销呈平方级上涨。 聪明的组织者开始改良规则:与其和所有人聊,不如只和“班委”与“同桌”聊天(稀疏注意力);或者干脆只和前后几个人说话,靠大家层层传话覆盖全场(滑动窗口);还可以全班共用一位“速记员”记录所有人的谈话重点(MQA),或者每组配一位速记员、各自记录本组要点(GQA)。这些改进统称为 Transformer 的架构改进,它们只有一个共同目标:在尽量不损伤沟通质量的前提下,让聚会的规模更大、效率更高。
理解这些架构改进,是 AI 工程师在实际训练和部署大模型时做资源分配与方案选型的基本功,也是推理优化面试的高频考点。
目录
可视化演示
本节配有交互动效(进入视口后自动加载,约 3KB)。
1. 注意力瓶颈
聚会规模还小的时候,“每个人和所有人聊一遍”的规则很温馨——信息最全,谁都不会被冷落。可当人数从几十涨到几千,这个规则就成了灾难:每个人要发出几千次对话请求,总对话次数按人数的平方爆炸式增长。Transformer 的标准注意力机制恰好就是这样一种“全聊”规则:每个词都要计算与所有词的关系,文章越长,代价越高。
在技术世界里,这个代价被写成一个公式。假设一篇文章有 \(n\) 个词,每个词用长度为 \(d\) 的向量表示,那么标准注意力需要做的计算量大约正比于 \(n^2 \times d\)。为什么是平方?因为每个词都要和其余 \(n\) 个词逐一配对打分,n 个词就有 \(n^2\) 个配对。维度 \(d\) 只是给每次配对打分时的工作量。
更麻烦的是内存:计算过程中需要把 \(n^2\) 个打分结果全部存下来。文章从 1 千词涨到 1 万词,光是这份“打分表”就要膨胀 100 倍。显存被占满后,模型要么跑不动,要么只能缩短输入,长序列建模便无从谈起。
回到聚会:如果一场聚会注定要到场几千人,“全员两两聊天”的原始规则一定撑不住。要想把聚会办下去,必须修改聊天的规则——这正是后面所有改进方案的出发点。
- 序列长度 \(n\)一句话或一篇文章切分出的词元个数,相当于聚会参与人数。
- 配对数量 \(n^2\)每个词要和所有词各算一次相关性,相当于每两个同学之间都要单独聊一次。
- 向量维度 \(d\)每个词用多少个数来描述语义,相当于每次聊天的“话题数量”。
- 复杂度记号 \(O(\cdot)\)表示开销随规模的“增长趋势”。\(O(n^2)\) 意味着规模翻倍、开销翻四倍。
2. 标准注意力回顾
在改良规则之前,先弄明白原始的“全员聊天”到底在聊什么。班级聚会里,每位同学见面时会带着三样东西:自己要找的人的特征(称为查询 Q)、自己身上贴着的标签(称为键 K)、以及自己真正想说的内容(称为值 V)。两个人是否投缘,由 Q 和 K 的匹配程度决定;聊完之后带走多少信息,则由 V 决定。
Transformer 的注意力机制把这套流程数学化了。第一步,把 A 的 Q 与 B 的 K 做点积,得到一个相似度分数,代表“你们两个有多相关”。第二步,把所有分数除以 \(\sqrt{d}\) 做缩放,再经过 softmax 归一化成一组和为 1 的权重——就像把“好感度”换算成“我该花多少比例的时间听你说话”。第三步,用这些权重对所有人的 V 做加权平均,得到融合后的新表示。
这个“全员聊天”机制是后续所有改进的基线。它的优点是一视同仁、信息无损,缺点是开销太大——接下来的每一种改进,本质上都是在“砍掉不必要的聊天”。
- 查询矩阵 \(Q\)每个词作为“提问者”时携带的信息,相当于聚会中“我想找什么样的人”。
- 匹配度 \(QK^{\mathsf{T}}\)问答双方的键值做点积,算出相似度分数矩阵。
- 缩放因子 \(\sqrt{d}\)维度越大点积数值越大,除以 \(\sqrt{d}\) 防止 softmax 进入饱和区导致梯度消失。
- 归一化 \(\mathrm{softmax}\)把每行的分数压成总和为 1 的权重分布。
- 加权汇聚 \(V\)按权重混合所有词的内容,得到每个词的输出向量。
3. 稀疏注意力
有经验的组织者很快发现:聚会上真正值得深聊的人并不多。大多数人只需要和两类人说话就够了——“班委”(少数全局重要的关键角色)和“同桌”(位置邻近的人)。于是他们制作了一份“通讯录名单”:名单上列了每个同学允许和谁聊天,名单外的一律免谈。这份名单,在数学上就叫掩码矩阵(Mask)。
稀疏注意力就是在标准注意力的打分矩阵上,套一个掩码。掩码中为 1 的位置允许计算注意力,为 0 的位置直接屏蔽。这样,原本 \(n^2\) 个配对中,只有少数位置需要真正计算,其余都被跳过,计算量随之大幅下降。
稀疏模式通常是结构化的:一部分 token 与全局固定的少数 token 相连(相当于认识班委),一部分与局部邻域相连(相当于认识同桌),还有一部分按固定规律做随机采样(相当于随缘认识几个新朋友)。这三种模式组合起来,就是经典的“全局 + 局部 + 随机”稀疏注意力。
回到聚会:有了“通讯录名单”,每个人只需要和自己名单上的人聊天,对话总数立刻从“全员互聊”降为“重点社交”。只要名单设计得合理,该聊的重要人物一个都没落下,聚会质量几乎不受影响。
- 掩码矩阵 \(M\)与分数矩阵同尺寸,元素为 0 或 1,1 表示允许关注、0 表示禁止关注。
- 逐元素相乘 \(\odot\)把分数矩阵与掩码对应位置相乘,被划掉的位置变为负无穷大,softmax 后权重即归零。
- 稀疏归一化softmax 只在掩码允许的位置上分配权重,其他位置权重为 0。
4. 滑动窗口注意力
另一种更省事的做法是:干脆只和座位前后左右的几位同学聊天,离得远的就暂时不理。这就像排队买奶茶,你只需要和前面几个人确认一下排队顺序,不必和队尾的人喊话。这种规则被称为滑动窗口注意力:每个词只关注相邻窗口大小为 \(w\) 的 \(2w+1\) 个词。
这样,每个词的配对数量从 \(n\) 降到了 \(2w+1\),总计算量从 \(n^2\) 降为 \(n \times (2w+1)\),变成了随序列长度线性增长。窗口 \(w\) 是常数时,无论文章多长,开销都只是成比例地增加,不再平方爆炸。
但有人会担心:只看邻居,远方的信息不就永远传不过来了吗?答案藏在“多层堆叠”里。Transformer 有很多层,每一层只和邻居交流,但信息会像“传话游戏”一样逐层扩散——第一层传给邻居,第二层邻居再传给邻居的邻居。层数足够多时,序列两端的信息照样能汇合到同一个词上。
滑动窗口把“全员聊天”改成了“邻居聊天 + 层层传话”。虽然单次对话范围变窄了,但依靠层数堆叠,整场聚会依然能信息互通,而代价却从平方级降到了线性级,真正让超长文本成为可能。
- 窗口大小 \(w\)每个词最多能看左右各多少个词,相当于“只和前后几个人聊天”。
- 配对次数 \(2w+1\)每个词关注的邻居数量,包含左侧 \(w\) 个、右侧 \(w\) 个和自己。
- 总计算量 \(n(2w+1)d\)每个词的配对次数从 \(n\) 降为常数,复杂度随 \(n\) 线性增长。
- 层级堆叠多层窗口交替作用,信息每层向外传播 \(w\) 个位置,深层即可覆盖全局。
5. 多查询注意力(MQA)
聚会开到一半又出现新问题:每个人都想记笔记,于是教室里坐着几十位“速记员”同时奋笔疾书,场面混乱且纸张浪费严重。多查询注意力(MQA)的想法很干脆——全班只保留一位速记员,所有人的谈话要点都交给这一个人记录,大家共用这一份笔记。
在 Transformer 里,标准注意力有 \(h\) 个“头”,每个头都维护自己独立的 K(键)和 V(值),相当于 \(h\) 位速记员各记各的。MQA 则让所有头共用同一份 K 和 V,只保留各自独立的 Q。这样,K/V 的数量从 \(h\) 份变成了 1 份,KV 缓存的内存占用直接缩为原来的 \(1/h\)。
为什么省内存能带来加速?因为在自回归生成时,模型要反复读取已经算好的 K/V 缓存。缓存越大,从显存搬运数据的时间就越长。MQA 把缓存大幅压缩后,显存带宽压力骤减,推理吞吐显著提升。代价是:所有头共享一套信息,表达多样性变弱,模型质量可能轻微下降。
全班共用一位速记员,纸张立刻省下了 \(h\) 倍,大家读笔记也快得多。但一份笔记要满足所有人的口味,难免丢失某些细节——这就是 MQA 用“质量换速度”的取舍。
- 注意力头数 \(h\)模型并行使用几套独立的 Q/K/V 关注不同子空间,相当于几个独立工作的速记员。
- 单头维度 \(d_{\mathrm{head}}\)每个注意力头处理的特征维度。
- 标准注意力 KV 参数 \(2h d_{\mathrm{head}}\)\(h\) 个头各存一份 K 和一份 V,共 \(2h\) 份。
- MQA 共享 KV所有头共用一份 K 和 V,因此与 \(h\) 无关。
6. 分组查询注意力(GQA)
既然一位速记员记全班容易遗漏细节,那能不能多配几位速记员,又不至于给每个人都配一个?分组查询注意力(GQA)给出的答案是:把全班分成若干小组,每组配一位速记员。组内成员共享同一份 K/V,组与组之间各自独立。
GQA 引入一个分组数 \(g\):一共有 \(g\) 份 K/V 和 \(h\) 个 Q 头,每组有 \(h/g\) 个 Q 头共享同一份 K/V。当 \(g=1\) 时,GQA 就退化成 MQA(全班一位速记员);当 \(g=h\) 时,每组只有一个 Q 头,GQA 又回到标准注意力(每人一位速记员)。因此 GQA 是夹在 MQA 与标准注意力之间的连续调节旋钮。
实际使用中,\(g\) 通常取 4 或 8,在“笔记够细致”和“纸张够省”之间取得平衡。例如 Llama 2 的 70B 模型就采用 GQA,用多组 K/V 保留了足够的信息多样性,同时把 KV 缓存压缩到标准注意力的几分之一,兼顾生成质量与推理吞吐。
分组速记员既避免了 MQA“一份笔记太粗”的问题,又比“人手一份笔记”省下大量纸张。GQA 的火爆正是因为它在质量与速度之间找到了一个性价比极高的甜蜜点。
- 分组数 \(g\)K/V 被分成几份,也就是配了几位速记员。
- 每组查询头数 \(h/g\)每组由多少个 Q 头共享这份 K/V。
- KV 参数 \(2g d_{\mathrm{head}}\)共有 \(g\) 份 K 和 \(g\) 份 V。
- 两个极限端点\(g=1\) 时只有一份 K/V 即 MQA;\(g=h\) 时每头一份 K/V 即标准注意力。
7. 方案综合对比
现在,我们手里有了好几套聚会规则:全员互聊(标准注意力)、通讯录名单(稀疏注意力)、邻居聊天(滑动窗口)、一位速记员(MQA)、分组速记员(GQA)。到底该选哪套?答案是:看聚会规模和信息需求。
- 质量优先:标准注意力信息最全,适合短文本、对精度要求极高的任务。
- 超长文本:稀疏注意力和滑动窗口把计算量从平方级降为线性级,适合处理长文档。
- 高并发推理:MQA 把 KV 缓存压到最小,吞吐最高,适合部署在流量巨大的线上服务。
- 均衡之选:GQA 介于标准注意力与 MQA 之间,常用于需要“质量不差、速度要快”的大模型。
如果量化 KV 缓存的影响,可以定义一个缓存缩减比:标准注意力的 KV 头数为 \(h\),GQA 为 \(g\),缓存大小与头数成正比,缩减比为 \(h/g\)。
这场“聚会规则改良”的旅程告诉我们:没有任何一种方案是绝对最优的。标准注意力像一场坦诚而昂贵的大型聚会,稀疏与窗口方案像懂得取舍的社交高手,MQA 是极致效率的独行侠,GQA 则是大多数场景下最务实的组织者。理解这些权衡,正是 AI 工程师做模型设计与部署决策的核心能力。
- 标准 KV 头数 \(h\)基线方案中每头一份 K/V。
- 改进后 KV 头数 \(g\)GQA 的组数,或 MQA 中固定为 1。
- 缓存缩减比 \(R\)KV 缓存大小与头数成正比,因此缩减比为两者之比。
AI 应用场景
长文本智能问答与文档分析
阶段:模型推理与部署优化
解决的问题:传统标准注意力在 10 万 token 级别的长文档上显存爆炸,问答系统无法直接“读完”整本手册;引入滑动窗口或稀疏注意力后,长文本占用显存线性可控,模型可以一次性扫描完整文档。
具体案例:某企业的客服机器人需要阅读 5 万字的售后服务手册。使用窗口注意力将复杂度降为线性后,同样的显存可以处理 4 倍长的文档,用户提问时机器人能准确引用手册深处的条款,回答完整率从 62% 提升到 89%。
高并发大模型在线服务
阶段:推理加速与成本控制
解决的问题:自回归生成需要反复读写 KV 缓存,并发用户越多,显存带宽越成为瓶颈;MQA/GQA 将 KV 缓存压缩数倍,相同 GPU 可以支撑更多并发请求。
具体案例:某 AI 写作平台在晚高峰需要同时服务 2000 个用户。将底座模型从标准注意力切换为 GQA 后,KV 缓存缩减为原来的 1/8,单卡吞吐提升 2.3 倍,单次生成成本下降约 40%,且生成内容的连贯性评分几乎不变。
大模型预训练的资源规划
阶段:模型训练与资源配置
解决的问题:训练超长序列模型时,标准注意力的 \(O(n^2)\) 激活内存让训练难以推进;在训练阶段直接采用稀疏或窗口注意力,可大幅降低激活显存,从而在同等硬件上训练更长上下文。
具体案例:某研究团队要在 8 卡 A100 上训练 32K 上下文的模型。改用滑动窗口注意力后,激活显存减少约 70%,训练吞吐提升近 2 倍,模型在长文本摘要任务上的 ROUGE 分数仅下降 0.5 个点,属可接受范围。
Python 演示
"""Compare standard, sliding-window, MQA and GQA attention costs."""import math def full_attn_flops(n: int, d: int) -> int: """Standard full attention: QK^T and AV, each ~ n^2 * d.""" return 2 * n * n * d def window_attn_flops(n: int, d: int, w: int) -> int: """Sliding window attention: each row attends to 2w+1 positions.""" return 2 * n * (2 * w + 1) * d def kv_cache_mb(layers: int, seq: int, d_head: int, kv_heads: int) -> float: """KV cache = 2 K/V * layers * seq * d_head * kv_heads.""" total = 2 * layers * seq * d_head * kv_heads return total * 4 / 1024 / 1024 def main() -> None: n, d, w = 4096, 128, 64 full = full_attn_flops(n, d) win = window_attn_flops(n, d, w) print(f"seq_len={n}, d_model={d}, window={w}") print(f"full attention flops : {full:>12,}") print(f"window attention flops: {win:>12,}") print(f"flops ratio : {win / full:.1%}") print() print("KV cache per layer (seq=4096, d_head=128):") for name, heads in [("standard(32)", 32), ("GQA(4)", 4), ("MQA(1)", 1)]: mb = kv_cache_mb(1, n, d, heads) print(f" {name:<14} {mb:8.1f} MB") if __name__ == "__main__": main()
def full_attn_flops(n: int, d: int) -> int:定义标准注意力计算量函数,接收序列长度与维度。return 2 * n * n * dQK^T 与 AV 两次矩阵乘法,各约 \(n^2d\) 次运算。return 2 * n * (2 * w + 1) * d每行只看 \(2w+1\) 个邻居,复杂度降为线性。def kv_cache_mb(...)计算 KV 缓存大小并换算为 MB,用于对比三种方案。total = 2 * layers * seq * d_head * kv_headsK 和 V 各一份,乘以层数、序列长度、维度与头数。for name, heads in [("standard(32)", 32), ...]用 32 头、4 组、1 头代表标准、GQA、MQA。
常见误区
误区我听说 MQA/GQA 能加速模型,那它们一定是把矩阵乘法的计算量变小了,所以训练和推理都更快。
正解MQA/GQA 并没有显著减少 FLOPs(浮点计算量),它们压缩的是 KV 缓存和显存带宽。自回归生成时,模型反复读取 KV 缓存,带宽才是瓶颈。缓存变小后,每次读写的字节数大幅下降,因此推理吞吐提升;但训练时的计算量基本不变。这就像聚会中速记员减少了纸张消耗,但大家聊天的内容并没有变少。
为何常见:人们习惯把“变快”直接归因于“计算更少”,忽略了访存瓶颈在推理中的主导地位。
误区让每个词只看一部分词,那肯定会漏掉关键信息,模型效果一定大打折扣。
正解设计良好的稀疏注意力(如全局 token + 局部窗口 + 随机采样)在大多数任务上几乎不掉点。真实文本中,绝大多数词对之间的关联本来就弱,注意力权重高度集中。掩码砍掉的往往正是那些权重接近 0 的“无效社交”,保留的是真正重要的连接。
为何常见:从直觉上,少看东西总觉得会丢信息;但注意力矩阵本身就很稀疏,人为稀疏只是顺势而为。
误区窗口注意力只看得到附近几个词,远处的词永远无法建立关联,长距离依赖一定学不会。
正解滑动窗口通过多层堆叠实现远距离信息传播。每层向外传递 \(w\) 个位置,层数为 \(L\) 时有效视野可达 \(L \times w\)。就像传话游戏:你只跟前面的人说话,但消息可以一路传到队尾。Mistral 7B 等模型正是用滑动窗口在长文本上取得出色表现。
为何常见:只关注单层窗口的局部性,忽略了 Transformer 深度堆叠带来的信息扩散效应。
误区GQA 比 MQA 保留更多信息、质量更高,那 MQA 就是过时方案,所有场景都该用 GQA。
正解GQA 在质量上通常优于 MQA,但 KV 缓存更大、吞吐更低。在极致的延迟敏感场景(如超大并发对话、长上下文生成),MQA 的缓存优势仍然不可替代。方案选择不是“谁更好”的问题,而是“哪个取舍更适合当前业务”的问题。
为何常见:看到开源模型普遍用 GQA,容易形成“GQA 全面优于 MQA”的简单判断,忽略了不同场景对质量和吞吐的权重差异。
误区稀疏注意力和滑动窗口都是部署时才用的小技巧,训练时用标准注意力就行,反正训练不在乎这点开销。
正解架构改进会影响训练的激活显存和吞吐。训练超长序列时,标准注意力的 \(O(n^2)\) 激活矩阵常常直接撑爆显存,导致无法训练长上下文模型。在训练阶段就使用稀疏或窗口注意力,是扩展上下文长度的必要手段,而不仅仅是推理优化。
为何常见:在短序列实验中,标准注意力训练开销尚可接受,让人误以为它永远不是瓶颈。
面试题
Q1. 标准注意力机制的计算复杂度随序列长度如何增长?
- A.计算量随序列长度线性增长
- B.计算量是序列长度乘以模型维度
- C.计算量随序列长度呈平方增长← 正确答案
- D.计算量是序列长度乘以窗口大小
答案:C。标准注意力需要计算 \(n \times n\) 个词对的相关性,因此复杂度为 \(O(n^2d)\)。C 正确。A 是滑动窗口等改进后的复杂度,B 描述的是单次矩阵乘的规模,D 是窗口注意力的复杂度。
Q2. 滑动窗口注意力中,每个词大约关注多少个位置?
- A.与序列长度相同的位置
- B.左右各 w 个,共约 2w+1 个位置← 正确答案
- C.全局随机采样 n 个位置
- D.只关注自身这一个位置
答案:B。滑动窗口将每个词的关注范围限制在相邻窗口内,单侧半径 w,总共约 \(2w+1\) 个位置。A 是标准注意力的全连接,C 属于随机稀疏注意力,D 等于完全失去上下文交流。
Q3. 多查询注意力 MQA 的核心设计是什么?
- A.所有查询头共享同一份键值对← 正确答案
- B.所有网络层之间共享权重矩阵
- C.把长序列切分成多个短片段
- D.大幅增加注意力头的数量
答案:A。MQA 让所有 Q 头共用一份 K 和 V,从而把 KV 缓存压缩为原来的 1/h。B 描述的是跨层权重共享,C 是分块处理,D 与 MQA 减少参数的方向相反。
Q4. 分组查询注意力中,当分组数 g 等于注意力头数 h 时,等价于什么?
- A.标准全注意力机制← 正确答案
- B.稀疏注意力机制
- C.多查询注意力机制
- D.滑动窗口注意力机制
答案:A。当 \(g=h\),每组只有一个查询头,每个头都拥有独立的 K/V,正是标准注意力。而 \(g=1\) 时才是 MQA(C),B 和 D 与分组数无关。
Q5. 滑动窗口注意力如何实现远距离信息的传递?
- A.在每一层内部做全局全连接
- B.对输入序列做随机排列组合
- C.依靠多层窗口层层传话覆盖← 正确答案
- D.额外引入一个全局记忆单元
答案:C。窗口注意力单层只能看到邻居,但多层堆叠后信息每层向外扩散 w 个位置,层数足够即可覆盖整个序列。A 就不是窗口注意力,B 破坏语序,D 是另一种全局稀疏设计而非滑动窗口的本质。
Q6. 下列哪些属于稀疏注意力的常见模式?
- A.与全局少量关键 token 相连← 正确答案
- B.与邻近位置 token 相连← 正确答案
- C.按某种规律随机采样相连← 正确答案
- D.与全部 token 两两相连
答案:ABC。全局 token 连接、局部窗口连接和随机连接是三种经典的稀疏模式,组合使用可兼顾全局与局部信息。D 是全连接的标准注意力,不属于稀疏注意力。
Q7. MQA 主要减少的资源开销是哪一项?
- A.减少了矩阵乘法的总 flops
- B.减少了 KV 缓存与显存带宽← 正确答案
- C.减少了训练所需的数据量
- D.减少了 Transformer 的网络层数
答案:B。MQA 的计算量(FLOPs)基本不变,压缩的是 KV 缓存大小,从而降低推理时的显存占用与带宽压力。A 是常见误解,C 和 D 与 MQA 设计无关。
Q8. 相比 MQA,GQA 的优点有哪些?
- A.分组让 K/V 保留更多信息细节← 正确答案
- B.KV 缓存远小于标准注意力缓存← 正确答案
- C.生成质量通常比 MQA 更稳定← 正确答案
- D.计算量显著低于标准注意力
答案:ABC。GQA 用多组 K/V 保留更多信息,质量优于 MQA,同时缓存比标准注意力小得多。D 错误,GQA 并不显著减少 FLOPs,它优化的是 KV 缓存而非计算量。
Q9. 在 GQA 中,若分组数 g=1,则它退化成哪种机制?
- A.多查询注意力机制← 正确答案
- B.标准全注意力机制
- C.滑动窗口注意力机制
- D.稀疏采样注意力机制
答案:A。\(g=1\) 意味着所有查询头共享唯一一份 K/V,这正是 MQA 的定义。\(g=h\) 时才退化回标准注意力(B),C 和 D 与分组数的端点无关。
Q10. Transformer 架构改进的共同目标包括哪些?
- A.提升长序列下的建模能力← 正确答案
- B.提升自回归生成的吞吐量← 正确答案
- C.不显著增加模型参数量← 正确答案
- D.彻底移除注意力计算
答案:ABC。稀疏注意力、滑动窗口、MQA、GQA 都在不大幅增加参数的前提下改善长序列建模或推理吞吐。D 错误,注意力机制是 Transformer 的核心,所有改进都是在保留注意力的前提下做效率优化。