
在这篇文章里,我们会通过一个逐步展开的数值例子,学习注意力机制背后的数学:查询(Query,Q)、键(Key,K)和值(Value,V)。
我们会讲到:
- 注意力公式
- 准备工作:从词到向量
- 创建 Q、K 和 V 矩阵
- 计算注意力分数(Q x K^T)
- 缩放分数
- 应用 softmax
- 计算最终输出(注意力权重 x V)
- 把所有步骤串起来
开始吧。
注意力公式
**缩放点积注意力(Scaled Dot-Product Attention)**的核心公式是:
Attention(Q, K, V) = softmax(Q x K^T / sqrt(d_k)) x V
这里:
- Q 是查询矩阵
- K 是键矩阵
- V 是值矩阵
- K^T 是键矩阵的转置
- d_k 是键向量的维度
- sqrt 表示平方根
如果这个公式看起来复杂,不用担心。我们会用真实数字一步步拆开它。读完这篇文章后,这个公式的每一部分都会变得清楚。
思路很简单:我们把每个词想寻找的内容(查询),和其他每个词能提供的内容(键)进行比较,再根据比较结果,从最相关的词中收集实际信息(值)。
现在,用真实数字来看一遍。
准备工作:从词到向量
我们取一个只有 3 个词的简单句子:
"I love AI"(我爱 AI)
在 Transformer 里,每个词会先被转换成一个向量(也就是一组数字),称为嵌入(embedding)。为了便于理解,我们会使用非常小的 4 维向量(也就是 d_emb = 4)。
"I" → [1.0, 0.0, 1.0, 0.0]
"love" → [0.0, 1.0, 0.0, 1.0]
"AI" → [1.0, 1.0, 0.0, 0.0]
我们把这些向量堆叠成一个形状为 3 x 4 的输入矩阵 X(3 个词,每个词有 4 个数字):
X = | 1.0 0.0 1.0 0.0 | ← "I"
| 0.0 1.0 0.0 1.0 | ← "love"
| 1.0 1.0 0.0 0.0 | ← "AI"
这里,每一行代表一个词,每一列对应嵌入向量中的一个数字。这就是我们的起点。
创建 Q、K 和 V 矩阵
现在,我们需要创建三个单独的矩阵:Q(查询)、K(键) 和 V(值)。
怎么创建它们?我们把输入矩阵 X 分别乘以三个不同的权重矩阵:W_Q、W_K 和 W_V。这些权重矩阵是在训练过程中学习得到的。
Q = X x W_Q
K = X x W_K
V = X x W_V
在我们的例子里,假设 d_k = 3(也就是我们想让 Q、K、V 向量的大小为 3)。因此,每个权重矩阵的形状都是 4 x 3(输入维度 4,输出维度 3)。
为了便于理解,我们使用下面这些权重矩阵:
W_Q = | 1 0 1 |
| 0 1 0 |
| 1 0 0 |
| 0 1 1 |
W_K = | 0 1 0 |
| 1 0 1 |
| 0 0 1 |
| 1 1 0 |
W_V = | 1 0 0 |
| 0 1 0 |
| 0 0 1 |
| 1 1 0 |
现在,我们来计算 Q、K 和 V。
计算 Q = X x W_Q:
Q = | 1.0 0.0 1.0 0.0 | | 1 0 1 |
| 0.0 1.0 0.0 1.0 | x | 0 1 0 |
| 1.0 1.0 0.0 0.0 | | 1 0 0 |
| 0 1 1 |
第一行("I"):[11 + 00 + 11 + 00, 10 + 01 + 10 + 01, 11 + 00 + 10 + 01] = [2, 0, 1]
第二行("love"):[01 + 10 + 01 + 10, 00 + 11 + 00 + 11, 01 + 10 + 00 + 11] = [0, 2, 1]
第三行("AI"):[11 + 10 + 01 + 00, 10 + 11 + 00 + 01, 11 + 10 + 00 + 01] = [1, 1, 1]
Q = | 2 0 1 | ← "I"
| 0 2 1 | ← "love"
| 1 1 1 | ← "AI"
计算 K = X x W_K:
第一行("I"):[10 + 01 + 10 + 01, 11 + 00 + 10 + 01, 10 + 01 + 11 + 00] = [0, 1, 1]
第二行("love"):[00 + 11 + 00 + 11, 01 + 10 + 00 + 11, 00 + 11 + 01 + 10] = [2, 1, 1]
第三行("AI"):[10 + 11 + 00 + 01, 11 + 10 + 00 + 01, 10 + 11 + 01 + 00] = [1, 1, 1]
K = | 0 1 1 | ← "I"
| 2 1 1 | ← "love"
| 1 1 1 | ← "AI"
计算 V = X x W_V:
第一行("I"):[11 + 00 + 10 + 01, 10 + 01 + 10 + 01, 10 + 00 + 11 + 00] = [1, 0, 1]
第二行("love"):[01 + 10 + 00 + 11, 00 + 11 + 00 + 11, 00 + 10 + 01 + 10] = [1, 2, 0]
第三行("AI"):[11 + 10 + 00 + 01, 10 + 11 + 00 + 01, 10 + 10 + 01 + 00] = [1, 1, 0]
V = | 1 0 1 | ← "I"
| 1 2 0 | ← "love"
| 1 1 0 | ← "AI"
现在,Q、K 和 V 矩阵都准备好了。
注意: 在真实模型中,这些权重矩阵不是手工设置的,而是在训练过程中学习得到的。这里为了便于理解,我们使用了简单数字。
到目前为止,我们已经学会了如何从输入创建 Q、K 和 V。现在进入下一步。
计算注意力分数(Q x K^T)
注意力公式里的第一步,是计算 Q x K^T。
这个结果表示每个词应该在多大程度上关注其他各个词。计算时,要把每个词的查询向量与其他每个词的键向量相乘。
首先,我们需要 K^T(K 的转置)。转置的意思很简单:交换行和列。第一行变成第一列,第二行变成第二列,依此类推:
K^T = | 0 2 1 |
| 1 1 1 |
| 1 1 1 |
现在,计算 Q x K^T:
Q x K^T = | 2 0 1 | | 0 2 1 |
| 0 2 1 | x | 1 1 1 |
| 1 1 1 | | 1 1 1 |
"I" 对所有词的注意力分数:
- "I" → "I":20 + 01 + 1*1 = 1
- "I" → "love":22 + 01 + 1*1 = 5
- "I" → "AI":21 + 01 + 1*1 = 3
"love" 对所有词的注意力分数:
- "love" → "I":00 + 21 + 1*1 = 3
- "love" → "love":02 + 21 + 1*1 = 3
- "love" → "AI":01 + 21 + 1*1 = 3
"AI" 对所有词的注意力分数:
- "AI" → "I":10 + 11 + 1*1 = 2
- "AI" → "love":12 + 11 + 1*1 = 4
- "AI" → "AI":11 + 11 + 1*1 = 3
"I" "love" "AI"
Scores = | 1 5 3 | ← "I"
| 3 3 3 | ← "love"
| 2 4 3 | ← "AI"
这里可以看到,"I" 给 "love" 的注意力分数最高,为 5,意味着 "I" 认为 "love" 最相关。"love" 给所有词的分数都一样,都是 3。"AI" 给 "love" 的分数最高,为 4。
注意力分数的计算就到这里。现在进入缩放步骤。
缩放分数
现在,我们把每个分数都除以 sqrt(d_k)。
在这个例子里,d_k = 3(也就是键向量的维度),所以 sqrt(3) = 1.732。
问题来了:为什么要缩放?答案是:如果点积的值太大,下一步里的 softmax 函数会产生非常极端的值(接近 0 或 1)。这会让模型更难学习。缩放可以把数值保持在一个更容易处理的范围内。
Scaled Scores = Scores / sqrt(3)
"I" "love" "AI"
Scaled Scores = | 0.577 2.887 1.732 | ← "I"
| 1.732 1.732 1.732 | ← "love"
| 1.155 2.309 1.732 | ← "AI"
这里可以注意到,分数的相对顺序没有改变。"I" 仍然最关注 "love"。但数值变小了,这正是我们想要的。
以后,我计划写一篇文章,解释为什么选择除以 sqrt(d_k),而不是其他因子。
接下来应用 softmax。
应用 softmax
现在,我们对每一行应用 softmax 函数。Softmax 会把分数转换成概率,并且这些概率加起来等于 1。
一行里某个值 x_i 的 softmax 公式是:
softmax(x_i) = e^(x_i) / sum(e^(x_j) for all j in that row)
这里,e 是数学常数(约等于 2.718)。不用太纠结这个公式。我们会一步步算出来。
对 "I" 这一行:[0.577, 2.887, 1.732]
- e^0.577 = 1.781
- e^2.887 = 17.940
- e^1.732 = 5.651
- 总和 = 1.781 + 17.940 + 5.651 = 25.372
注意力权重:
- "I" → "I":1.781 / 25.372 = 0.070
- "I" → "love":17.940 / 25.372 = 0.707
- "I" → "AI":5.651 / 25.372 = 0.223
对 "love" 这一行:[1.732, 1.732, 1.732]
所有值都相等,所以每个词获得相同的注意力:
- "love" → "I":0.333
- "love" → "love":0.333
- "love" → "AI":0.333
对 "AI" 这一行:[1.155, 2.309, 1.732]
- e^1.155 = 3.174
- e^2.309 = 10.063
- e^1.732 = 5.651
- 总和 = 3.174 + 10.063 + 5.651 = 18.888
注意力权重:
- "AI" → "I":3.174 / 18.888 = 0.168
- "AI" → "love":10.063 / 18.888 = 0.533
- "AI" → "AI":5.651 / 18.888 = 0.299
最终的注意力权重矩阵是:
"I" "love" "AI"
Attention Weights = | 0.070 0.707 0.223 | ← "I"
| 0.333 0.333 0.333 | ← "love"
| 0.168 0.533 0.299 | ← "AI"
这里可以看到:
- "I" 把 70.7% 的注意力放在 "love" 上,22.3% 放在 "AI" 上,只有 7.0% 放在自己身上。
- "love" 对三个词的注意力相同(各 33.3%)。
- "AI" 把 53.3% 的注意力放在 "love" 上,29.9% 放在自己身上,16.8% 放在 "I" 上。
每一行加起来都是 1.0(也就是 100%)。这正是 softmax 所保证的。
现在,我们有了注意力权重。接下来计算最终输出。
计算最终输出(注意力权重 x V)
现在,我们把注意力权重矩阵和值矩阵 V 相乘,得到最终输出。
Output = Attention Weights x V
Output = | 0.070 0.707 0.223 | | 1 0 1 |
| 0.333 0.333 0.333 | x | 1 2 0 |
| 0.168 0.533 0.299 | | 1 1 0 |
对 "I":
- 0.0701 + 0.7071 + 0.223*1 = 1.000
- 0.0700 + 0.7072 + 0.223*1 = 1.637
- 0.0701 + 0.7070 + 0.223*0 = 0.070
对 "love":
- 0.3331 + 0.3331 + 0.333*1 = 0.999
- 0.3330 + 0.3332 + 0.333*1 = 0.999
- 0.3331 + 0.3330 + 0.333*0 = 0.333
对 "AI":
- 0.1681 + 0.5331 + 0.299*1 = 1.000
- 0.1680 + 0.5332 + 0.299*1 = 1.365
- 0.1681 + 0.5330 + 0.299*0 = 0.168
Output = | 1.000 1.637 0.070 | ← "I"
| 1.000 1.000 0.333 | ← "love"
| 1.000 1.365 0.168 | ← "AI"
这里可以看到,每个词现在都有了一个新向量,它是所有词的 V 向量的加权组合。"I" 得到的新表示受 "love" 的 V 向量影响很大(因为它对 "love" 的注意力权重最高,为 0.707)。这就是注意力机制的作用。
每个词的输出不再只与这个词本身有关。它现在包含了来自其他所有词的信息,并且这些信息会按相关性加权。这就是模型理解上下文和词与词之间关系的方式。
最终输出的计算就到这里。现在,把所有步骤串起来。
把所有步骤串起来
我们把整个计算过程集中总结一下:
第 1 步: 从输入嵌入向量(X)开始。
第 2 步: 用 X 乘以权重矩阵,得到 Q、K 和 V。
第 3 步: 用 Q 乘以 K 的转置(Q x K^T),计算注意力分数。
第 4 步: 除以 sqrt(d_k),对分数进行缩放。
第 5 步: 应用 softmax,得到注意力权重(概率)。
第 6 步: 用注意力权重乘以 V,得到最终输出。
整个过程可以写成一个公式:
Attention(Q, K, V) = softmax(Q x K^T / sqrt(d_k)) x V
现在,这个公式的每一部分都清楚了。
这就是注意力机制中 Q、K 和 V 背后的数学。
每个大语言模型(LLM)的核心都会用到这套计算。为了便于理解,我们使用的是很小的数字;但在真实模型里,维度会大得多(512、1024 或更高),权重矩阵也是在训练过程中学习得到的。
现在,我们应该已经理解了注意力机制背后的数学:Q、K 和 V。
今天就到这里。
谢谢
Amit Shekhar
Outcome School 创始人