原文:https://mp.weixin.qq.com/s/Jypa7YybekHi2VqET2zaGg
欢迎关注公zh: AI-Frontiers
transformer往期文章推荐
过去几年里,Transformer 彻底改变了 NLP 领域。如今,也被广泛应用于机器人、计算机视觉等领域。
在前几篇关于 Transformer 的文章,我们了解了 Transformer 的架构、训练和推理过程,我们的目标不止「How」,更要讲清楚「Why」。
比如,Transformer 的强大能力要归功于注意力模块。但最关键的问题来了:它到底是怎么做的?为什么要这么做。本篇试着回答这个问题,帮助大家理解。
输入序列如何到达注意力模块的?
注意力模块存在于编码器栈和码器栈的每个编码器中。我们首先来详细了解一下编码器的注意力机制。
以英译西举例,源序列示例是 "The ball is blue.",目标序列是 "La bola es azul"。
源序列首先经过嵌入和位置编码层,每个词被生成嵌入向量。嵌入向量随后被传递到编码器,编码器首先会经过注意力模块。
在注意力机制中,嵌入的序列会经过三个线性层,生成三个独立的矩阵:查询矩阵、键矩阵和值矩阵,用于计算注意力得分。
需要注意的是,这些矩阵的每一行都对应于源序列中的一个单词。
输入的每一行都是序列中的一个单词
要理解注意力机制的运作方式,需要从源序列中的各个词语入手,追踪它们在 Transformer 模型中的处理路径,,即注意力模块内部的运作机制。
这将有助于理解源序列和目标序列中的每个词是如何与其他词相互作用的。
因此,在下面的解释中,请集中注意力关注每个词所执行的操作,以及每个向量如何映射到原始输入词。如果矩阵形状、算术运算的具体细节、多个注意力头等与每个词的去向没有直接关系,直接忽略这些细节。
为了简化解释和可视化,我们忽略嵌入维度,只跟踪每个单词的行。
每个词都经过一系列「可学习的」变换
上面说的每一行,都是由它对应的源词,经过一系列变换生成的:嵌入、位置编码、线性层。
所有这些转换都是可训练的操作。这意味着这些操作中使用的权重并非预先设定,而是由模型学习,从而产生所需的输出预测。
关键问题是,Transformer 如何确定哪组权重能带来最佳结果?我们稍后会再讨论。
注意力分数:Query 词和 Key 词之间的点积
注意力机制执行多个步骤,我们只关注线性层和注意力分数。
从公式可以看出,注意力机制的第一步是对查询矩阵(Q)和键矩阵(K)的转置进行矩阵乘法(即点积)。观察每个词的变化。
我们生成一个中间矩阵(我们称之为「因子矩阵」),其中每个单元格都是两个单词之间的矩阵乘法
例如,第四行的每一列对应于第四个查询词与每个关键词的点积。
注意力得分:查询词和值词之间的点积
下一步是将中间「因子矩阵」与值 (V) 矩阵相乘,得出注意力模块输出的注意力分数。可以看到,第四行对应于第四个查询词矩阵与所有其他键值对的乘积。
这样就产生了注意力模块输出的注意力得分向量(Z)。
理解输出得分的方法是:对于每个词,它是「值矩阵 」中所有词的编码值乘以「因子矩阵 」的权重。「因子矩阵 」是该特定词的查询值与所有词的键值的点积。
查询词、键和值的作用
-
Query 词:可以理解为 "我正在为它计算注意力" 的那个词。
-
Key 和 Value 词:是 "我正在关注"的那个词,换句话说,就是"这个词跟我的 Query 词有多相关"。
举个例子。对于 "The ball is blue" 这个句子,"blue" 那一行里,包含了 "blue" 与其他每个词的注意力分数。在这个例子里, "blue" 就是 Query 词,而其他词就是 Key / Value。
注意力计算里还有别的操作,比如除法和 Softmax。暂时忽略它们。这些操作只是改变矩阵里的数值,但不会影响每个词所在的行在矩阵中的位置,也不会引入任何词与词之间的交互。
点积,揭示词与词之间的相似度
我们已经看到,注意力分数通过计算点积并将结果相加,捕捉到特定词语与句子中其他所有词语之间的某种交互作用。但是,矩阵乘法是如何帮助 Transformer 确定两个词语之间的相关性的呢?
为了理解这一点,请记住,查询行、键行和值行实际上是具有嵌入维度的向量。让我们深入了解一下这些向量之间的矩阵乘法是如何计算的。
当我们对两个向量进行点积运算时,我们将成对的数字相乘,然后将它们相加。
-
如果两对数字(例如上面的 a 和 d)均为正数或均为负数,则它们的乘积为正数。乘积会增加最终的总和。
-
如果一个数是正数,另一个数是负数,那么它们的乘积将为负数。乘积会减少最终的总和。
-
如果乘积为正数,则两个数越大,它们对最终总和的贡献就越大。
这意味着,如果两个向量中对应数字的符号一致,则最终的总和会更大。
不同词之间的相关性
点积的这个特性,同样适用于注意力分数。如果两个词的向量更对齐(也就是符号一致的部分更多),那么注意力分数就更高。
那么,我们希望 Transformer 表现出什么样的行为呢?
-
对于句子里彼此相关的两个词,希望注意力分数高。
-
对于不相关的两个词,希望注意力分数低。
举个例子。对于 "The black cat drank the milk" 这个句子:
-
"milk"(牛奶)和 "drank"(喝)非常相关。
-
"milk" 和 "cat"(猫)可能稍微有点相关(但没那么强)。
-
"milk" 和 "black"(黑色的)则基本不相关。
我们希望模型学到的输出是这样的:
-
"milk" 和 "drank" 产生高注意力分数。
-
"milk" 和 "cat" 产生一个稍低的分数。
-
"milk" 和 "black" 产生一个可以忽略不计的低分。
为了达到这个效果,"milk" 和 "drank" 的词向量必须对齐;"milk" 和 "cat" 的词向量会有些分歧;而 "milk" 和 "black" 的词向量则会相当不同。
现在,回到前来遗留的问题:Transformer 是怎么知道哪一组权重能给它带来最佳结果的?
这些词向量,是基于词嵌入和线性层的权重生成的。因此,Transformer 可以去学习那些嵌入、线性层的权重等等,从而按上面需要的方式,生成合适的词向量。
换句话说:它会去学习那些嵌入和权重,使得两个词彼此相关就会对齐,从而产生更高的注意力分数;如果两个词不相关,词向量就不会对齐,产生较低的注意力分数。
因此:
-
"milk" 和 "drank" 的嵌入会非常对齐,产生高注意力分数。
-
"milk" 和 "cat" 的嵌入会有一些分歧,产生稍低的分数。
-
"milk" 和 "black" 的嵌入会相当不同,产生低分。
以上,就是注意力模块背后的核心原理。
小结:什么让 Transformer 这个「发动机」运转起来
-
Query 和 Key 之间的点积,计算出每一对词之间的相关性。
-
然后,这个相关性被当作一个「因子」,用来计算所有 Value 词的加权和。
-
这个加权和,就是注意力模块输出的注意力分数。
Transformer 去学习嵌入等参数,使得彼此相关的词嵌入向量更加对齐。
这也正是为什么要引入三个线性层,并把输入序列做成三个版本(Query、Key 和 Value)的原因之一。这给了注意力模块更多可学习的参数,让它能够去调优词向量的生成过程。
Transformer 里的编码器自注意力
注意力在 Transformer 里用于三个地方:
-
编码器中的自注意力:源序列关注自己。
-
解码器中的自注意力:目标序列关注自己。
-
解码器中的编码器-解码器注意力:目标序列关注源序列。
在编码器自注意力里,计算的是:源句子里的每个词,与源句子里的其他每个词之间的相关性。这发生在编码器堆栈里的所有编码器中。
Transformer 里的解码器自注意力
刚才在编码器自注意力机制中看到的大部分内容也适用于解码器中的注意力机制,只有一些细微但重要的区别。
在解码器自注意力机制中,我们计算目标句子中每个词与其他每个词之间的相关性。
Transformer 里的编码器-解码器注意力
在编码器-解码器注意力里:
-
Query 来自目标句子。
-
Key 和 Value 来自源句子。
因此,它计算的是:目标句子里的每个词,与源句子里的每个词之间的相关性。
感谢阅读文章,如果觉得不错,欢迎关注、点赞、转发!