我正在努力理解 Transformer 模型中的解码器,特别是关于其架构的某些方面以及它在训练期间如何实际处理数据。
我现在拥有的是编码器的一个工作实现,它输出一些计算出的自注意力分数(使用缩放的点积作为我的注意力机制)。
在我的解码器中,我知道正确的“目标”输出首先是嵌入和位置编码的(我已经实现了)。然后我给解码器添加了一层自我关注。
据我了解,接下来是编码器-解码器注意块。
首先,自注意力层应该包含在解码器块中,与编码器-解码器注意力层一起重复,还是应该在目标传递到解码器后只发生一次?
接下来,对于实际的编码器-解码器注意力,我有点不确定查询、键和值向量是如何计算的。据我了解,编码器的输出通过前馈层来计算键和值向量,而解码器的前一个块的输出通过前馈层来计算查询向量。因此,我的实现如下:
x = self.encoder(x)
y = self.decoder_self_attention(y)
for decoder_block in self.decoder_blocks:
y = decoder_block(x, y)
这对我来说具有数学意义(所需的输出应该与解码器块的输入具有相同的嵌入维度,因此查询向量必须来自解码器,因为它是点积注意力计算中最左边的矩阵)。但是,我不明白这如何使它能够处理经常性数据。这尤其令人困惑,因为最后一层是前馈层,我不明白这将如何处理序列而不是说 LSTM。
此外,我已经阅读了关于何时发生屏蔽操作的非常矛盾的信息。有些论文直接对嵌入进行掩码,而有些论文在位置编码之后执行,而有些论文在注意力机制中实现。我的模型只是在叉积计算期间(在 softmax 之前)将掩码添加到查询和键向量的叉积中,但我不确定如何验证这是正确的。
z = (q @ k.transpose(-2, -1)) * scale # Q K^T / sqrt(d)
z += self.mask # before softmax, set everything above diagonal to -inf
最后,虽然我确定我无法理解解码器的某些方面导致错误,但我无法让我的模型适应不同模式的数据。我的输入嵌入形状在哪里是令牌的数量和是嵌入维度。但是,我的输出尺寸是形状在哪里和.
虽然在数学上这对于注意力机制应该没问题,但使用默认的 PyTorch 编码器和解码器层会引发大量错误,除非和,这使我相信当输入和输出序列具有不同的模态时可能会出现问题。尽管我的模型确实会在损失方面收敛,但当我传入训练数据并将输出转换回标记时,输出绝对是无意义的。我已经对照更传统的 LSTM 自动编码器检查了完全相同的数据集并得到了合理的结果,这让我相信我可能只是误解了变压器架构的某些部分。