你走进一座巨大的图书馆,手里攥着一张纸条,上面写着你的问题:“怎样做出酥脆的红烧肉?” 这张纸条就是你此刻的“检索需求”。图书馆里每一本书,书脊上都贴着一枚主题标签:“家常菜谱”“分子料理”“肉类烹饪科学”……标签回答的是“这本书是什么”。而每本书厚重的正文,才是真正有价值的内容,回答的是“这本书能给你什么”。你先用问题去和成千上万枚标签比对,相关度高的书优先翻开,最后把几本书的精华按比例揉成一份综合摘要——整个过程,就像一场“按需取用”的智能检索。 现代人工智能在做“理解语言”这件事时,用的正是同一个套路:让一个词,去整句话里“检索”自己需要的信息。哪个词和它关系最紧密,就从那个词身上多吸收一些信息;关系疏远的,就少吸收一些。这套机制,让机器可以同时照看整句话,而不用像老式方法那样逐字排队。神奇的是,“怎么提问”“怎么匹配”“怎么吸收”这三个问题,机器自己会在训练中摸索出答案。接下来的篇幅,我们就把这套机制一层层拆开看。
掌握 QKV 计算,你就拿到了理解 Transformer、GPT、BERT 等一切现代大模型的钥匙;无论是训练还是调优,你都能看清模型每一步在“读”什么、在“找”什么。
可视化演示
展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。
本节配有交互动效(进入视口后自动加载,约 3KB)。
系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T
QKV基本概念
你站在图书馆的检索台前,手里那张写满问题的纸条,就是 Query。它回答的问题只有一个:“我在找什么?” 图书馆里每本书的书脊标签,就是 Key,回答的是另一个问题:“我是什么?” 至于书里真正的文字和知识,则是 Value,回答的是:“我能给你什么?” 一次成功的检索,就是让 Query 和 Key 先对上话,再让 Value 交出内容。
把这个场景搬进 Transformer,一切都对应得上。模型读入一句话,比如“猫追老鼠”,每个字都会被表示成一个向量。关键的变化在于:每一个词向量,都会同时生成自己的 Q、K、V 三份“投影副本”。也就是说,每个词既是提出问题的人,也是书架上等待被检索的书。“猫”这个字,既拿着自己的问题纸条(Q),也在书脊上贴着标签(K),还带着自己的正文(V)。
三者角色分工明确:Q 负责“主动出击”,拿自己与序列里所有词的 K 做匹配,匹配度越高,说明这个词越值得关注;K 负责“被动响应”,安静地等着被别人匹配;V 负责“提供信息”,一旦确定某个词该被重点关注,就把自己的内容贡献出去。正是这套分工,让注意力机制既知道“该看谁”(由 Q 与 K 决定),也知道“看什么”(由 V 决定)。
就像图书馆里每一本书都可以反过来当检索者:当“老鼠”这个词想知道自己该关注谁时,它会拿出自己的问题纸条,去和“猫”“追”等词的标签比对,然后优先翻开“猫”这本书——因为它们俩的关系最紧密。整个句子,就在这样的相互检索中,形成了一张动态的“关注关系网”。
输入投影
图书馆不会把你的手稿原样摆上书架,而是由编目员加工成三件标准产品:一张检索问题卡片、一枚书脊标签、一份内容摘要。原始手稿是宝贵的,但它太“原始”,不能直接参与检索。Transformer 里的编目员,就是三个可学习的权重矩阵。
输入序列 X(可以理解为所有词向量的集合)分别乘上三个矩阵,就得到 Q、K、V。这三份副本不再是原始词向量本身,而是“为检索而量身定做”的三种形态。每个权重矩阵都是可学习的,模型在训练中会自己学会“怎样的问题更好提问、怎样的标签更利于匹配”。
投影还常伴随维度变化:输入维度是 d_model,而 Q、K 通常投影到 d_k 维,V 投影到 d_v 维。维度变小,既控制了计算量,又迫使模型把信息压缩到最关键的维度上。
编目员的工作看似重复——三份产出都来自同一份手稿,但正是这套“一稿三投”的流程,让之后的信息检索有了分工的基础。没有这三道投影工序,后面的匹配与聚合将无从谈起,就像图书馆若只堆原始手稿,谁也找不到自己想要的那本书。
- 输入 X一行是一个词,是整句话所有词向量拼成的矩阵,形状为 n×d_model。
- 权重矩阵 W_Q / W_K / W_V三个独立的学习参数,相当于编目员的三套专业工具。
- 矩阵乘法X 逐行与 W 相乘,完成线性变换,得到 Q、K、V 三个新矩阵,角色从此分家。
注意力分数
现在问题纸条(Q)要开始和书脊标签(K)打交道了。怎么判断“怎样做出酥脆的红烧肉”和“家常菜谱”更像,还是和“分子料理”更像?办法是量化相似度——把两个向量放在一起,看它们的“方向”是否一致。
技术上说,这个量化动作叫“点积”。点积越大,通常说明两个向量的方向越接近,也就是“越对得上”。于是,序列里第 i 个词的 Q,会和序列里每一个词的 K 都做一次点积,得到一个分数。所有分数拼在一起,就形成了一张 n×n 的分数矩阵。
直接点积有个隐患:向量的维度 d_k 越大,点积的数值往往越大,方差也随之膨胀,会让后续的 softmax 进入梯度饱和区。于是人们给点积加了一个缩放系数:除以 √d_k。这一除,分数的尺度就被拉回到稳定区间。这也正是论文里“缩放点积注意力”名字的由来——先缩放,再进 softmax。
就像图书馆评分员手里有一把“统一量纲”的尺子,不管书的标签是长是短、用词是繁是简,最后都能换成同一套百分制分数。有了这把尺子,不同书的匹配度才可以公平比较,后面的“按比例翻书”才有了可靠依据。
- 转置 KK 的形状是 n×d_k,转置成 d_k×n,才能与 Q 做矩阵乘法。
- 矩阵乘法 QK^T结果形状为 n×n,第 i 行第 j 列就是第 i 个词的 Q 与第 j 个词的 K 的匹配分。
- 除以 √d_k对每个元素统一除以根号 d_k,抑制维度增大带来的方差膨胀,保持梯度稳定。
Softmax归一化
打分表出来了,但分数是“绝对分”,还不能直接用来翻书。比如说“红烧肉”和“家常菜谱”的分数明显高于“分子料理”,但高多少才该多翻几页?你需要一个换算规则,把绝对分变成一组加起来正好等于 100% 的优先级。
这个换算规则就是 softmax。它先对每个分数取指数,再除以所有指数之和,把任意实数分数统统压到 (0,1) 区间,而且所有输出相加严格等于 1,构成一个合法的“概率分布”。在注意力里,这个概率分布就是每个词应该分到的注意力权重。
softmax 还有两个重要细节。第一,对任意两个分数,它们的权重之比等于“分数差”的指数倍,因此分数稍高一点,权重占比就可能明显领先——这正是 softmax 擅长“制造聚焦”的关键。第二,计算机算指数时,若分数很大,e^z 会溢出;稳健写法是先把整行减去该行最大值,再取指数,结果不变但数值安全。此外,有时还会引入温度系数 T:T 越大分布越平滑,T 越小越尖锐,用来控制注意力的“集中程度”。
图书馆的换算表把“绝对分”变成了“相对优先级”。原本只是分数高低的差别,经过 softmax 后变成了清晰的占比差异——高分者稳稳占据主导,低分者虽不至于为零,但已无足轻重。于是,接下来翻书的动作有了明确的轻重缓急。
- 指数函数 e^{z_i}将第 i 个分数转为非负的“热度值”,分数越高热度涨得越快。
- 分母求和 Σe^{z_j}把本行所有热度值加起来,作为归一化因子,保证总和为 1。
- 比值第 i 个热度值占全体热度值的比例,就是第 i 个词的注意力权重。
加权求和输出
优先级定了,最后一步就是把书打开、按比例吸收内容。相关度最高的书,你读得最仔细,贡献最多;相关度低的书,你只扫一眼,贡献极少。把所有书的内容按比例混合,就是一份综合摘要。整个过程叫“按权重对 V 做加权求和”。
在数学上,将 softmax 得到的权重矩阵与 V 相乘。权重形状为 n×n,V 形状为 n×d_v,相乘后第 i 行输出,就是“第 i 个词用整句话的信息更新后的新表示”,也就是上下文向量。这个向量同时携带了“自己原本的信息”和“从别人那里吸收的相关信息”。
完整的 Attention 公式就是把前面几步串起来。值得注意的是,softmax 是“按行”做的,每一行代表“某个词看其他所有词”的权重分布。因此输出的行数与输入行数相同,整个模块不改变序列长度,这为 Transformer 层层堆叠提供了便利。输出的每个向量,本质是 V 的加权组合,不会跑出 V 能表达的“信息范围”。
图书馆的检索闭环就此完成:问题 → 比对标签 → 算比例 → 翻书吸收。每个词都经历这样一轮“检索—吸收”,最终得到的输出里,已经悄悄融入了整句话的上下文。自注意力的名字也由此而来——每个词都在“注意”其他词,而注意的强度,完全由数据自己说了算。
- QK^T 点积计算所有词两两之间的匹配分数,得到 n×n 的相关性表。
- 缩放 √d_k除以根号 d_k,把分数拉回稳定区间,避免 softmax 梯度消失。
- softmax 归一化逐行把分数变成权重,每行之和为 1,代表某个词对其他词的关注比例。
- 乘 V 加权聚合用权重对 V 的各行做加权组合,输出上下文向量,完成信息吸收。
多头注意力
一个检索员,只盯着“主题”这一个角度查书,难免有盲区。比如“红烧肉”相关的书,有的胜在步骤详细,有的胜在原理透彻,还有的胜在故事好看。与其只派一个检索员,不如派八个,各负责一个角度,最后把八份报告拼在一起。
多头注意力就是“八个检索员”的工程实现。它把 d_model 维的 Q、K、V 均分成 h 组(每个头一组),每组独立走一遍自注意力流程,得到 h 份输出。每个头使用自己那组权重矩阵,实际上是在不同的低维子空间里做匹配,因此天然可以学到不同类型的依赖关系:有的头偏向语法结构,有的头偏向语义关联,有的头偏向位置远近。
每个头的维度是 d_k = d_model/h(Q、K 维度)与 d_v = d_model/h(V 维度)。把 h 个头的输出按列拼接,得到 d_model 维的向量,再乘上一个输出权重矩阵 W^O 做融合,就得到多头注意力的最终结果。这个“分而治之、最后汇合”的设计,既保证了总参数量不失控,又让模型从多个角度同时观察序列。
八个检索员各带回一份角度不同的报告,组长把它们拼起来、提炼成一份综合报告。多头注意力就是这样让模型“看得更全面”——单头注意力像一位专才,多头注意力则像一个各有所长的检索团队,这也是 Transformer 能同时捕捉复杂语言现象的关键之一。
- 分头投影第 i 个头用自己的权重矩阵,从原始 QKV 中切出属于自己的子空间视图。
- 独立注意力每个头单独执行缩放点积注意力,得到各自的上下文表示。
- 拼接与融合把 h 个头的输出横向拼成大矩阵,再乘 W^O 做线性融合,输出维度恢复为 d_model。
复杂度与优化
图书馆只有 4 本书时,两两比对只要 16 次;可当书架上有一万本书时,两两比对要一亿次。这就是“平方爆炸”:书越多,比对成本增长得越快。真实世界的文档动辄数万词,模型必须想办法给检索“减负”。
标准注意力要计算 n×n 的分数矩阵,时间与空间复杂度都是 O(n²),n 是序列长度。长度翻倍,成本变四倍;长度变一万,成本就是一亿。这成为长文本场景(如整本书级别的文档)的瓶颈。
工程师们从“哪些比对真正必要”入手,提出几类优化:稀疏注意力,让每个词只与固定的邻居或“全局哨兵”词比对,把复杂度降到 O(n);线性注意力,改变乘法顺序,先聚合 K、V 再与 Q 相乘,避开显式 n×n 矩阵;KV 缓存则用在推理阶段——生成下一个词时,前面已算好的 K、V 直接复用,不必重算。这些优化在长短不同任务里各有取舍,是当前大模型工程优化的主战场。
聪明的图书馆会做减法:书脊标签不必和所有书都比对,只比较同区域的书架、或者先看几次“总索引”。稀疏注意力、线性注意力、KV 缓存,本质都是给这场浩大的“两两检索”做减法——牺牲一点点全面性,换来处理超长文本的可能。这张考卷,至今仍是 AI 工程师们最常面对的优化课题。
- n 是序列长度句子里词的个数,即 token 数量。
- n² 次两两比对每个词要和其余每个词算一次匹配,共 n×n 次。
- 大 O 表示量级O(n²) 描述计算量随 n 增长的主导趋势,是衡量算法效率的标准记号。
AI 应用场景
机器翻译中的动态对齐
阶段:特征提取与上下文建模
解决的问题:传统 RNN 按顺序读句子,前面的词容易被遗忘,长句翻译常出错。自注意力通过 QKV 计算,让每个词一次性看完整句话,动态决定该依赖谁。
具体案例:在英译中时,面对“他把昨天买的苹果吃了”,“苹果”这个词的 Q 会与“吃”“买”的 K 形成高注意力权重,正确建立动宾关系;同时“昨天”的权重帮助模型把握时间状语,输出自然流畅的中文语序。
大模型推理的 KV 缓存加速
阶段:推理优化与部署
解决的问题:对话模型逐 token 生成时,若每次都重算全部 K、V,成本随对话变长飙升。KV 缓存把已算过的 K、V 存下来,新 token 只需计算自己的 Q 与缓存中的 K 匹配,再对缓存 V 加权求和。
具体案例:ChatGPT 类模型在流式输出时,KV cache 使解码吞吐量提升数倍,同时显著降低显存占用,是多轮对话能“秒回”的重要底层支撑。
Python 演示
import numpy as np class SelfAttention: def __init__(self, d_model, d_k, d_v): self.d_k = d_k self.d_v = d_v self.W_q = np.random.randn(d_model, d_k) * 0.1 self.W_k = np.random.randn(d_model, d_k) * 0.1 self.W_v = np.random.randn(d_model, d_v) * 0.1 def softmax(self, x): e = np.exp(x - x.max(axis=-1, keepdims=True)) return e / e.sum(axis=-1, keepdims=True) def forward(self, X): Q = X @ self.W_q K = X @ self.W_k V = X @ self.W_v scores = Q @ K.T / np.sqrt(self.d_k) weights = self.softmax(scores) out = weights @ V return out, weights def main(): np.random.seed(42) seq_len, d_model, d_k, d_v = 4, 8, 4, 4 X = np.random.randn(seq_len, d_model) attn = SelfAttention(d_model, d_k, d_v) out, weights = attn.forward(X) print("weights shape:", weights.shape) print("row sums:", weights.sum(axis=1)) print("output shape:", out.shape) print("output[0]:", np.round(out[0], 3)) if __name__ == "__main__": main()
self.W_q = np.random.randn(d_model, d_k) * 0.1初始化查询投影矩阵,乘以 0.1 让初始数值小一些,避免一上来就饱和Q = X @ self.W_q把输入矩阵投影成 Query,对应“把问题写在纸条上”scores = Q @ K.T / np.sqrt(self.d_k)核心一行:点积打相似度分,再除以根号 d_k 缩放e = np.exp(x - x.max(axis=-1, keepdims=True))先减去每行最大值再取指数,数值稳定版 softmaxout = weights @ V权重矩阵右乘 V,完成按权重聚合信息
常见误区
误区“Q 不就是这个词的向量吗?模型输入是什么,Q 就是什么。”很多初学者以为 QKV 是输入 X 的三种叫法。
正解Q、K、V 都是 X 经过独立权重矩阵投影后的产物,每个都是“加工过的副本”而不是原稿。就像图书馆里问题卡片、书脊标签、内容摘要都不是原始手稿,而是编目员按不同用途重新制作的。投影公式在训练中不断调整,决定了三份副本各自的“专业方向”。
为何常见:论文公式里 Attention(Q,K,V) 的 QKV 都写成大写变量,容易让人觉得它们是模型输入的一部分。
误区“Softmax 的作用就是把分数差距拉开,让大的更大、小的更小。”
正解Softmax 的核心作用是“把任意实数变成和为 1 的概率分布”,它有时会放大差距,但当分数都偏小时,反而会压缩差距。比如 0.83 和 0.05 经过 softmax 后权重约为 0.38 和 0.17,差距从 16 倍缩到 2 倍多。它不负责“制造悬殊”,只负责“变成合法概率”。
为何常见:指数函数单调递增,人们自然联想到“放大”,却忽略了归一化分母同时也在变大。
误区“√d_k 就是个常数,除不除都一样,反正 softmax 会归一化。”
正解虽然 softmax 能归一化,但它对输入尺度非常敏感。d_k 越大,点积分值的方差越大,极端分值把 softmax 推向饱和区,梯度趋近于零,模型几乎学不动。除以 √d_k 把方差拉回 1 附近,就像厨师统一各锅汤的咸淡再让评委打分,评委的舌头才不会被齁到失灵。
为何常见:除法项看起来像单纯调大小,初学者不易察觉它和梯度健康的深层关系。
误区“多头就是把一个注意力算好几遍然后取平均,属于浪费算力。”
正解每个头使用自己独立的投影矩阵,是在不同子空间里做匹配,学习到的模式互不相同。有研究可视化发现,有的头关注句法依赖,有的头关注指代关系,有的头关注相邻词。就像派一组各自持不同专长的检索员,汇总后信息更全面,绝不是简单重复。
为何常见:从公式看,每个头的计算结构确实相同,容易误以为结果也相同,忽略了“不同投影导致不同视角”这一关键。
面试题
Q1. 在自注意力中,Query 承担的核心职责是什么?
- A.存储序列的全部原始信息
- B.表达“当前词在找什么”← 正确答案
- C.表示书的实际正文内容
- D.控制输出向量的尺寸
答案:B。Query 对应图书馆里的问题纸条,表达的是“我在找什么”;存储原始信息是输入 X 的角色,书的内容对应 Value,输出尺寸由维度设定决定。Q 的核心职责是主动发起匹配,故选 B。
Q2. Q、K、V 三种向量分别由输入 X 与什么相乘得到?
- A.WQ/WK/WV 三个独立矩阵← 正确答案
- B.三个共享的输入权重矩阵
- C.同一个共享的权重矩阵
- D.输入向量的转置矩阵
答案:A。Q=XWQ、K=XWK、V=XWV,三个矩阵互相独立、各自可学习,绝不可混用同一个 W。这与图书馆编目员用三套工具加工出三种产品同理。B 的“共享”说法与“独立”矛盾,C、D 更是混淆了投影方式。
Q3. 缩放点积注意力中除以 √d_k 的主要目的是什么?
- A.防止点积分值方差过大← 正确答案
- B.增加模型的参数量
- C.将分数转换为概率
- D.降低计算的复杂度
答案:A。维度 d_k 越大,点积的方差越大,极端分数会把 softmax 推向饱和、梯度趋近零。除以 √d_k 将方差拉回 1 附近,保证梯度健康。转概率靠 softmax,降复杂度靠稀疏化等方法,均与缩放无关,故选 A。
Q4. 自注意力中的 softmax 完成归一化后,权重矩阵的行有什么特点?
- A.每行只有一个非零数
- B.每行元素全部相等
- C.每行元素之和为 1← 正确答案
- D.每行元素都大于 1
答案:C。softmax 按行把分数变为 (0,1) 区间的权重且每行和为 1,代表某个词对全体词的关注比例之和。行内值通常不相等,也可能全部小于 1,故选 C。这正是“优先级百分比加起来为 100%”的数学表达。
Q5. 自注意力最终输出的计算方式是下列哪一种?
- A.归一化权重与 V 加权求和← 正确答案
- B.归一化权重与 Q 加权求和
- C.Q 矩阵与 K 矩阵直接相加
- D.V 矩阵与 K 矩阵做拼接
答案:A。完整公式 Attention=softmax(QKᵀ/√dₖ)V,权重右乘 V 完成加权聚合。V 承载真正要传递的信息,Q 只负责提问、K 只负责匹配。用权重去聚合 Q,或把 Q/K 相加、K/V 拼接,都不符合公式定义,故选 A。
Q6. 多头注意力中每个头使用独立投影矩阵的根本目的是什么?
- A.加快 softmax 的运算速度
- B.在不同子空间捕捉不同模式← 正确答案
- C.减少模型的总参数量
- D.替代位置编码的模块
答案:B。每个头用独立的 WQi、WKi、WVi 投影,天然把 QKV 送入不同低维子空间,从而学到句法、语义、位置等不同依赖模式,类似各组专长不同的检索员。多头不会减少参数量,也不负责位置编码,故选 B。
Q7. 标准自注意力中,序列长度为 n 时的时间复杂度是多少?
- A.O(n) 线性阶
- B.O(n log n) 对数阶
- C.O(n²) 平方阶← 正确答案
- D.O(1) 常数阶
答案:C。每个 token 的 Q 都要与全部 n 个 K 做点积,n 个 token 共 n×n 次匹配,故时间与空间复杂度均为 O(n²)。n 翻倍成本变四倍,这正是长文本场景的瓶颈,也是稀疏注意力、线性注意力优化的对象,故选 C。
Q8. 关于 QKᵀ 得到的分数矩阵,下列说法正确的有哪些?
- A.分数矩阵的形状为 n×n← 正确答案
- B.表示词两两间的匹配度← 正确答案
- C.经 softmax 后每行和为 1← 正确答案
- D.矩阵中每个元素都为正数
答案:ABC。QKᵀ 中 Q 为 n×d_k、Kᵀ 为 d_k×n,乘积是 n×n 的相似度矩阵,第 i 行第 j 列即第 i 个词对第 j 个词的匹配分;softmax 按行归一化后每行和为 1,三项都正确。点积分值可正可负,D 错误。
Q9. 下列哪些手段可以降低自注意力的平方复杂度?
- A.稀疏注意力← 正确答案
- B.线性注意力← 正确答案
- C.KV 缓存
- D.提高学习率
答案:AB。稀疏注意力只让每个词与邻居或全局哨兵词匹配,线性注意力通过调整乘法顺序避开显式 n×n 矩阵,二者都直接降低复杂度。KV 缓存优化的是推理阶段的重复计算,不改变复杂度量级;学习率与复杂度无关,故选 A、B。
Q10. 关于数值稳定版 softmax,下列说法正确的是?
- A.先减去该行的最大值← 正确答案
- B.分子分母同缩不影响结果← 正确答案
- C.可完全避免 softmax 饱和
- D.该技巧只适用于注意力
答案:AB。分数很大时 e^z 可能溢出,先减去行最大值,分子分母同除一个常数,结果不变且数值安全,A、B 正确。该技巧只能防止溢出,不能消除梯度饱和问题;它同样适用于分类等场景,C、D 错误。