Convolutional Sequence to Sequence Learning

ICML 2017. Facebook 2017年的卷积版seq2seq。卷积加注意力机制,外加GLU,训练速度很快,因为RNN训练时依靠上一个元素的隐藏状态,CNN可以并行训练。原文链接:Convolutional Sequence to Sequence Learning

Abstract

流行的序列到序列的学习方法将输入的序列通过循环神经网络映射到一个变长输出序列。我们提出了一个完全基于卷积神经网络的架构。对比循环神经网络模型,在训练过程中对所有元素的运算都可以并行,而且可以充分利用GPU资源,优化过程也会变得更加容易,因为非线性单元的个数是固定的,而且与输入长度无关。我们使用的门控线性单元(GLU)可以帮助梯度传播,我们在每个解码层上部署了一个独立的注意力模块。我们算法表现在WMT’14英语-德语和WMT’14英语-法语两个数据集上,都要比Wu等人的深度LSTM拥有更高的精度,且在GPU和CPU上训练速度都快了一个量级。

1. Introduction

序列到序列模型在很多任务中都大获成功,如机器翻译、语音识别(Sutskever et al., 201v4; Chorowski et al., 2015),文本摘要(Rush et al., 2015; Nallapati et al., 2016; Shen et al., 2016)等等。当今主流的方法将输入序列使用一个双向循环神经网络进行编码,并且用另一个循环神经网络生成一个变长输出序列,这两个模型通过soft-attention(Bahdanau et al., 2014; Luong et al., 2015)相连。在机器翻译中,这个架构已经比传统的基于短语的模型要好出很多了(Sennrich et al., 2016b; Zhou et al., 2016; Wu et al., 2016)。

尽管卷积神经网络有很多优点,但是很少应用在序列建模中(Waibel et al., 1989; LeCun & Bengio, 1995)。对比循环神经网络中的循环层,卷积是对定长的内容生成表示,然而,有效的卷积长度可以通过简单的堆叠卷积层变得逐渐增加。这就使得我们可以精确地控制要建模的依赖关系的最大长度。卷积神经网络不需要依赖于之前时间步的计算,因此可以在序列中的任意一个地方进行并行运算。RNN需要维持一个含有整个过去信息的隐藏状态,导致对序列进行计算时不能并行。

多层卷积神经网络在整个输入序列上构建了层次表示,在这个层次表示中,底层是临近的输入元素交互,高层是离得较远的元素交互。层级结构相比于链式结构的循环神经网络,提供了一条更短的路径来捕获长范围的依赖关系。比如,我们可以用一个滑动窗在 $n$ 个单词上,使用复杂度为 $O(\frac{n}{k})$ 的卷积操作,卷积核宽度为 $k$,来获取单词间的关系,提取到一个特征表示,如果用循环神经网络,复杂度为 $O(n)$。卷积神经网络的输入会被放入一个有着固定数目的卷积核和非线性单元的网络中,然而循环神经网络对第一个单词进行了 $n$ 次操作和非线性变换后,对最后一个单词只进行了一组操作。固定数目的非线性操作也可以简化学习过程。

最近在卷积神经网络应用于序列建模的工作,像 Bradbury et al.(2016),他们在一连串的卷积层间引入了循环池化。Kalchbrenner et al.(2016) 解决了没有注意力机制的神经机器翻译的问题。然而,这些方法的表现没有一个在大型的数据集上超越当前最先进的技术。门控卷积在之前已经被 Meng et al.(2015) 用于了机器翻译,但是他们的评估方法受限于小数据集,而且模型与传统的基于计数的模型相串联。有一部分是卷积层的架构在大数据集上展现了更好的效果但是他们的解码器仍然是循环的。

在这篇文章中,我们提出了一个针对序列到序列的模型,这个模型完全是基于卷积的。我们的模型使用了门控线性单元(Dauphin et al., 2016)和残差连接(He et al., 2015a)。我们在每个解码层也使用了注意力机制,而且显示出每个注意力层只增加了一点点可以忽略不计的开销。这些方法的融合可以让我们处理大规模的数据集。

我们在几个大型的机器翻译数据集上评估了我们的方法,并且和文章中现有的最好的架构们进行了对比与总结。在 WMT’16 英语-罗马尼亚语数据集上,我们的算法是最好的,比之前最好的结果要好 1.9 BLEU。在 WMT’14 英语-德语上,我们比 Wu et al.(2016) 的 strong LSTM 好 0.5 BLEU。在 WMT’14 英语-法语上,我们比 Wu et al.(2016) 的 likelihood trained system 好 1.6 BLEU。除此以外,我们的模型可以翻译从未见过的句子,速度比 Wu et al.(2016) 的算法在 GPU 和 CPU 上都快出一个数量级。

2. Recurrent Sequence to Sequence Learning

序列到序列建模又称基于循环神经网络的编码器-解码器架构(Sutskever et al., 2014; Bahdanau et al., 2014)。编码器 RNN 处理输入序列 $\mathbf{x} = (x_1, …, x_m)$ $m$ 个元素,返回状态表示 $\mathbf{z} = (z_1, …, z_m)$。解码器 RNN 接受 $\bf{z}$ 并且从左到右生成输出序列 $\mathbf{y} = (y_1, …, y_n)$,一次一个元素。为了生成输出 $y_{i+1}$,解码器基于之前的隐藏状态 $h_i$ ,前一个目标单词 $y_i$ 的嵌入表示 $g_i$,还有一个源自编码器输出 $\bf{z}$ 的条件输入 $c_i$,计算一个新的隐藏状态 $h_{i+1}$。基于这个大体的规则,各种各样的编码-解码架构被相继提出,他们之间主要差别是条件输入和RNN的类型不同。

没有注意力机制的模型通过对所有的 $i$ 设定 $c_i = z_m$,只考虑最后的编码状态 $z_m$(Cho et al., 2014),或是简单地将第一个解码器的隐藏状态初始化为 $z_m$(Sutskever et al., 2014),在后面这种情况中没有用到 $c_i$。带注意力机制的架构(Bahdanau et al., 2014; Luong et al., 2015)在每个时间步,计算 $(z_1, …, z_m)$ 的加权和得到 $c_i$。求和时每一项的权重称为注意力分数,可以使网络在输出序列时关注于输入序列的不同部分。注意力分数本质上是通过比较每个编码器状态 $z_j$ 和之前的解码器隐藏状态 $h_i$ 与最后的预测结果 $y_i$ 的线性组合,计算得到;结果通过归一化得到了在输入序列上的一个分布。

当前流行的编解码器使用的模型是长短时记忆网络(LSTM; Hochreiter & Schmidhuber, 1997)和门控循环单元(GRU; Cho et al., 2014)。这两个都是使用门控机制对Elman的RNN(Elman, 1990)进行了扩展,门控机制使得模型可以记得前一时间步获得的信息,以此来对长期依赖进行建模。大多数最近的方法也依赖于双向编码器对过去和未来的上下文环境同时地构建表示(Bahdanau et al., 2014; Zhou et al., 2016; Wu et al., 2016)。通常带有很多层的模型会依赖于残差网络的残差连接(He et al., 2015a; Zhou et al., 2016; Wu et al., 2016)。

3. A Convolutional Architecture

接下来我们介绍一个序列到序列的完全卷积架构。我们使用卷积神经网络替代 RNN 来计算中间的编码器状态 $\bf{z}$ 和解码器状态 $\bf{h}$。

3.1. Position Embeddings

首先,我们将输入序列 $\mathbf{x} = (x_1, …, x_m)$ 嵌入到一个分布的空间内 $\mathbf{w} = (w_1, …, w_m)$中,其中 $w_j \in \mathbb{R}^f$ 是嵌入矩阵 $\mathcal{D} \in \mathbb{R}^{V \times f}$ 的一列。我们也通过嵌入输入元素 $\mathbf{p} = (p_1, …, p_m)$ 的绝对位置使模型对顺序敏感,其中 $p_j \in \mathbb{R}^f$。这两者做加和获得输入元素的表示 $\mathbf{e} = (w_1+p_1, …, w_m+p_m)$。我们对解码器输出的元素也做相似的工作来生成输出元素表示 $\mathbf{g} = (g_1, …, g_n)$,然后再传入解码网络。位置嵌入在我们的架构中很有用,因为他们能让模型知道当前正在处理的输入或输出序列中的哪个部分。

3.2. Convolutional Block Structure

编码器和解码器网络共享一个简单的块状结构,这个块状结构会基于固定长度的输入元素计算出中间状态。我们将解码器的第 $l$ 个块的输出记为 $\mathbf{h}^l = (h^l_1, …, h^l_n)$,编码器的第 $l$ 个输出记为 $\mathbf{z}^l=(z^l_1, …, z^l_m)$;我们交替地称块和层。每个块包含一个一维卷积加一个非线性单元。对于一个有着一个块和宽度为 $k$ 的卷积核的解码网络来说,每个结果状态 $h^l_i$ 包含了过去 $k$ 个输入元素的信息。堆叠多个块增加了在一个状态中可以表示的输入元素的数量。比如,堆叠6个宽度为 $k=5$ 的块可以得到输入空间为25个元素的表示,也就是每个输出依赖于25个输入。非线性单元允许网络利用整个输入空间,或者在必要时关注更少的元素。

每个卷积核的参数为 $W \in \mathbb{R}^{2d \times kd}$,$b_w \in \mathbb{R}^{2d}$,接收的输入为 $X \in \mathbb{R}^{k \times d}$,输入是 $k$ 个输入元素嵌入到 $d$ 维空间得到的向量的拼接,然后将他们映射到一个有着输入元素维数两倍的输出元素 $Y \in \mathbb{R}^{2d}$ 上;后续的层对前一层的 $k$ 个输出元素进行操作。我们选择门控线性单元(GLU; Dauphin et al., 2016)作为非线性激活单元,这是一个在卷积 $Y=[A \ B] \in \mathbb{R}^{2d}$ 的输出上实现的一个简单的门控机制:

其中 $A, B \in \mathbb{R}^d$ 是非线性层的输入,$\otimes$ 是元素对元素相乘,输出 $v([A B]) \in \mathbb{R}^d$ 是 $Y$ 的大小的一半。门 $\sigma(B)$ 控制当前的上下文环境中哪个输入 $A$ 是相关的。一个相似的非线性单元由 Oord et al. (2016b) 提出,他们在 $A$ 上加了 $tanh$ 但是 Dauphin et al. (2016) 展示了GLUs在语言模型中表现的更好。

为了让深度卷积网络可行,我们在每个卷积的输入和块的输出间加入了残差连接(He et al., 2015a)。

对于编码器网络,我们确信卷积层的输出通过在每层增加 padding 可以匹配输入长度。然而,对于解码器网络我们需要注意对于解码器来说没有可用的未来信息(Oord et al., 2016a)。详细来说就是,我们在输入的左右两侧都加了 $k-1$ 个 0 作为 padding,并且从卷积输出的末端删除了 $k$ 个元素。

我们也在嵌入的大小 $f$ 和 卷积的输出,也就是大小为 $2d$ 的空间中做了线性映射关系。我们在将嵌入表示输入到编码器的时候,对 $\bf{w}$ 使用了这样的变换,也对编码器输出 $z^y_j$,解码器在 softmax $\bf{h^L}$ 之前的最后一层,以及计算注意力值之前的解码器的每一层$h^l$。

最后,我们计算了在 $T$ 个可能的下一个目标元素 $y_{i+1}$ 上的分布,通过将解码器最上面的输出做权重为 $W_o$ 偏置为 $b_o$ 的线性组合得到:

3.3. Multi-step Attention

我们对于每一个解码层引入了一个分开的注意力机制。为了计算注意力,我们融合了当前解码器状态$h^l_i$和前一个目标元素$g_i$的嵌入表示:

解码器层$l$的注意力$a^l_{ij}$的状态$i$和源元素$j$是通过解码器状态的汇总$d^l_i$和最后一个编码器块$u$的每个输出$z^u_j$的点乘得到:

对当前解码器层的条件输入$c^l_i$是编码器输出的加权求和,也就是输入元素嵌入$e_j$(图1,中右侧):

这与循环神经网络的方法稍有不同,在循环神经网络中,注意力和$z^u_j$的加权求和是同时计算的(This is slightly different to recurrent approaches which compute both the attention and the weighted sum over $z^u_j$ only)。我们发现加入$e_j$更有效,而且它与键值记忆网络相似,后者的键是$z^u_j$,值是$z^u_j+e_j$(Miller et al., 2016)。编码器输出$z^u_j$潜在地表达了大量的输入上下文,$e_j$提供了一个在做预测时有效的输入元素的点信息。一旦$c^l_i$被计算得出,它就会被简单的加到对应解码层$h^l_i$的输出上。
对比单步注意力机制(Bahdanau et al., 2014; Luong et al., 2015; Zhou et al., 2016; Wu et al., 2016)来说,这可以被看作是多步“跳跃”(Sukhbaater et al., 2015)的注意力机制。特别地,第一层的注意力决定了被输入到第二层的一个有效的源上下文,第二层在计算注意力的时候考虑了这个信息。解码器也可以直接获取注意力的前$k-1$步历史,因为条件输入$c^{l-1}_{i-k}, …, c^{l-1}_{i}$是$h^{l-1}_{i-k}, …, h^{l-1}_i$的一部分,而后者是$h^l_i$的输入。对于循环神经网络来说,前几步的输入在隐藏状态中,并且需要经过多个非线性单元后还保存下来,但是对于卷积的网络来说,考虑已经被加入的前几步信息更加简单。总的来说,我们的注意力机制考虑了我们之前已经加入的哪个单词,并且每个时间步都实现了多次跳跃注意力机制。在后记$C$中,我们绘制了对于深层解码器的注意力分数,显示出了不同层,被考虑的源输入的不同位置。
我们的卷积架构与RNN相比可以批量的计算一个序列的所有元素的注意力(图1,中间)。我们分别地计算了每个解码器层。

正则化的策略

我们通过小心的权重初始化稳定了学习过程$\text{\S3.5}$,并且通过缩放网络的部分使透过网络中的方差不会剧烈的变化。特别地,我们也对残差块的输出和注意力进行缩放来保持激活后的方差。我们将输入的加和和一个残差块的输出乘以了$\sqrt{0.5}$,来使和的方差减半。这假设了被加数有着相同的方差,虽说不一定总是能这样,但是在使用的时候还是很有效的。
通过注意力机制生成的条件输入$c^l_i$是$m$个向量的加权求和,我们通过缩放$m\sqrt{1/m}$抵消了在方差上的一个变化;我们假设注意力分数是均匀分布的,对输入乘以了$m$来使他从原来的大小放大。一般我们不这么干,但是我们发现在实际情况中表现得还挺好。
对于带有多个注意力机制的卷积解码器,我们根据我们的使用的注意力机制的数量对编码层的梯度进行缩放;我们排除了源单词的嵌入。我们发现这样可以稳定训练过程,因为如果不这样编码器就会接受到很大的梯度。

初始化

在对不同层的输出进行加和的时候,比如残差连接,对激活单元进行归一化时需要很小心的权重初始化。我们的初始化策略是受到了归一化的启发:保持网络前向和反向传播时激活后的值的方差。所有的嵌入表示从一个均值为0,标准差为0.1的正态分布中初始化得到。对于输出不直接输入到门控线性单元的层,我们从$\mathcal{N}(0, \sqrt{1/n_l})$中初始化权重,其中$n_l$是每个神经元输入连接数。这确保了一个均匀分布输入的方差是保持不变的。
对于通过GLU激活的层来说,我们提出了一个通过adapting the derivations in(He et al., 2015b; Glorot & Bengio, 2010; Appendix A)的初始化机制。如果GLU的输入服从均值为0的分布,并且有充分小的方差,那么我们可以用输入方差的四分之一来近似输出方差(Appendix A.1)。因此,我们初始化权重,使得GLU激活的输入有着4倍的输入的方差。这可以通过对$\mathcal{N}(0, \sqrt{r/n_l})$采样初始化得到。偏置项在网络构建时均匀的设置为0。
我们在某些层的输入使用了dropout,以便输入保持一个概率$p$。这可以看作是一个伯努利随机变量取值为$1/p$的概率为$p$,其他为0(Srivastava et al., 2014)。dropout的应用会使得方差被$1/p$缩放。我们的目标是通过使用大的权重来初始化各个层来恢复进入的方差(We aim to restore the incoming variance by initializing the respective layers with larger weights)。特别地,我们使用$\mathcal{N}(0, \sqrt{4p/n_l})$初始化那些输出会输入至GLU的层,使用$\mathcal{N}(0, \sqrt{p/n_l})$来初始化其他的。