转换器解码器是否像 GPT2 一样重用先前令牌的中间状态?

数据挖掘 nlp 变压器 openai-gpt
2022-03-10 15:25:32

我最近阅读了 Jay Alammar 关于 GPT-2 的博文(http://jalammar.github.io/illustrated-gpt2/),我发现其中一点很清楚:他解释说 GPT-2 的解码器在有一次,只主动处理最后一个输入令牌,过去的令牌已经保存在内存中,并且“被动地”重复使用而无需重新评估。

根据我对转换器架构的理解,我的印象是解码器会重新评估每一代生成的每个令牌。那么这是来自 GPT-2 的解码器之间的区别,还是来自“经典”变压器的解码器也以这种方式工作?

直觉上,我认为在每次迭代中重新评估所有内容会更有意义,因为单词之间的新依赖关系可能会出现在开始时不存在的情况,如果过去处理的单词被被动重用,则不会被考虑在内。

我希望我是有道理的,了解 GPT2 架构的人可以帮助我澄清这一点吗?

2个回答

我的理解是,Transformer 解码器和 Transformer 编码器-解码器模型通常以 GPT-2 的方式运行,即生成序列中的表示被计算一次,然后在以后的步骤中重复使用。但你是对的,这不是唯一可以做的事情。可以使用对迄今为止生成的序列中的标记的完全自注意力来重新计算部分生成的序列中所有标记的表示(这样做没有数学障碍——这类似于在部分生成的序列中的单词)。

但据我从文献中得知,这种额外的计算并不常见。我认为至少有两个原因。首先,正如其他人所指出的,使用先前时间步长的先前计算的表示在计算上更便宜(尽管它会导致不同的结果,而且我没有在任何论文中看到经验比较)。其次,它与培训的完成方式相匹配。在训练期间,self-attention 中的掩蔽结果是输出位置 i 的表示是使用输出位置 <= i 的表示计算的。这意味着在训练期间,对于每一层的输出位置 i,只有一个表示计算。这与使用我们一直在讨论并在 GPT-2 中使用的标准方法在推理时发生的情况相匹配。

如果我们想训练一个模型,其中输出位置的表示是基于所有可用的输出表示(当然总是排除那些尚未“生成”的表示),那么我们需要为每个输出计算多个表示训练期间的输出位置,每个可能的未覆盖部分正确上下文一个。例如,如果我们在大小为 512 的窗口上训练语言模型,我们将必须为第一个单词计算(大约)512 个表示,一个对应于在窗口中生成每个后续单词的损失。这将导致计算图非常大并减慢训练速度。但是,它可能会更好地工作,因为它会导致更丰富的输出表示,所以请尝试并告诉我们。:)

过去的令牌内部状态在 GPT-2 和任何其他 Transformer 解码器中都被重用。

例如,在 fairseq 的转换器实现中,这些先前的状态是TransformerDecoder.forward在参数中接收的incremental_state(参见源代码)。

请记住,解码器中的自注意力模块中有一个掩码,可以防止预测和中间状态关注等于或大于当前位置的位置,这意味着即使您重新计算它们,内部状态也不会改变在每个解码步骤。

更新:当然,在技术上可以重新计算过去的代币和未来的代币,但是,在你重新计算过去的代币之后,你如何处理未来的代币?你重新计算它们吗?这是一个完全不同的野兽,已经在一定程度上进行了研究,被称为“迭代细化”。可以在文章“Deterministic Non-Autoregressive Neural Sequence Modeling by Iterative Refinement”中找到一个示例。AFAIK,这种方法尚未在自回归模型中研究,仅在非自回归模型中研究。