从零理解注意力机制:Q、K、V 到底是什么,又从哪里来?

2026-10-05 · AI · 阅读 80 · 访客 65

一篇写给工程师的注意力机制入门笔记。不背公式,从「为什么」讲起。


目录

  1. 注意力机制的直觉:一次"查字典"
  2. 为什么需要 Q、K、V 三个角色?
  3. Q、K、V 从哪里来?——X 与可学习投影矩阵
  4. 为什么是 Q × Kᵀ,而不是 Q × K?
  5. 矩阵乘积的本质:批量点积 = 两两相似度
  6. X 又是从哪里来?——Embedding 表
  7. Embedding 表是怎么学出来的?
  8. Embedding 表的意义:把语言规律变成数学规律
  9. 完整数据流回顾
  10. 常见误区澄清

1. 注意力机制的直觉:一次"查字典"

注意力机制的一切,都可以从"查字典"这个动作出发。

想象你在查一本词典:

  • 你想查什么? → 这是 Query(查询)
  • 词典里每个词条的标题是什么? → 这是 Key(键)
  • 每个词条里解释的内容是什么? → 这是 Value(值)

查词典的过程是:

  1. 拿你的 Query,去和词典里所有 Key 比对
  2. 越匹配的 Key,对应的 Value 越重要
  3. 把所有 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.450.78...
102我0.20-0.500.80...
235爱0.700.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 行会被更新。

一次完整训练

用句子"我爱吃苹"预测"果"为例:

  1. 前向:查表得到 X,过网络,得到预测
  2. 损失:预测和正确答案比较
  3. 反向:梯度从损失一路回传,传到 embedding 表
  4. 更新:只有"我"、"爱"、"吃"、"苹"这 4 行被更新
  5. 重复:换下一个句子,走同样的流程

看了几十亿句子后,每一行都被更新过成千上万次。

为什么训练后语义相近的词会靠近?

没有人规定"猫"和"狗"要像,是训练自动把它们推到一起的。

原因:它们出现在相似的上下文里。

"...一只___在叫..."      → 猫、狗、鸟 都能填
"...我养了一只___..."    → 猫、狗、兔 都能填
"...___很可爱..."        → 猫、狗、兔 都能填

当模型在这些句子里预测时:

  • "猫"和"狗"收到的梯度方向相似(因为它们要满足相似的预测任务)
  • 所以它们的向量被推向相似的方向
  • 而"汽车"从不出现在"一只___在叫"里,它收到的梯度方向完全不同

这就是"分布假设":意思相近的词,上下文也相近;上下文相近,梯度就相似;梯度相似,向量就被推到相近的位置。


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 表学习全过程。