5.3 Transformer意境级讲解

[toc]

1、前言

在之前的文章中,Attention成了深度学习模型中无处不在的方法,它是种帮助提升NMT(Neural Machine Translation)的翻译效果的思想。在本篇博客中,我们解析下Transformer,该模型扩展Attention来加速训练,并且在特定任务上 transformer 表现比 Google NMT 模型还要好。然而,其最大的好处是可并行。实际上谷歌云推荐将Transformer作为云TPU的推导模型。现在我们将Transformer拆解开来看看它是如何工作的。

Transformer是在"Attention is All You Need"中提出的,其中的TF应用是Tensor2Tensor的子模块。哈佛的NLP团队专门制作了对应的PyTorch的指南说明。本文旨在简化难度,一步一步地解释其中的概念,希望有助于初学者更容易地理解。

传统的基于 RNN 的 Seq2Seq 模型由于难以处理长序列的的句子,且因顺序性也无法并行处理。而完全基于 CNN 的 Seq2Seq 模型虽然可以实现并行化,但是非常耗内存。

传统 Attention

  • 方法:基于源端和目标端的隐向量计算Attention,
  • 结果:源端每个词与目标端每个词间的依赖关系 【源端->目标端】
  • 问题:忽略了 远端或目标端 词与词间 的依赖关系

Self-attention,也称为 intra-attention,是一种将序列的不同位置联系起来并计算序列表示的注意力机制。Self-attention 已成功应用于各个任务中,包括阅读理解、摘要生成、句子表示等任务中。

而本文介绍的 Transformer 是一个完全使用 Self-attention 的模型,即解决了计算量和并行效率的问题,又提高了实验的结果。

2、Transformer 整体概念

我们先将整个Transformer 模型视为黑盒,比如在机器翻译中,接收一种语言的句子作为输入,然后将其翻译成其他语言输出。

5.3 Transformer意境级讲解

细看下,其中由编码组件、解码组件和它们之间的连接层组成。

5.3 Transformer意境级讲解

编码组件是六层编码器首位相连堆砌而成,解码组件也是六层解码器堆成的。

5.3 Transformer意境级讲解

编码器是完全结构相同的,但是并不共享参数,每一个编码器都可以拆解成以下两个字部分。

5.3 Transformer意境级讲解

编码器的输入首先流过一个self-attention层,该层帮助编码器能够看到输入序列中的其他单词当它编码某个词时。后面,我们会细看self-attention的内部结构。

self-attention的输出流向一个前向网络,每个输入位置对应的前向网络是独立互不干扰的。

解码器同样也有这些子层,但是在两个子层间增加了attention层,该层有助于解码器能够关注到输入句子的相关部分,与seq2seq model的Attention作用相似。

5.3 Transformer意境级讲解

3、如何工作

3.1、输入

现在,我们解析下模型最主要的组件,从向量/Tensor开始,然后是它们如何流经各个组件们并输出的。 正如NLP应用的常见例子,先将输入单词使用 “词嵌入”转成向量。

5.3 Transformer意境级讲解

词的向量化仅仅发生在最底层的编码器的输入时,这样每个编码器的都会接收到一个list(每个元素都是512维的词向量),只不过其他编码器的输入是前个编码器的输出。list的尺寸是可以设置的超参,通常是训练集的最长句子的长度。

在对输入序列做词的向量化之后,它们流经编码器的如下两个子层。

5.3 Transformer意境级讲解

这里能看到Transformer的一个关键特性,每个位置的词仅仅流过它自己的编码器路径。在self-attention层中,这些路径两两之间是相互依赖的。Feed Forward网络层则没有这些依赖性,但这些路径在流经Feed Forward网络时可以并行执行

接下来,我们将把这个例子转换成一个更短的句子,我们将看看在编码器的每个子层中发生了什么。

3.2、编码器

正如之前所提,编码器接收向量的list作输入。然后将其送入self-attention处理,再之后送入前馈网络,最后将输入传入下一个编码器。

5.3 Transformer意境级讲解

每个位置的词向量被送入self-attention模块,然后是前馈网络(对每个向量都是完全相同的网络结构)

4、Self-Attention 工作流程

不要被self-attention这个词迷惑了,看起来好像每个人对它都很熟悉,但是在我读到Attention is All You Need这篇文章之前,我个人都没弄懂这个概念。下面我们逐步分解下它是如何工作的。

以下面这句话为例,作为我们想要翻译的输入语句“

The animal didn’t cross the street because it was too tired”。

句子中"it"指的是什么呢?“it"指的是"street” 还是“animal”?对人来说很简单的问题,但是对算法而言并不简单。

当模型处理单词“it”时,self-attention允许将“it”和“animal”联系起来。

当模型处理每个位置的词时,self-attention允许模型看到句子的其他位置信息作辅助线索来更好地编码当前词。如果你对RNN熟悉,就能想到RNN的隐状态是如何允许之前的词向量来解释合成当前的词向量。Transformer使用self-attention来将相关词的理解编码到当前词中。

5.3 Transformer意境级讲解

当编码"it"时(编码器的最后层输出),部分attention集中于"the animal",并将其表示合并进入到“it”的编码中。

上图是Tensor2Tensor notebook的可视化例子

4.1、Self-Attention的计算

我们先看下如何计算self-attention的向量,再看下如何以矩阵方式计算。

第一步,根据编码器的输入向量,生成三个向量,比如,对每个词向量,生成query-vec, key-vec, value-vec,这些向量是单词的 Embedding 分别与对应的查询矩阵 $W^Q$ 、键矩阵$W^K$ 和值矩阵 $W^V$相乘得来的。,这些矩阵在训练过程中需要学习。【注意:不是每个词向量独享3个matrix,而是所有输入共享3个转换矩阵;权重矩阵是基于输入位置的转换矩阵

注意到这些新向量的维度比输入词向量的维度要小(512–>64),它们的维数为64,而嵌入向量和编码器输入/输出向量的维数为512。它们不必更小,这是一种结构选择,可以使多头注意力(主要)的计算保持不变。

5.3 Transformer意境级讲解

x1乘以WQ权重矩阵产生q1,即与该单词相关的“查询”向量。我们最终为输入句子中的每个单词创建一个“queries”、一个“keys”和一个“values”投影。

所谓的query/key/value是什么?

它们是对计算和思考attention很有用的抽象概念。一旦你继续阅读下面的注意力是如何计算的,你就会知道你需要知道的关于这些向量所扮演的角色。

第二步,计算self-attention就是计算一个分值。对“Thinking Matchines”这句话,对“Thinking”计算attention 分值。我们需要根据这个单词给输入的句子中的每个单词打分.分数决定了当我们在某个位置对一个单词进行编码时,对输入句子其他部分的关注程度。

这个分,通过“Thinking”对应queries向量与我们打分的单词的keys向量的点积来计算的。所以当我们处理位置#1Thinking 时,第一个分值是q1和k1的点积,第二个分值是q1和k2的点积。

(也可以理解为当前单词的是由句子的所有单词加权求和得到的,现在计算的是当前单词和其他单词的分数,这个分数将用于后面计算各个单词对当前单词的贡献权重。)

5.3 Transformer意境级讲解

第三步和第四步,除以8 $(=\sqrt{dim_{key}}(dim_{key}:key的维度))$ ,这样梯度会更稳定。然后加上softmax操作,归一化分值使得全为正数且加和为1。

5.3 Transformer意境级讲解

softmax分值决定着在这个位置,每个词的表达程度(关注度)。很明显,这个位置的词应该有最高的softmax分数,但有时关注与当前单词相关另一个单词是有用的。

经过 Softmax 后的分数决定了序列中每个单词在当前位置的表达量(如,对着 Thinking 这个位置来说,= 0.88 * Thinking + 0.12 * Machines)。Softmax 分数越高表示与当前单词的相关性更大。

第五步,将softmax分值与values按位相乘。这里的直觉是保持我们想要关注的单词的值不变,而忽略不相关的单词(例如,通过将它们乘以极小的数字,如0.001)。值。

第六步,对加权值向量进行求和,产生该位置的self-attention的输出结果。

5.3 Transformer意境级讲解

上述就是self-attention的计算过程,生成的向量流入Feed Forward网络。

在实际应用中,上述计算是以速度更快的矩阵形式进行的。下面我们看下在单词级别的矩阵计算。

4.2、Self-Attention矩阵计算

第一步,计算query/key/value matrix,将所有输入词向量合并成embedding矩阵 $X$ ,并且将其分别乘以权重矩阵

5.3 Transformer意境级讲解

X矩阵中的每一行对应于输入句子中的一个单词。我们再次看到嵌入向量(512,图中4个盒子)和q/k/v向量(64,图中3个盒子)的大小差异。

最后,鉴于我们使用矩阵处理,将步骤2~6合并成一个计算self-attention层输出的公式。

5.3 Transformer意境级讲解

上图是Transformer中self-attention的计算过程。其实在Transformer中,Q,K,V指的都是输入序列乘上不同的权重$W_Q,W_K,W_V$。

该编码过程的一个特点是,在编码序列中的某一个词时,让该词充分的与序列中的其他词进行运算,从而能够得到该词与序列中所有词的句法和语义关系编码

该编码过程的另外一个重要的特点是,序列是并行输入的,因此运算效率很高

self-attention 如何并行化?

  • Transformer 如何进行并行化?
    • 为什么 RNN 不能并行化:
      • 原因:RNN 在 计算 $x_i$ 的时候,需要考虑到 $x_1 ~ x_{i-1}$ 的 信息,使得 RNN 只能 从 $x_1$ 计算到 $x_i$;
    • 思路:
      • 在 self-attention 能够 并行的 计算 句子中不同 的 query,因为每个 query 之间并不存在 先后依赖关系,也使得 transformer 能够并行化;

4.3、multi-headed的应用

论文进一步增加了multi-headed的机制到self-attention上,在如下两个方面提高了attention层的效果:

  1. 多头机制扩展了模型集中于不同位置的能力。极大的增强了模型的序列编码能力,特别是序列内词之间关系的语义表征能力。这个可以这样去想,假如只有一个头的话,因为是self-attention,在计算过程中,很有可能该词与该词的的计算结果可能会比较大,从而词与自身的运算占据了很大的影响。如果引入多头机制,不同的权重,则可以避免这种弊端,增强模型的编码能力。在上面的例子中,z1只包含了其他词的很少信息,仅由实际自己词决定。在其他情况下,比如翻译 “The animal didn’t cross the street because it was too tired”时,我们想知道单词"it"指的是什么。
  2. 多头机制赋予attention多种子表达方式。实现了Attention的多个表征子空间。这样的好处是,每个子空间可以表征序列不同方面语义信息。像下面的例子所示,在多头下有多组query/key/value-matrix,而非仅仅一组(论文中使用8-heads)。每一组都是随机初始化,经过训练之后,输入向量可以被映射到不同的子表达空间中。

5.3 Transformer意境级讲解

在多头注意中,我们为每个头保持单独的Q/K/V权矩阵,从而得到不同的Q/K/V矩阵。正如我们之前所做的,我们用X乘以WQ/WK/WV矩阵得到Q/K/V矩阵。

如果我们计算multi-headed self-attention的,分别有八组不同的Q/K/V matrix,我们得到八个不同的矩阵。

5.3 Transformer意境级讲解

这给我们带来了一些挑战。前馈层期望的不是八个矩阵,而是一个矩阵(每个单词对应一个向量)。所以我们需要一种方法把这8个压缩成一个矩阵。

我们怎么做呢?我们对矩阵进行concat,然后将它们乘以一个额外的权值矩阵$W^O$。

5.3 Transformer意境级讲解

上述就是Multi-Head Attention 的内容,我认为还仅是一部分矩阵,下面尝试着将它们放到一个图上可视化如下。

5.3 Transformer意境级讲解

现在加入Multi-Head Attention之后,让我们重新回顾一下之前的例子,看看当句子中对单词“it”进行编码时,不同的attention head都集中在哪里:

5.3 Transformer意境级讲解

当我们对单词“it”进行编码时,一个Attention集中在“animal”上,而另一个Attention则集中在“tire”上——从某种意义上说,模型对“it”的表示同时包含了“animal”和“tire”的一些表示。

如果我们将所有的attention heads都放入到图中,就很难直观地解释了。

5.3 Transformer意境级讲解

5、 位置编码

截止到目前为止,我们还没有讨论如何理解输入语句中词的顺序。

transformer模型中缺少一种解释输入序列中单词顺序的方法,它跟序列模型还不不一样。为了处理这个问题,transformer给encoder层和decoder层的输入“词嵌入”添加了一个额外的向量Positional Encoding,维度和embedding的维度一样,这个向量采用了一种很独特的方法来让模型学习到这个值,这个向量能决定当前词的位置,或者说在一个句子中不同的词之间的距离。这个位置向量的具体计算方法有很多种,论文中的计算方法如下:

5.3 Transformer意境级讲解

其中pos是指当前词在句子中的位置,i是指向量中每个值的index,可以看出,在偶数位置,使用正弦编码,在奇数位置,使用余弦编码

直觉上,在嵌入向量被投影到Q/K/V向量和点积注意时,将这些值添加到嵌入向量中可以提供嵌入向量之间有意义的距离

最后把这个Positional Encoding与embedding的值相加,作为输入送到下一层。

5.3 Transformer意境级讲解

为了让模型了解单词的顺序,我们添加位置encoding向量——其值遵循指定的模式

如果假设位置向量有4维,实际的位置向量将如下所示:

5.3 Transformer意境级讲解

一个只有4维的位置向量表示例子

所谓的指定模式是什么样的呢?

在下面的图中,每一行对应一个向量的位置编码。因此,第一行将是我们要添加的向量,用于嵌入输入序列中的第一个单词。每行包含512个值—每个值在1到-1之间。我们用颜色标记了它们,这样图案就清晰可见了。

5.3 Transformer意境级讲解

这是对20个单词(行)进行位置编码的真实示例,嵌入大小为512(列)。你可以看到它从中间一分为二。这是因为左半部分的值由一个函数(使用正弦)生成,而右半部分的值由另一个函数(使用余弦)生成。然后它们被连接起来形成每个位置编码向量。

位置向量编码方法在论文的3.5节有提到,也可以看代码get_timing_signal_ld(),对位置编码而言并不只有一种方法。然而,它的优势在于能够伸缩到序列中看不到的长度(例如,如果我们的训练模型被要求翻译一个比我们训练集中的任何一个都长的句子)。

上面显示的位置编码来自转换器的Tranformer2Transformer实现。文中给出的方法略有不同,它不是直接连接,而是将两个信号交织在一起。下图显示了它的样子。生成它的代码:

5.3 Transformer意境级讲解

6、残差

编码器结构中值得提出注意的一个细节是,在每个子层中(slef-attention, Feed Forward),都有残差连接Feed Forward,并且紧跟着layer-normalization

5.3 Transformer意境级讲解

这个虚线其实就是一个残差,为了防止出现梯度消失或者梯度爆炸问题。而 Add & Normalize 是指将上一层传过来的数据和通过残差结构传过来的数据相加,并进行归一化:

5.3 Transformer意境级讲解

上图是Transformer中,第一个sub-layer的结构示意图。其特别之处只有输入接收的为字向量和位置编码的和,其他sub-layer的输入为上一层sub-layer的输出.

LAdd & Normalize。Normalize是什么?

  • 动机:因为 transformer 堆叠了 很多层,容易 梯度消失或者梯度爆炸;
  • 原因:
    • 数据经过该网络层的作用后,不再是归一化,偏差会越来越大,所以需要将数据重新做归一化处理;
  • 目的:
    • 在数据送入激活函数之前进行Normalize(归一化)之前,需要将输入的信息利用 Normalize转化成均值为0方差为1的数据,避免因输入数据落在激活函数的饱和区而出现梯度消失或者梯度爆炸问题
  • 介绍:
    • 归一化的一种方式
    • 对每一个样本介绍均值和方差【这个与 BN 有所不同,因为他是在 批方向上 计算均值和方差】
  • 公式

BN 计算公式 $$ B N\left(x_{i}\right)=\alpha \times \frac{x_{i}-\mu_{b}}{\sqrt{\sigma_{B}^{2}+\epsilon}}+\beta \

$$ LN 计算公式

$$ \begin{array}{l} L N\left(x_{i}\right)=\alpha \times \frac{x_{i}-\mu_{L}}{\sqrt{\sigma_{L}^{2}+\epsilon}}+\beta \end{array} $$

在解码器中也是如此,假设两层编码器+两层解码器组成Transformer,其结构如下:

5.3 Transformer意境级讲解

7、前馈网络

每一个sub-layer还会接一个Feed-forward Neural Network(FNN),FNN的计算公式如下: $$ \operatorname{FFN}(x)=\max \left(0, x W_{1}+b_{1}\right) W_{2}+b_{2} $$ 即在每个sub-layer,针对self-Attention层的输出,先使用一个线性变换,再针对该线性变换的输出使用RELU函数,最后再针对RELU函数的输出使用一个线性变化。那么,做这么繁琐的变换有什么意义呢?

我们将FNN与CNN做对比,其实可以发现,其效果与加上一层卷积核大小为11的CNN是一样的。那么这就好理解了,这层所谓的FNN其实也是做*特征提取**的。

  • FFN 将每个位置的Multi-Head Attention结果映射到一个更大维度的特征空间,然后使用ReLU引入非线性进行筛选,最后恢复回原始维度。
  • Transformer在抛弃了 LSTM 结构后,FFN 中的 ReLU成为了一个主要的提供非线性变换的单元。

8、Decoder层结构

根据上面的总体结构图可以看出,decoder部分其实和encoder部分大同小异,刚开始也是先添加一个位置向量Positional Encoding,接下来接的是masked mutil-head attetion,这里的mask也是transformer一个很关键的技术,下面我们会进行一一介绍。

其余的层结构与Encoder一样,请参考Encoder层结构。

8.1、 masked mutil-head attetion

mask 表示掩码,它对某些值进行掩盖,使其在参数更新时不产生效果。Transformer 模型里面涉及两种 mask,分别是 padding mask 和 sequence mask。其中,padding mask 在所有的 scaled dot-product attention 里面都需要用到,而 sequence mask 只有在 decoder 的 self-attention 里面用到。

  1. padding mask 什么是 padding mask 呢?因为每个批次输入序列长度是不一样的也就是说,我们要对输入序列进行对齐。具体来说,就是给在较短的序列后面填充 0。但是如果输入的序列太长,则是截取左边的内容,把多余的直接舍弃。因为这些填充的位置,其实是没什么意义的,所以我们的attention机制不应该把注意力放在这些位置上,所以我们需要进行一些处理。 具体的做法是,把这些位置的值加上一个非常大的负数(负无穷),这样的话,经过 softmax,这些位置的概率就会接近0! 而我们的 padding mask 实际上是一个张量,每个值都是一个Boolean,值为 false 的地方就是我们要进行处理的地方。
  2. Sequence mask 文章前面也提到,sequence mask 是为了使得 decoder 不能看见未来的信息。也就是对于一个序列,在 time_step 为 t 的时刻,我们的解码输出应该只能依赖于 t 时刻之前的输出,而不能依赖 t 之后的输出。因此我们需要想一个办法,把 t 之后的信息给隐藏起来。 那么具体怎么做呢?也很简单:产生一个上三角矩阵,上三角的值全为0。把这个矩阵作用在每一个序列上,就可以达到我们的目的
  • 对于 decoder 的 self-attention,里面使用到的 scaled dot-product attention,同时需要padding mask 和 sequence mask 作为 attn_mask,具体实现就是两个mask相加作为attn_mask。
  • 其他情况,attn_mask 一律等于 padding mask。

8.1、encoder 和 Decoder 共同工作

现在我们已经了解了编码器侧的大部分概念,也基本了解了解码器的工作方式,下面看下他们是如何共同工作的。 编码器从处理输入序列开始。然后将顶部编码器的输出转化为一组Attention向量K和v,每个解码器在其“encoder-decoder atttention”层中使用这些Attention向量K和v,这有助于解码器将注意力集中在输入序列中相应的位置:

5.3 Transformer意境级讲解

完成编码阶段后,我们开始解码阶段。解码阶段的每一步都输出一个元素作输出序列(本例中是英语翻译句)。

下面的步骤一直重复直到一个特殊符号出现表示解码器完成了翻译输出。每一步的输出被喂到下一个解码器中。正如编码器的输入所做的处理,对解码器的输入增加位置向量。

5.3 Transformer意境级讲解

在解码器中的self attention 层与编码器中的稍有不同,在解码器中,self-attention 层仅仅允许关注早于当前输出的位置。在softmax之前,通过遮挡未来位置(将它们设置为-inf)来实现。

"Encoder-Decoder Attention "层工作方式跟multi-headed self-attention是一样的,除了一点,它从前一层获取输出转成query矩阵,key和value矩阵接收最后层编码器的。

9、Output层

解码器最后输出浮点向量,如何将它转成词?这是最后的线性层和softmax层的主要工作。

线性层是一个简单的全连接网络,它将解码器堆栈产生的向量投射到一个更大的向量中,称为logits向量。

假设模型已知有1万个单词(输出的词表)从训练集中学习得到。那么,logits向量就有1万维,每个值表示是某个词的可能倾向值。

softmax层将这些分数转换成概率值(都是正值,且加和为1),最高值对应的维上的词就是这一步的输出单词。

5.3 Transformer意境级讲解

10、Training

现在我们已经了解了一个训练完毕的Transformer的前向过程,顺道看下训练的概念也是非常有用的。

在训练时,模型将经历上述的前向过程,当我们在标记训练集上训练时,可以对比预测输出与实际输出。 为了可视化,假设输出一共只有6个单词(“a”, “am”, “i”, “thanks”, “student”, “”)

5.3 Transformer意境级讲解

模型的词表是在训练之前的预处理中生成的

一旦定义了词表,我们就能够构造一个同维度的向量来表示每个单词,比如one-hot编码,下面举例编码“am”。

5.3 Transformer意境级讲解

举例采用one-hot编码输出词表

下面让我们讨论下模型的loss损失,在训练过程中用来优化的指标,指导学习得到一个非常准确的模型。

10.1、The Loss Function

我们用一个简单的例子来示范训练,比如翻译“merci”为“thanks”。那意味着输出的概率分布指向单词“thanks”,但是由于模型未训练是随机初始化的,不太可能就是期望的输出。

5.3 Transformer意境级讲解

由于模型参数是随机初始化的,未训练的模型输出随机值。我们可以对比真实输出,然后利用误差后传调整模型权重,使得输出更接近与真实输出

如何对比两个概率分布呢?简单采用cross-entropy或者Kullback-Leibler divergence中的一种。

鉴于这是个极其简单的例子,更真实的情况是,使用一个句子作为输入。比如,输入是“je suis étudiant”,期望输出是“i am a student”。在这个例子下,我们期望模型输出连续的概率分布满足如下条件:

1 每个概率分布都与词表同维度。

2 第一个概率分布对“i”具有最高的预测概率值。

3 第二个概率分布对“am”具有最高的预测概率值。

4 一直到第五个输出指向""标记。

5.3 Transformer意境级讲解

对一个句子而言,训练模型的目标概率分布

在足够大的训练集上训练足够时间之后,我们期望产生的概率分布如下所示:

5.3 Transformer意境级讲解

训练好之后,模型的输出是我们期望的翻译。当然,这并不意味着这一过程是来自训练集。注意,每个位置都能有值,即便与输出近乎无关,这也是softmax对训练有帮助的地方。

现在,因为模型每步只产生一组输出,假设模型选择最高概率,扔掉其他的部分,这是种产生预测结果的方法,叫做greedy 解码。

另外一种方法是beam search,每一步仅保留最头部高概率的两个输出,根据这俩输出再预测下一步,再保留头部高概率的两个输出,重复直到预测结束。top_beams是超参可试验调整。

11、总结

前面大概讲述了Transformer的结构及其每个sub-layer的组成。那么我们再来讨论一下,Transformer到底是什么?

我们可不可以这样说,Transformer其实是一个用于对序列输入进行特征编码的工具。它以self-Attention机制为基础,从而能够编码序列输入的语义信息,对序列输入内不同词之间的关系也具有较强的编码能力,特别是Multi-Attention的引入,极大的增强了其编码能力。同时,Transformer内其实还有CNN的影子,尽管原作者避免提及。并且,因为其结构上的优势,像CNN一样,Transformer天然就能够并行计算,这一点是RNN等模型无法具备的。

缺点

缺点在原文中没有提到,是后来在Universal Transformers中指出的,在这里加一下吧,主要是两点:

  1. 实践上:有些rnn轻易可以解决的问题transformer没做到,比如复制string,或者推理时碰到的sequence长度比训练时更长(因为碰到了没见过的position embedding)

  2. transformers非computationally universal(图灵完备),(我认为)因为无法实现“while”循环

    • 在Transformer中,单层中sequential operation (context two symbols需要的操作数)是$O(1)$ time,独立于输入序列的长度。那么总的sequenctial operation仅由层数$T$决定。这意味着transformer不能在计算上通用,即无法处理某些输入。如:输入是一个需要对每个输入元素进行顺序处理的函数,在这种情况下,对于任意给定的深度$T$的transformer,都可以构造一个长度为 $N>T$;
  3. 不能很好的处理超长输入问题

    • 例如 在 Bert 里面,输入句子的默认长度 为 512;
    • 处理方式一:截断句子方式(Transformer 处理方式);
    • 处理方式二:将句子划分为 多个 seg (Vanilla Transformer 处理方式);
    • 处理方式三:Segment-Level Recurrenc ( Transformer-XL 处理方式);
  4. 缺少Recurrent Inductive Bias

    学习算法中Inductive Bias可以用来预测从未遇到的输入的输出(参考[10])。对于很多序列建模任务(如需要对输入的层次结构进行建模时,或者在训练和推理期间输入长度的分布不同时),Recurrent Inductive Bias至关重要【可以看论文The Importance of Being Recurrent for Modeling Hierarchical Structure

  5. transformer缺少conditional computation

    transformer在encoder的过程中,所有输入元素都有相同的计算量,比如对于“I arrived at the bank after crossing the river", 和"river"相比,需要更多的背景知识来推断单词"bank"的含义,然而transformer在编码这个句子的时候,无条件对于每个单词应用相同的计算量,这样的过程显然是低效的。

  6. transformer 时间复杂度 和 空间复杂度 过大问题

    Transformer 中用到的自注意力与长度n呈现出$O(n^2)$的时间和空间复杂度

    解决方法:

Go Forth And Transform

希望本文能够帮助读者对Transformer的主要概念理解有个破冰效果,如果想更深入了解,建议如下步骤:

1 阅读 Attention Is All You Needpaper,Transformer的博客文章Transformer: A Novel Neural Network Architecture for Language UnderstandingTensor2Tensor使用说明。

2 观看"Łukasz Kaiser’s talk",梳理整个模型及其细节。

3 耍一下项目Jupyter Notebook provided as part of the Tensor2Tensor repo

4 尝试下项目Tensor2Tensor

参考

  1. Depthwise Separable Convolutions for Neural Machine Translation
  2. One Model To Learn Them All
  3. Discrete Autoencoders for Sequence Models
  4. Generating Wikipedia by Summarizing Long Sequences
  5. Image Transformer
  6. Training Tips for the Transformer Model
  7. Self-Attention with Relative Position Representations
  8. Fast Decoding in Sequence Models using Discrete Latent Variables
  9. Adafactor: Adaptive Learning Rates with Sublinear Memory Cost
  10. https://jalammar.github.io/illustrated-transformer/
  11. https://zhuanlan.zhihu.com/p/44121378
  12. https://www.zhihu.com/question/20115374/answer/288346717
  13. https://zhuanlan.zhihu.com/p/106867810
  14. https://github.com/km1994/nlp_paper_study
上一篇:【TensorFlow】Seq2Seq模型的代码实现 & attention机制


下一篇:python查询修改配置文件功能