基于 Transformer 的 Encoder-Decoder 模型 Hugging Face 博客文章 2020

TL;DR

Hugging Face 发布了一篇教育性博客文章,详细介绍了基于 Transformer 的 encoder-decoder 模型,解释了其 encoder 和 decoder 组件、self-attention 和 cross-attention 的工作原理,并使用 MarianMT 翻译示例演示了使用 🤗Transformers 库进行自回归生成。

背景

该博客文章将 sequence-to-sequence 任务定义为将输入向量序列映射到未知长度的目标序列,这一表述促使了 encoder-decoder 模型的发展。

"自然语言生成 (NLG)(NLP 的一个子领域)中的任务最好表达为 sequence-to-sequence 问题。"

文章指出,早期的基于 RNN 的 encoder-decoders 可以处理变长输出,但存在梯度消失和并行化能力有限的问题。

"RNN 受梯度消失问题的影响,这使得捕捉长程依赖变得非常困难……其次,RNN 固有的循环架构在编码时阻碍了高效的并行化。"

随后,文章介绍了 Vaswani 等人 (2017) 提出的 Transformer 架构,作为实现变长序列高度并行化处理的解决方案。

Encoder-Decoder 架构

基于 Transformer 的 encoder-decoder 由一个 encoder stack 和一个 decoder stack 组成,每个 stack 都是由 residual attention blocks 构建而成的。

"类似于基于 RNN 的 encoder-decoder 模型,基于 Transformer 的 encoder-decoder 模型由一个 encoder 和一个 decoder 组成,两者都是 residual attention blocks 的堆叠。"

encoder 将输入序列映射为一系列上下文相关的隐藏状态(hidden states),而 decoder 则根据这些编码和先前生成的 token 来建模目标序列的条件分布。

"基于 Transformer 的 encoder 部分将输入序列编码……为一系列隐藏状态……基于 Transformer 的 decoder 部分随后根据编码的隐藏状态序列来建模目标向量序列的条件概率分布……"

自回归生成是逐步进行的,decoder 在第一次前向传播后会重复使用 encoder 的输出。

"重要的是要理解,encoder 仅在第一次前向传播中使用以进行映射……从第二次前向传播开始,decoder 可以直接利用之前计算的编码。"

Encoder 详情

每个 encoder block 包含一个双向 self-attention 层,随后是两个 feed-forward 层。self-attention 层将输入向量投影为 queries、keys 和 values,通过 softmax 计算注意力权重,并返回 values 的加权和加上原始输入。

"每个输入向量……被投影为一个 key vector、一个 value vector 和一个 query vector……一个输出向量被定义为所有 value vectors 的加权和……加上输入向量。"

由于每个 query 都会关注所有的 keys,因此 encoder 可以在单次操作中捕捉长程依赖,并实现跨位置的全并行化。

"输出……是通过一系列矩阵乘法和 softmax 操作计算的,可以进行有效的并行化。"

一段代码片段显示,改变输入中的最后一个词会改变 encoder 对第一个 token 的表示,从而证实了上下文依赖性。

Decoder 详情

每个 decoder block 包含一个单向 self-attention 层、一个 cross-attention 层和两个 feed-forward 层。单向 self-attention 限制每个 query 只能关注其自身位置和之前的位置,从而确保自回归行为。

"在单向 self-attention 中,每个 query vector 仅与其各自的 key vector 和所有之前的 key vector 进行比较……这防止了输出向量包含任何关于后续输入向量的信息。"

随后,cross-attention 通过将 decoder 的隐藏状态作为 queries,与 encoder 的 keys 和 values 进行投影,使 decoder 的表示以完整的 encoder 输出为条件。

"cross-attention 层将其每个输入向量与所有上下文编码向量联系起来,从而使下一个目标向量的概率分布同样以 encoder 的输入为条件。"

decoder 的最后一个线性层 (LM head) 将隐藏状态映射到词表上的 logits,这些 logits 通过 softmax 转换为概率。

"'LM head' 将编码后的目标向量序列映射为一系列 logit 向量……可以通过应用 softmax 操作获得整个词表的概率分布。"

一个代码示例证明,改变给定位置之后的 decoder token 不会影响之前 token 的 logit,说明了单向 self-attention 的因果性质。

使用 🤗Transformers 进行推理

本文展示了如何使用 🤗Transformers 库使用预训练的 MarianMT 模型进行翻译,强调了 generate() 方法在内部处理编码、使用 BOS/pad token 进行 decoder 初始化以及 beam-search 解码。

"调用 .generate() 在底层执行许多操作。首先,它将 input_ids 传递给 encoder。其次,它将一个预定义的 token(即 </s> 符号)……连同编码后的 input_ids 传递给 decoder。第三,它应用 beam search 解码机制……"

提供的示例将 "I want to buy a car" 翻译成德语,输出为 Ich will ein Auto kaufen

附录:代码片段

附录包含一个极简的贪婪解码(greedy-decoding)循环,该循环手动执行 encoder 和 decoder 的调用,使用 argmax 选择下一个 token,并将其拼接至 decoder 输入,从而重现翻译的前几个单词。

"在这个代码示例中,我们展示了之前描述的内容……结果,模型生成了单词 'Ich will ein'。"

文章最后指出,读者现在对基于 Transformer 的 encoder-decoder 模型的工作原理以及如何使用 🤗Transformers 有了详细的了解,同时指出训练细节将在未来的文章中介绍。

Sources