我目前正在学习Transformer的代码,但我不能理解解码器的掩码多头。论文说是为了防止你看到生成词,但我不明白,如果生成词之后的词还没有生成,怎么能看到呢?
我试着读Transformer的代码(链接:https://github.com/Kyubyong/transformer)。代码实现掩码如下所示。它用下三角矩阵来遮罩,我不明白为什么。
padding_num = -2 ** 32 + 1
diag_vals = tf.ones_like(inputs[0, :, :]) # (T_q, T_k)
tril = tf.linalg.LinearOperatorLowerTriangular(diag_vals).to_dense() # (T_q, T_k)
masks = tf.tile(tf.expand_dims(tril, 0), [tf.shape(inputs)[0], 1, 1]) # (N, T_q, T_k)
paddings = tf.ones_like(masks) * padding_num
outputs = tf.where(tf.equal(masks, 0), paddings, inputs)
字符串
3条答案
按热度按时间wwodge7n1#
解码器是一个自回归器,不能看到未来的话
1.这意味着它将根据前一个令牌预测下一个令牌;
1.所以输入
x
不能看到未来的单词;1.我们使用掩蔽的多头注意力来做到这一点。
avwztpqn2#
假设我们正在训练的课文是“一二三四五”
这是自我监督训练,我们只是要训练模型来预测序列中的下一个单词。而不是编码器-解码器模型,我们将使用GPT风格的Transformer(有时称为“仅解码器”,因为它是“因果关系”,有时称为“仅编码器”,因为没有交叉注意)。
如果我们正在进行生成式预训练,我们将使用以下内容来训练这个模型:
input_tokens = [one, two, three, four]
和output_tokens [ two, three, four, five ]
我们移动令牌,使得模型总是预测下一个令牌。现在,对于输出“二”,我们只想考虑输入“一”。当学习生成输出“三”时,我们只想考虑输入“一”和“二”。
现在,在预训练之后,我们将输入模型“玛丽had a little”,我们期望得到输出“had a little lamb”。输出被移动一个标记。
在输出中对整个句子进行训练可能看起来很浪费。你可能会问自己,为什么不训练模型来预测下一个令牌呢?为什么预测输入中的单词,需要这个因果掩码?参数是共享的当模型通过关注“一”来学习“二”时,它正在改变模型参数,这些参数有助于在关注“四”时生成“五”。更长的序列长度最终相当于更大的批量大小,因此这种看似冗余的训练方式实际上非常有效。
3mpgtkmj3#
我阅读了Transformer paper之后也有同样的问题。我在互联网上没有找到完整和详细的答案,所以我将尝试解释我对掩蔽多头注意力的理解。
简短的回答是-我们需要掩蔽来使训练并行。并行化是好的,因为它允许模型更快地训练。
这里有一个例子来解释这个想法。比如说,我们训练把“我爱你”翻译成德语。编码器以并行模式工作-它可以在恒定数量的步骤(即,“I love you”)内产生输入序列(“I love you”)的向量表示。步骤的数量不取决于输入序列的长度)。
假设编码器产生数字
11, 12, 13
作为输入序列的向量表示。实际上,这些向量会长得多,但为了简单起见,我们使用短向量。同样为了简单起见,我们忽略了服务令牌,例如-序列的开始,-序列的结束等。在训练期间,我们知道翻译应该是“Ich liebe dich”(我们总是知道训练期间的预期输出)。假设“Ich liebe dich”单词的期望向量表示是
21, 22, 23
。如果我们以顺序模式进行解码器训练,它看起来就像循环神经网络的训练。将执行以下顺序步骤:
11, 12, 13
。21
21
,假设它是21.1
。11, 12, 13
,以及21.1
作为先前的输出。22
。22
,假设它是22.3
。11, 12, 13
,并将22.3
作为先前的输出。23
。23
,假设它是23.5
。这意味着我们需要进行3次顺序操作(一般情况下-每个输入都是顺序操作)。而且,我们在每次下一次迭代中都会有一个累积误差。此外,我们不使用注意力,因为我们只看一个以前的输出。
因为我们实际上知道预期的输出,所以我们可以调整该过程并使其并行。不需要等待上一步的输出。
11, 12, 13
。21
。11, 12, 13
和21
。22
11, 12, 13
和21, 22
。23
。该算法可以并行执行,而且不会积累误差。并且该算法使用注意力(即,查看所有先前的输入)因此具有关于在进行预测时要考虑的上下文的更多信息。
这就是我们需要面具的地方。训练算法知道整个预期输出(
21, 22, 23
)。它为每个并行操作隐藏(掩蔽)该已知输出序列的一部分。掩码本身的实现如下(来自original paper):
我们通过屏蔽(设置为−∞)softmax输入中与非法连接相对应的所有值,在缩放的点积注意力内实现这一点
注意:在推理(非训练)期间,解码器以顺序(非并行)模式工作,因为它最初不知道输出序列。但它与RNN方法不同,因为Transformer推理仍然使用自注意力并查看所有以前的输出(但不仅仅是前一个)。
注2:我在一些材料中看到,掩蔽可以在非翻译应用中以不同的方式使用。例如,对于语言建模,掩蔽可以用于从输入句子中隐藏一些单词,并且模型将尝试在训练期间使用其他未掩蔽的单词(即,未掩蔽的单词)来预测它们。学习理解上下文)。