剖析 BERT 附录:解码器
转载自:https://medium.com/dissecting-bert/dissecting-bert-appendix-the-decoder-3b86f66b0e5f
符号
在开始之前,让我们定义将在整篇文章中使用的符号:
emb_dim:嵌入的尺寸
input_length:输入序列的长度
target_length:目标序列的长度 + 1。+1 是移位的结果。
vocab_size:词汇量中的单词数量(偏离语料库)。
目标输入:我们将互换使用这个术语来描述解码器中的输入字符串(句子集)或序列。
介绍
Transformer是一种基于注意力的自然语言处理 (NLP) 架构,一年前在《 Attention Is All You Need》一文中介绍了这一架构。
在这篇博文中,我们将深入研究解码器;BERT 中未使用的Transformer 架构部分。我们将参考Encoder来解释完整的Transformer架构。
注意:如果您只想了解 BERT 的工作原理,则本博文中描述的Transformer部分不相关。
这篇文章的结构安排如下:
- Transformer旨在解决的问题。
- 信息流。
- 解码器。
问题
Transformer解决的问题是翻译。要将句子翻译成另一种语言,我们希望我们的模型能够:
- 能够捕捉输入句子中单词之间的关系。
- 将输入句子中包含的信息与每一步已翻译的信息结合起来。
想象一下,目标是将一个句子从英语翻译成西班牙语,我们得到以下标记序列:
X = [‘Hello’, ‘,’, ‘how’, ‘are’, ‘you’, ‘?’] (输入序列) Y = [
‘Hola’, ‘,’, ‘como’, ‘estas’, ‘?’](目标序列)
首先,我们希望通过组合序列中每个单词的信息来处理输入序列*X中的信息。*这是在编码器内部完成的。
一旦我们在编码器的输出中获得了这些信息,我们就希望将其与目标序列结合起来。这是在解码器中完成的。
编码器和解码器是Transformer架构的特定部分,如图 1 所示。我们将在第 3-b 级:层中详细研究解码器。
信息流
该架构的数据流如下:
- 该模型将每个标记表示为维度emb_dim的向量。然后,我们得到特定输入序列的维度*(input_length) x (emb_dimb)矩阵。*
- 然后它添加位置信息(位置编码)。*此步骤将返回维度(input_length) x (emb_dim)*的矩阵,就像上一步一样。
- 数据经过 N 个编码器块。之后,我们获得维度为*(input_length) x (emb_dim)*的矩阵。
- 目标序列被屏蔽并通过相当于 1) 和 2) 的解码器发送。输出的尺寸为*(target_length) x (emb_dim)*。
- 4)的结果经过N个解码器块。在每次迭代中,解码器都使用编码器的输出 3)。这在图 2 中用从编码器到解码器的箭头表示。输出的尺寸为*(target_length) x (emb_dim)*。
- 最后,它应用了全连接层和行式 softmax。输出的维度为*(target_length) x (vocab_size)。*
解码器块的输入和输出的维度是相同的。因此,使用一个解码器块的输出作为下一个解码器块的输入是有意义的。
注意:在 Attention Is All You Need 实验中,N 选择为 6。
注意:块不共享权重
输入
请记住,所描述的算法正在处理输入句子和目标句子以训练网络。输入句子将按照编码器架构中的描述进行编码。在本节中,我们讨论给定一个目标句子(例如“Hola,como estás?”),我们如何获得代表解码器块的目标句子的矩阵。
过程完全相同。它也由两个一般步骤组成:
- 代币嵌入
- 位置的编码。
主要区别在于目标句子发生了转移。也就是说,在填充之前,目标序列将如下:
[“Hola”, “, “, “como”, “estás”, “?”]→[“”, “Hola”, “, “, “como”, “estás”, “?”]
向量化目标序列的其余过程将与编码器架构中输入句子所描述的过程完全相同。
解码器
在本节中,我们将介绍解码器中与编码器中介绍的部分不同的部分。
解码器块——训练与测试
在测试期间,我们没有基本事实。在这种情况下,步骤如下:
- 计算输入序列的嵌入表示。
- 使用起始序列标记,例如“”作为第一个目标序列:[]。该模型给出下一个标记作为输出。
- 将最后一个预测的标记添加到目标序列中,并使用它生成新的预测 [‘’, Prediction_1,…,Prediction_n]
- 执行步骤 3,直到预测的标记是代表序列结束的标记,例如 。
在训练期间,我们有基本事实,即我们希望模型为上述过程的每次迭代输出的标记。由于我们提前有了目标,我们将立即为模型提供整个移位目标序列,并要求它预测未移位的目标。
继续我们之前的示例,我们将输入:
[‘’,‘Hola’, ‘,’, ‘como’, ‘estas’, ‘?’]
预期的预测是:
[‘Hola’, ‘,’, ‘como’, ‘estas’, ‘?’, ‘’]
然而,这里有一个问题。如果模型看到预期的标记并用它来预测自己怎么办?例如,它可能会在*'como’右侧看到’estas* '并用它来预测*‘estas’*。这不是我们想要的,因为模型在测试时无法做到这一点。
我们需要修改一些注意力层,以防止模型看到右侧(或向量表示矩阵中的向下)信息,但允许它使用已经预测的单词。
让我们用一个例子来说明这一点。鉴于:
[‘’,‘Hola’, ‘,’, ‘como’, ‘estas’, ‘?’]
我们将其转换为如上所述的矩阵并添加位置编码。这将产生一个矩阵:
就像编码器中一样,解码器块的输出也将是大小为*(target_length) x (emb_dim)*的矩阵。在逐行线性(右侧矩阵乘积形式的线性层)和每行 Softmax 之后,这将产生一个矩阵,其中每行的最大元素指示下一个单词。
这意味着分配给“”的行负责预测“Hola”,分配给“Hola”的行负责预测“,”,依此类推。因此,为了预测“estas”,我们将允许该行直接与绿色区域交互,但不与图 13 中的红色区域交互。
观察到我们在线性层中没有问题,因为它们被定义为按标记/按行以矩阵右乘的形式。
问题出在多头注意力上,并且输入需要被屏蔽。我们将在下一节中详细讨论屏蔽。
在训练时,所有行的预测都很重要。鉴于在预测时我们正在进行迭代过程,我们只关心目标/输出序列中最后一个标记的下一个单词的预测。
蒙面多头注意力
这将与多头注意力机制完全相同,但会为我们的输入添加屏蔽。
唯一需要屏蔽的**多头注意力块是每个解码器块的第一个。**这是因为中间的一层用于组合编码输入和从前一层继承的输出之间的信息。将每个目标标记的表示与任何输入标记的表示组合起来没有问题(因为我们将在测试时拥有所有这些表示)。
修改将在计算后进行: Q i K i T d k \frac{Q_iK_i^T}{\sqrt{d_k}} dkQiK