2.多头注意力
下图显示了同时包含编码器和解码器的transformer模型。我们可以观察到,每个解码器的多头注意力子层接收两个输入:一个是来自前一个子层(掩蔽多头注意力)的输入,另一个是编码器表示:
图1.52 – 编码器-解码器交互
让我们用R表示编码器表示(representation),用M表示掩蔽多头注意力子层获得的注意力矩阵。由于这里编码器和解码器之间有交互,这个层也被称为编码器-解码器注意力层(encoder-decoder attention layer)。
现在,让我们深入了解细节,学习多头注意力层究竟是如何工作的。多头注意力机制的第一步是创建查询、键和值矩阵。我们了解到可以通过将输入矩阵乘以权重矩阵来创建查询、键和值矩阵。但是在这个层中,我们有两个输入矩阵:一个是R(编码器表示)和另一个是M(前一个子层的注意力矩阵)。那么我们应该使用哪一个呢?
我们使用前一个子层获得的注意力矩阵M来创建查询矩阵Q,并使用编码器表示R来创建键和值矩阵。由于执行的是多头注意力机制,对于第i头,我们执行以下操作:
(1)查询矩阵Qi是通过将注意力矩阵M乘以权重矩阵WiQ创建的。
(2)键和值矩阵是通过将编码器表示R乘以权重矩阵WiK和WiV分别创建的。
这个过程图示如下:
图1.53 – 创建查询、键和值矩阵
但我们为什么要这样做呢?为什么我们要从M获取查询矩阵,而从R获取键和值矩阵呢?查询矩阵本质上持有我们的目标句子的表示,因为它来自M,而键和值矩阵持有源句子的表示,因为它来自R。但这是如何以及为什么产生作用的呢?让我们通过逐步计算自注意力来理解这一点。
自注意力的第一步是计算查询矩阵和键矩阵之间的点积。下图显示了查询矩阵和键矩阵。我们可以观察到,由于查询矩阵来自M,它持有目标句子的表示,而键矩阵来自R,它持有输入句子的表示。请注意,这里使用的值是任意的,只是为了更好地理解:
图1.54 – 查询和键矩阵
下图显示了查询矩阵和键矩阵之间点积的结果:
图1.55 – 查询和键矩阵之间的点积
通过观察前面的矩阵QiKiT,我们可以理解到:
(1)从矩阵的第一行,我们可以观察到我们正在计算查询向量q1()和所有键向量k1(I)、k2(love)和k3(learning)之间的点积。因此,第一行表明目标单词与源句子中的所有单词(I、love和learning)的相似程度。
(2)同样,从矩阵的第二行,我们可以观察到我们正在计算查询向量q2(我)和所有键向量k1(I)、k2(love)和k3(learning)之间的点积。因此,第二行表明目标单词“我”与源句子中的所有单词(I、love和learning)的相似程度。
(3)同样的情况适用于所有其他行。因此,计算QiKiT帮助我们理解查询矩阵(目标句子表示)与键矩阵(源句子表示)的相似程度。
多头注意力矩阵的下一步是将结果QiKiT除以sqrt(dk)。然后,应用softmax函数获得分数矩阵softmax(QiKiT/sqrt(dk))。
接下来,我们将分数矩阵乘以值矩阵Vi,得到softmax(QiKiT/sqrt(dk))Vi,并获得注意力矩阵Zi,如下所示:
图1.56 – 计算注意力矩阵
假设我们有以下结果:
图1.57 – 注意力矩阵的结果
目标句子的注意力矩阵Zi是通过将值向量乘以分数并求和来计算的。为了更清晰,让我们看看单词“我”的自注意力值z2是如何计算的:
图1.58 – 单词“我”的自注意力
如图所示,单词“我”的自注意力z2是通过将值向量乘以分数并求和来计算的。因此,z2的值将包含来自值向量v1(I)的98%的值和来自值向量v2(love)的2%的值。这基本上帮助模型理解目标单词“我”意味着源单词I。
同样,我们可以计算h个注意力矩阵,将它们连接起来,并将结果乘以一个新的权重矩阵W0,创建最终的注意力矩阵,如下所示:
现在,我们将这个最终的注意力矩阵送入解码器中的下一个子层——前馈网络。
下一节,我们将介绍解码器中的前馈网络是如何工作的。
感谢您的阅读,欢迎关注!