从零理解注意力机制:Q、K、V 到底是什么,又从哪里来?
2026-10-05 · AI · 阅读 80 · 访客 65
一篇写给工程师的注意力机制入门笔记。不背公式,从「为什么」讲起。
目录
- 注意力机制的直觉:一次"查字典"
- 为什么需要 Q、K、V 三个角色?
- Q、K、V 从哪里来?——X 与可学习投影矩阵
- 为什么是 Q × Kᵀ,而不是 Q × K?
- 矩阵乘积的本质:批量点积 = 两两相似度
- X 又是从哪里来?——Embedding 表
- Embedding 表是怎么学出来的?
- Embedding 表的意义:把语言规律变成数学规律
- 完整数据流回顾
- 常见误区澄清
1. 注意力机制的直觉:一次"查字典"
注意力机制的一切,都可以从"查字典"这个动作出发。
想象你在查一本词典:
- 你想查什么? → 这是 Query(查询)
- 词典里每个词条的标题是什么? → 这是 Key(键)
- 每个词条里解释的内容是什么? → 这是 Value(值)
查词典的过程是:
- 拿你的 Query,去和词典里所有 Key 比对
- 越匹配的 Key,对应的 Value 越重要
- 把所有 Value 按匹配度加权求和,得到你要的结果
注意力机制就是这个过程的数学化。
在 Transformer 里,句子里的每个词都会发出自己的 Q、K、V;每个词用自己的 Q 去和全句所有词的 K 匹配,然后按权重从所有词的 V 中提取信息。这样,每个词的表示里就混入了上下文里"该关注的那些词"的信息。
2. 为什么需要 Q、K、V 三个角色?
一个自然的问题:既然每个词已经有一个向量 X,那直接 Q = K = V = X 不行吗?
答案是:不行,而且原因很致命。
原因 1:一个词同时扮演三种身份
一个词在句子里同时是:
| 角色 | 含义 |
|---|---|
| 提问者 | "我要找什么信息?" |
| 被检索者 | "别人要找我的时候,我该亮出什么标签?" |
| 信息提供者 | "如果别人关注我,我该给什么内容?" |
三件事关注的特征完全不同。
以「苹果」为例:
- 作为 Query,它关注"我后面接什么动词"
- 作为 Key,它需要告诉别人"我是水果"还是"我是品牌"
- 作为 Value,它根据上下文提供"水果"或"科技公司"的语义
如果 Q = K = V = X,模型就失去了为不同角色提取不同特征的灵活性。
原因 2:Q 和 K 必须不对称
注意力的核心是「用我的 Query 去匹配别人的 Key」。这里天然不对称:
- 「我」问「你」和「你」问「我」,语义完全不同
- 主语找宾语,和宾语找主语,是两件事
如果 Q = K,那么 Q·Kᵀ 会变成一个对称矩阵(S[i][j] = S[j][i]),注意力就失去了方向性。
原因 3:标签和内容本来就可以不同
一个词作为"被检索的标签"和作为"被提取的内容",没有理由相同。
W_K 和 W_V 让模型自己决定:
- 我对外"亮什么标签"(方便别人找到我)
- 被找到之后,我"交出什么内容"(我实际贡献的信息)
图书馆类比
| 概念 | 图书馆对应 |
|---|---|
| Query (Q) | 你告诉管理员"我想找深度学习的书" |
| Key (K) | 每本书书脊上的分类标签 |
| Value (V) | 每本书的实际内容 |
| Q·Kᵀ | 管理员比对需求和标签,算出匹配度 |
| softmax | 把匹配度变成优先顺序 |
| A·V | 按优先级,从每本书里各取内容 |
标签和内容本来就是两回事,这是 Q、K、V 必须分开的根本原因。
3. Q、K、V 从哪里来?——X 与可学习投影矩阵
既然 Q、K、V 是三个不同角色,它们怎么从 X 得来?
答案很简单:用三个不同的投影矩阵。
Q = X · W_Q
K = X · W_K
V = X · W_V
其中:
- X:每个 token 的输入向量(来自 embedding + 位置编码)
- W_Q、W_K、W_V:三个可学习的参数矩阵
- Q、K、V:投影后的三个不同表示
为什么用矩阵,而不是固定函数?
因为「怎样把 X 投影成好用的 Q」这件事,应该由模型自己学出来:
- 英语和中文的投影方式不同
- 代码任务和诗歌任务不同
- 不同的注意力头学到的也不同
W_Q、W_K、W_V 就是给模型的自由度。
训练开始时它们是随机数;训练过程中通过反向传播和梯度下降,模型自己学会了「该怎样把输入投影成好用的 Q、K、V」。训练结束后它们固定,推理时不再变化。
维度关系
通常 W_Q、W_K、W_V 会把输入维度 d 投影到更小的维度 d_k(每个头的维度)。这就是为什么:
- X 是
[n, d](n 是 token 数) - W_Q、W_K、W_V 是
[d, d_k] - Q、K、V 是
[n, d_k]
维度减少让计算更高效,也是多头注意力的基础——每个头用自己的一组 W,投影到自己的子空间。
4. 为什么是 Q × Kᵀ,而不是 Q × K?
这是一个非常常见的疑惑:K 为什么要转置?
答案不是"逻辑要求",而是"让矩阵乘法成立,并且刚好实现我们想要的效果"。
我们想要什么?
我们想要:每一个 Query 和每一个 Key 做一次点积,得到一张 n × n 的分数表。S[i][j] = 第 i 个词的 Query 和第 j 个词的 Key 有多像。
直接 Q × K 行不行?
Q 是 [n, d_k],K 也是 [n, d_k]。
矩阵乘法要求:左矩阵的列数 = 右矩阵的行数。
这里 d_k ≠ n(除非 token 数恰好等于维度),乘法根本不成立。
就算强行逐元素相乘,也只会得到 [n, d_k] 的矩阵——那是"同一个词的 query 和 key 相乘",完全不是我们想要的。
Kᵀ 解决了什么?
Kᵀ 是 [d_k, n]。左矩阵列数 d_k = 右矩阵行数 d_k,乘法成立。
结果 [n, n]:
- 行是"谁在问"
- 列是"被问的是谁"
- S[i][j] = 第 i 个词的 Query · 第 j 个词的 Key
更妙的是:Kᵀ 的第 j 列,原本就是 K 的第 j 行,也就是第 j 个词的 Key 向量。所以 Q 的每一行和 Kᵀ 的每一列做点积,正好就是"每个 Query 和每个 Key 配对"。
换个角度
点积有交换律 q·k = k·q,所以 Q·Kᵀ 和 K·Qᵀ 数值上等价,只是行列位置不同。
我们约定用 Q × Kᵀ,是因为它更符合直觉:第 i 行就是"第 i 个词问了每个词多少分",方便下一步按行做 softmax。
转置不是逻辑要求,而是让批量点积正好成形的技术手段。
5. 矩阵乘积的本质:批量点积 = 两两相似度
理解了 Kᵀ,还需要理解矩阵乘积在表达什么关系。
两个向量相乘 = 一个相似度
一个行向量 × 一个列向量,得到一个数:
[1, 0] · [1] = 1×1 + 0×1 = 1
[1]
这个运算叫点积。几何意义是:两个向量有多"对齐"。
- 方向接近 → 点积大
- 方向垂直 → 点积为 0
- 方向相反 → 点积为负
点积 = 相似度。 这是注意力机制最重要的一件事。
矩阵乘积 = 批量做点积
既然每一对向量的点积是"一对相似度",那所有配对就是"一张相似度表"。
Q 有 n 行,K 有 n 行,我们想要 n×n 个相似度分数。矩阵乘法就是一次性算完:
Q Kᵀ S
[q₁] [k₁ k₂ k₃] [q₁·k₁ q₁·k₂ q₁·k₃]
[q₂] × [ ] = [q₂·k₁ q₂·k₂ q₂·k₃]
[q₃] [ ] [q₃·k₁ q₃·k₂ q₃·k₃]
S[i][j] = qᵢ · kⱼ = 第 i 个向量和第 j 个向量的相似度。
所以矩阵乘积表示什么关系?
它表示的是"两组向量之间的两两相似度矩阵"。
它不是说"A 矩阵和 B 矩阵这两个整体有什么关系",而是在说:A 的每一行,分别和 B 的每一行,是什么关系。
在注意力里:
- Q 的第 i 行 = 第 i 个词的"我在找什么"
- K 的第 j 行 = 第 j 个词的"我是什么标签"
- S[i][j] = 第 i 个词觉得第 j 个词有多相关
这个关系矩阵就是注意力的核心。
6. X 又是从哪里来?——Embedding 表
到这里,Q、K、V 的来源清楚了。但 X 又从哪里来?
X = 词嵌入 + 位置编码。
Embedding 表:把词翻译成数字
神经网络只认数字。但你不能直接把"我"编号成 102 就丢进去——102 这个数字本身没有含义。
Embedding 表是一张巨大的数字表格:
| 行号 (token ID) | 词 | 维度1 | 维度2 | 维度3 | ... |
|---|---|---|---|---|---|
| 0 | [PAD] | 0.12 | -0.45 | 0.78 | ... |
| 102 | 我 | 0.20 | -0.50 | 0.80 | ... |
| 235 | 爱 | 0.70 | 0.30 | -0.20 | ... |
| ... | ... | ... | ... | ... | ... |
- 行数 = 词表大小(如 5 万行)
- 列数 = 嵌入维度 d(如 768 列)
查表操作:拿 token ID 当行号,取出那一行。
为什么说它"有语义"?
训练之后,语义相近的词,它们的向量也相近。
经典例子:
vec("国王") - vec("男人") + vec("女人") ≈ vec("女王")
这说明 Embedding 表不只是"随便编的编号",而是真的把词的含义编码进了那串数字的方向和距离里。
位置编码
Embedding 表解决"我是哪个词",位置编码解决"我在第几个位置"。
两者相加,得到 X:
"我" 在位置 0 → embedding[102] + position[0] = X₁
"爱" 在位置 1 → embedding[235] + position[1] = X₂
7. Embedding 表是怎么学出来的?
核心机制一句话:Embedding 表就是一层可训练的权重矩阵,通过反向传播和梯度下降更新。
关键问题:查表怎么反向传播?
"查表"听起来不可导,但它等价于用 one-hot 向量乘整个矩阵:
one-hot("我") = [0, 0, 1, 0, 0]
[0,0,1,0,0] × Embedding表 = 表的第 2 行
既然是矩阵乘法,反向传播就自然成立:
- 前向时只有第 2 行被"选中"
- 反向时,只有第 2 行会收到梯度
- 其他行的梯度是 0
每次训练,只有出现在这个 batch 里的那些词,它们的 embedding 行会被更新。
一次完整训练
用句子"我爱吃苹"预测"果"为例:
- 前向:查表得到 X,过网络,得到预测
- 损失:预测和正确答案比较
- 反向:梯度从损失一路回传,传到 embedding 表
- 更新:只有"我"、"爱"、"吃"、"苹"这 4 行被更新
- 重复:换下一个句子,走同样的流程
看了几十亿句子后,每一行都被更新过成千上万次。
为什么训练后语义相近的词会靠近?
没有人规定"猫"和"狗"要像,是训练自动把它们推到一起的。
原因:它们出现在相似的上下文里。
"...一只___在叫..." → 猫、狗、鸟 都能填
"...我养了一只___..." → 猫、狗、兔 都能填
"...___很可爱..." → 猫、狗、兔 都能填
当模型在这些句子里预测时:
- "猫"和"狗"收到的梯度方向相似(因为它们要满足相似的预测任务)
- 所以它们的向量被推向相似的方向
- 而"汽车"从不出现在"一只___在叫"里,它收到的梯度方向完全不同
这就是"分布假设":意思相近的词,上下文也相近;上下文相近,梯度就相似;梯度相似,向量就被推到相近的位置。
8. Embedding 表的意义:把语言规律变成数学规律
训练完成后,我们得到一张表。它到底有什么意义?
意义 1:把"符号"变成"数学"
计算机原本只会处理数字。文字对它是无意义的符号——"猫"就是 102,"狗"就是 235,102 和 235 之间没有任何关系。
这张表做了一件革命性的事:给每个词分配一串数字,让"关系"可以变成"数学运算"。
- "猫" → (0.62, 0.55)
- "狗" → (0.78, 0.68)
- "汽车" → (-0.68, 0.62)
现在可以算了:
- 猫和狗的距离 ≈ 0.21,很近
- 猫和汽车的距离 ≈ 1.30,很远
"猫和狗更接近"这件事,第一次变成了可以计算的东西。
意义 2:向量空间 = 语义地图
距离 = 语义相似度:相似词的点靠得近,不相似的点离得远。
方向 = 语义关系:经典例子
vec("国王") - vec("男人") + vec("女人") ≈ vec("女王")
翻译成人话:从"男人"到"国王"的方向 = 从"女人"到"女王"的方向。"性别/提升"这个语义,被编码成了一个方向向量。
同理:
vec("巴黎") - vec("法国") + vec("日本") ≈ vec("东京")vec("走") - vec("走") + vec("跑")类似关系到处存在
这张表里藏着一套"语义坐标系"。 这是训练过程中模型自己发现的。
意义 3:它是模型理解世界的第一层
Transformer 里,后面所有计算都建立在 X(= embedding + 位置编码)之上。
- 如果 embedding 表把"猫"和"狗"放在很远的位置 → 后面的注意力很难发现它们相似
- 如果 embedding 表已经把它们放在附近 → 后面的注意力、FFN 就能"站在巨人肩膀上"
这张表是整个模型的地基。 所以大模型参数量里,embedding 表往往占几千万到几亿个参数。
意义 4:实用价值
学好的 embedding 表可以直接用:
- 语义搜索:搜"怎么养小狗",也能返回"如何照顾幼犬"
- 类比推理:
vec("东京") + vec("中国") - vec("北京") ≈ "日本" - 迁移学习:预训练好的表可以拿到具体任务上微调
- 可解释性:通过看哪些词聚在一起,理解模型的内部世界
9. 完整数据流回顾
把所有环节串起来:
文字
↓ 查 embedding 表(训练学出来的)
X(每个 token 一个向量)
↓ 加上位置编码
X'(带位置的输入)
↓ 乘 W_Q、W_K、W_V(训练学出来的)
Q、K、V
↓ Q·Kᵀ / √d_k
分数 S
↓ softmax(按行)
权重 A
↓ A · V
输出 O
↓ 残差、FFN、堆叠 N 层……
预测下一个词
↓ 和正确答案比较
损失
↓ 反向传播
调整所有参数:embedding 表、W_Q、W_K、W_V、FFN 的权重……
每一步的数据形状:
| 阶段 | 形状 | 说明 |
|---|---|---|
| token IDs | [n] | n 个整数 |
| X(embedding) | [n, d] | 每个 token 变 d 维向量 |
| Q、K、V | [n, d_k] | 投影到 d_k 维 |
| S = Q·Kᵀ | [n, n] | 两两相似度 |
| A = softmax(S) | [n, n] | 每行和为 1 |
| O = A·V | [n, d_k] | 输出 |
10. 常见误区澄清
误区 1:Q、K、V 是"事先定义的"
不是。它们由 X 乘 W 得到,W 是训练学出来的。人类只规定了"用 Q·Kᵀ 这个结构"。
误区 2:K 转置是"逻辑要求"
不是。转置是为了让矩阵乘法成立,并让"每个 Query 和每个 Key 配对"这件事能用一次矩阵乘法完成。
误区 3:Q×Kᵀ 和 K×Qᵀ 完全不同
不是。数值上等价,只是行列位置不同。选 Q×Kᵀ 是因为它让"每行是某个词的注意力分配",方便按行做 softmax。
误区 4:Embedding 表是人工设计的
不是。随机初始化,训练学出来。语义相近的词聚到一起,是"分布假设"导致的自然结果。
误区 5:Q、K、V 必须维度相同
不是。d_k 可以不同于 d,这正是多头注意力能高效并行的原因。
结语
注意力机制的核心,其实一句话就能说清楚:
让每个词去"检索"全句的信息。用 Q 和 K 算相似度,用 softmax 变成权重,用权重加权 V。
但要把这句话落到每一个细节上,就涉及:
- Q、K、V 为什么必须分开 → 检索的三种角色
- Q、K、V 从哪里来 → X 乘可学习的 W
- K 为什么要转置 → 让批量点积成立
- 矩阵乘积表示什么 → 两组向量的两两相似度
- X 从哪里来 → Embedding 表 + 位置编码
- Embedding 表怎么学 → 反向传播只更新被查到的行
- Embedding 表的意义 → 把语言规律变成数学规律
理解这七层,就理解了注意力机制,也理解了大模型为什么能从数据里"学"到语言的规律。
本文配套一个可交互的 HTML 动画演示,涵盖 Q/K/V 生成、矩阵乘法、训练循环与 Embedding 表学习全过程。