【什么是大模型自注意力机制?】
自注意力是Transformer架构的核心,它使模型能够通过权衡序列中所有其他元素的重要性,来计算序列中某个元素的表示。
第一部分:视频链接
建议读者先看视频,然后再看下面的计算过程,可以更加快速地理解计算步骤:
【通俗易懂理解自注意力机制(Self-Attention)】
第二部分:核心思想
想象一下你在阅读一句话:
“The animal didn’t cross the street because it was too tired.”
这里的 “it” 指的是什么?“animal” 还是 “street”?人类能轻松地判断出 “it” 指的是 “animal”,因为我们会根据上下文中的其他单词(如 “animal”, “tired”)来理解 “it”。
自注意力机制的目的就是让模型能够做到这一点:它允许序列中的每个位置(例如每个单词)去“关注”序列中的所有其他位置,从而根据整个上下文信息来计算出更好的当前元素的表示。
第三部分:计算过程分步解析
自注意力通过三个步骤将输入序列(一组向量)转换为输出序列(另一组向量,即注意力加权后的表示)。
我们用一个极简的示例来说明。假设我们的输入序列是两个单词,已经通过嵌入层(Embedding)转换为了两个向量。为了计算简单,我们使用非常低的维度。
定义输入:
假设我们的输入序列有两个词,每个词的嵌入向量是 2维 的。
X = [[1, 2], # Word 1 的向量 [3, 4]] # Word 2 的向量
X
的形状是 (2, 2)
(2个词,每个词2维)。
第1步:创建查询、键和值 (Q, K, V)
自注意力机制为输入序列学习三组不同的权重矩阵:W_Q
, W_K
, W_V
。这些矩阵的作用是将输入向量 X
投影到三个不同的空间,分别代表三种角色:
- 查询 (Query):表示当前词,它像是一个“提问”,用于去匹配其他词。
- 键 (Key):表示序列中的所有词,它像是身份的“标识”,用于被查询匹配。
- 值 (Value):表示序列中所有词所包含的“实际信息”,最终加权求和的对象。
为了简化,我们假设权重矩阵都是 2x2 的单位矩阵 I
。
W_Q = [[1, 0], [0, 1]]
W_K = [[1, 0], [0, 1]]
W_V = [[1, 0], [0, 1]]
现在,我们计算 Q, K, V:
Q = X * W_Q = [[1, 2], [3, 4]] * [[1, 0], [0, 1]] = [[1*1+2*0, 1*0+2*1], [3*1+4*0, 3*0+4*1]] = [[1, 2], [3, 4]]
K = X * W_K = [[1, 2], [3, 4]]
(计算同Q)
V = X * W_V = [[1, 2], [3, 4]]
(计算同Q)
所以,在这个特例中,Q = K = V = X
。
第2步:计算注意力分数 (Attention Scores)
注意力分数决定了当我们在某个位置编码一个词时,对其他词的关注程度。
我们通过计算查询向量 (Q) 和所有键向量 (K) 的点积来得到分数。
对于一个查询向量(例如,对于第一个词 q1 = [1, 2]
),我们计算它与所有键(k1 = [1, 2]
, k2 = [3, 4]
)的点积。
Scores = Q * K^T
= [[1, 2], [3, 4]] * [[1, 3], [2, 4]]^T
= [[1, 2], [3, 4]] * [[1, 2], [3, 4]]
(注意:这里 K^T
是 K 的转置)
= [[1*1 + 2*2, 1*3 + 2*4], [3*1 + 4*2, 3*3 + 4*4]]
= [[1+4, 3+8], [3+8, 9+16]]
= [[5, 11], [11, 25]]
得到的分数矩阵 (2, 2)
的含义是:
- 第一行
[5, 11]
:代表第一个词与第一个词自身的相关性(5),以及与第二个词的相关性(11)。 - 第二行
[11, 25]
:代表第二个词与第一个词的相关性(11),以及与自身的相关性(25)。
第3步:缩放并应用Softmax
- 缩放 (Scaling):为了防止点积的结果过大导致softmax函数的梯度消失,通常会将分数除以一个缩放因子。这个因子是键向量维度
d_k
的平方根。在我们的例子中d_k = 2
,所以缩放因子是sqrt(2) ≈ 1.414
。
Scaled_Scores = Scores / sqrt(d_k) = [[5/1.414, 11/1.414], [11/1.414, 25/1.414]] ≈ [[3.54, 7.78], [7.78, 17.68]]
- 应用Softmax:对缩放后的分数矩阵的每一行应用softmax函数。Softmax将分数转化为概率分布(所有权重为正数且总和为1),这代表了关注的“权重”。
计算第一行的softmax:[3.54, 7.78]
exp(3.54) ≈ 34.5
exp(7.78) ≈ 2396.0
Sum = 34.5 + 2396.0 ≈ 2430.5
Softmax([3.54, 7.78]) = [34.5/2430.5, 2396.0/2430.5] ≈ [0.014, 0.986]
计算第二行的softmax:[7.78, 17.68]
exp(7.78) ≈ 2396.0
exp(17.68) ≈ 非常巨大的数,我们假设是 4.8e7
Sum ≈ 2396.0 + 4.8e7 ≈ 4.8002396e7
Softmax([7.78, 17.68]) ≈ [2396.0/4.8e7, 4.8e7/4.8e7] ≈ [0.00005, 0.99995]
所以,最终的注意力权重矩阵为:
Attention_Weights ≈ [[0.014, 0.986], [0.000, 1.000]]
(第二行第一个数约等于0)
解读权重:
- 对于第一个词(第一行),它分配了 1.4% 的注意力给自己,98.6% 的注意力给第二个词。
- 对于第二个词(第二行),它分配了 ~0% 的注意力给第一个词,~100% 的注意力给自己。
第4步:计算输出
最终的输出是注意力权重和值向量 (V) 的加权和。
Output = Attention_Weights * V
-
第一个词的输出向量
Z1
:
Z1 = 0.014 * [1, 2] + 0.986 * [3, 4]
= [0.014*1 + 0.986*3, 0.014*2 + 0.986*4]
≈ [0.014 + 2.958, 0.028 + 3.944]
≈ [2.972, 3.972]
-
第二个词的输出向量
Z2
:
Z2 ≈ 0.000 * [1, 2] + 1.000 * [3, 4] = [3, 4]
所以,自注意力层的最终输出是:
Z = [[2.972, 3.972], [3.000, 4.000]]
第四部分:示例解读与总结
发生了什么?
- 我们的原始输入是
X = [[1,2], [3,4]]
。 - 经过自注意力计算后,输出变成了
Z ≈ [[2.97, 3.97], [3, 4]]
。 - 第一个词的表示
[1,2]
被显著地改变了,它融入了大量(98.6%)来自第二个词[3,4]
的信息,变成了[2.97, 3.97]
。 - 第二个词的表示
[3,4]
几乎保持不变,因为它主要关注自己。
这模拟了什么?
这模拟了在上下文中理解词义的过程。假设第一个词是“it”,第二个词是“animal”。自注意力机制计算出“it”的表示应该几乎完全由“animal”的表示来定义,这完美地解决了指代消解的问题。
关键要点:
- 动态权重:每个位置的输出都是整个序列的加权和,权重是根据词之间的相关性动态计算出来的,而不是固定的。
- 并行计算:由于矩阵运算,序列中所有位置的注意力可以并行计算,效率极高。
- 核心角色:Query, Key, Value 的概念是核心。模型通过
Q·K^T
计算相关性,然后用这个相关性对V
进行加权求和。 - 可学习性:在实际的Transformer中,
W_Q
,W_K
,W_V
是需要学习的参数矩阵,它们决定了如何将输入投影到Q, K, V空间,从而让模型学习到不同类型的关注模式(例如,关注语法、关注语义等)。