1. 简介

seq2seq 是一个 Encoder–Decoder 结构的网络,它的输入是一个序列,输出也是一个序列, Encoder 中将一个可变长度的信号序列变为固定长度的向量表达,Decoder 将这个固定长度的向量变成可变长度的目标的信号序列。这个结构最重要的地方在于输入序列和输出序列的长度是可变的,可以用于翻译,聊天机器人,句法分析,文本摘要等。
seq2seq及注意力机制
Encoder-Decoder结构先将输入数据编码成一个上下文向量c。得到c有多种方式,最简单的方法就是把Encoder的最后一个隐状态赋值给c,还可以对最后的隐状态做一个变换得到c,也可以对所有的隐状态做变换
seq2seq及注意力机制
拿到c之后,就用另一个RNN网络对其进行解码,这部分RNN网络被称为Decoder。具体做法就是将c当做之前的初始状态h0h_0输入到Decoder中
seq2seq及注意力机制
还有一种做法是将c当做每一步的输入
seq2seq及注意力机制

2.编码器Encoder

编码器的作⽤是把⼀个不定⻓的输⼊序列变换成⼀个定⻓的背景变量c, 常⽤的编码器是循环神经⽹络。考虑批量⼤⼩为1的时序数据样本。假设输⼊序列是x1,x2,...,xTx_1, x_2,...,x_T ,例如 xix_i 是输入句子中的第ii个词。在时间步tt,循环神经网络将输入 xtx_t 的特征向量和上个时间步的隐藏状态 ht1h_{t-1} 变换为当前时间步的隐藏状态 hth_t
ht=f(xt,ht1)h_t=f(x_t, h_{t-1})
编码器通过⾃定义函数 qq 将各个时间步的隐藏状态变换为背景变量
c=q(h1,h2,...,hT)c=q(h_1, h_2, ..., h_T)
当选择 q(h1,h2,...,hT)=hTq(h_1, h_2, ..., h_T)=h_T 时,背景变量是输⼊序列最终时间步的隐藏状态 hTh_T

3.解码器Decoder

给定训练样本中的输出序列y1,y2,...,yTy_1, y_2, ..., y_T,对每个时间步 tt 解码器输出 yty_t 的条件概率将基于之前的输出序列y1,y2,...,yt1y_1, y_2, ..., y_{t-1}和背景变量cc,即P(yty1,y2,...,yt1,c)P(y_t|y_1, y_2, ..., y_{t-1}, c)

为此,我们可以使⽤另⼀个循环神经⽹络作为解码器,在输出序列的时间步 tt,解码器将上⼀时间步的输出 yt1y_{t-1} 以及背景变量 cc 作为输⼊,并将它们与上⼀时间步的隐藏状态 st1s_{t-1} 变换为当前时间步的隐藏状态 sts_t。即:
st=g(yt1,c,st1)s_t = g(y_{t-1}, c, s_{t-1})
有了解码器的隐藏状态后,我们可以使⽤⾃定义的输出层和 softmax 运算来计算输出P(y_t|y_1, y_2, …, y_{t-1}, c)

4. 训练模型

根据最⼤似然估计,我们可以最⼤化输出序列基于输⼊序列的条件概率
P(y1,,yTx1,,xT)=t=1TP(yty1,,yt1,x1,,xT)=t=1TP(yty1,,yt1,c)\begin{aligned} P\left(y_{1}, \ldots, y_{T^{\prime}} | x_{1}, \ldots, x_{T}\right) &=\prod_{t^{\prime}=1}^{T^{\prime}} P\left(y_{t^{\prime}} | y_{1}, \ldots, y_{t^{\prime}-1}, x_{1}, \ldots, x_{T}\right) \\ &=\prod_{t^{\prime}=1}^{T^{\prime}} P\left(y_{t^{\prime}} | y_{1}, \ldots, y_{t^{\prime}-1}, \boldsymbol{c}\right) \end{aligned}
并得到该输出序列的损失
logP(y1,,yTx1,,xT)=t=1TlogP(yty1,,yt1,c)-\log P\left(y_{1}, \ldots, y_{T^{\prime}} | x_{1}, \ldots, x_{T}\right)=-\sum_{t^{\prime}=1}^{T^{\prime}} \log P\left(y_{t^{\prime}} | y_{1}, \ldots, y_{t^{\prime}-1}, \boldsymbol{c}\right)
在模型训练中,所有输出序列损失的均值通常作为需要最⼩化的损失函数;在训练中我们也可以将标签序列(训练集的真实输出序列)在上⼀个时间步的标签作为解码器在当前时间步的输⼊。这叫作强制教学(teacher forcing)。而在测试的时候因为不知道标签,因此将上一时刻的输出作为当前时刻的输入。

5. 束搜索

假设解码器的输出是⼀段⽂本序列。设输出⽂本词典 VV(包含特殊符号" <eos> ")的⼤⼩为V|V|,输出序列的最⼤⻓度为 T,所有可能的输出序列⼀共有O(VT)O(|V|^T)种,我们需要找出使得P(y1,,yTx1,,xT)=t=1TP(yty1,,yt1,c)P\left(y_{1}, \ldots, y_{T^{\prime}} | x_{1}, \ldots, x_{T}\right)=\prod_{t^{\prime}=1}^{T^{\prime}} P\left(y_{t^{\prime}} | y_{1}, \ldots, y_{t^{\prime}-1}, \boldsymbol{c}\right)最大的输出序列y1,y2,...,yTy_1, y_2, ...,y_T

5.1 贪婪搜索

对每一次的输出,都使得P(yty1,y2,...,yt1,c)P(y_t|y_1, y_2, ..., y_{t-1}, c)最大,此方法主要问题是不能保证得到最优输出序列,即使得P(y1,,yTx1,,xT)P\left(y_{1}, \ldots, y_{T^{\prime}} | x_{1}, \ldots, x_{T}\right)最大,如下例子
seq2seq及注意力机制
seq2seq及注意力机制

5.2 穷举搜索

穷举所有可能的输出序列,输出条件概率最⼤的序列;穷举搜索可以得到最优输出序列,但它的计算开销 O(VT)O(|V|^T) 很容易过⼤;⽽贪婪搜索的计算开销是O(TV)O(T|V|)

5.3 束搜索

束搜索(beam search)是对贪婪搜索的⼀个改进算法。它有⼀个束宽(beam size)超参数。我们将它设为 kk。在时间步1时,选取当前时间步条件概率最⼤的 kk 个词,分别组成 kk 个候选输出序列的⾸词。在之后的每个时间步,基于上个时间步的 kk 个候选输出序列,从 kVk|V|个可能的输出序列中选取条件概率最⼤的 kk 个(词),作为该时间步的候选输出序列。最终,我们从各个时间步的候选输出序列中筛选出包含特殊符号“<eos>”的序列,并将它们中所有特殊符号“<eos>”后⾯的⼦序列舍弃,得到最终候选输出序列的集合。
seq2seq及注意力机制
上图头通过一个例子演示了束搜索的过程。假设输出序列的词典中只包含 5 个元素,即
V={A,B,C,D,E}V=\{A, B, C, D, E\},且其中⼀个为特殊符号“<eos>”。设束搜索的束宽等于2,输出序列最⼤⻓度为3。在输出序列的时间步1时,假设条件概率 P(y1c)P(y_1|c) 最⼤的2个词为AACC 。我们在时间步2时将对所有的 y2Vy_2 \in V都分别计算P(y2A,c)P(y_2|A, c)P(y2C,c)P(y_2|C, c),并从计算出的10个条件概率中取最⼤的2个,假设为P(BA,c)P(B|A, c)P(EC,c)P(E|C,c);那 么 , 我 们 在 时 间 步 3 时将对所有的 y3Vy_3 \in V都 分 别 计 算 P(y3A,B,c)P(y_3|A, B, c)P(y3C,E,c)P(y_3|C, E, c)并 从 计 算 出 的 10 个条件概率中取最⼤的 2 个,假设为P(DA,B,c)P(D|A, B, c)P(DC,E,c)P(D|C, E, c);如此⼀来,我们得到6个候选输出序列:(1) A ; (2) C ; (3) A, B; (4) C, E ; (5) A, B, D; (6) C E D我们将根据这6个序列得出最终候选输出序列的集合。

在最终候选输出序列的集合中,我们取以下分数最⾼的序列作为输出序列:
1LαlogP(y1,,yL)=1Lαt=1LlogP(yty1,,yt1,c)\frac{1}{L^{\alpha}} \log P\left(y_{1}, \ldots, y_{L}\right)=\frac{1}{L^{\alpha}} \sum_{t^{\prime}=1}^{L} \log P\left(y_{t^{\prime}} | y_{1}, \ldots, y_{t^{\prime}-1}, \boldsymbol{c}\right)
其中 LL 为最终候选序列⻓度,α\alpha⼀般可选为0.75;分⺟上的 LαL^\alpha是为了惩罚较⻓序列在以上分数中较多的对数相加项,束搜索的计算开销为O(kVT)O(k|V|T) 。这介于贪婪搜索和穷举搜索的计算开销之间。此外,贪婪搜索可看作是束宽为1的束搜索。束搜索通过灵活的束宽 kk 来权衡计算开销和搜索质量。

6 注意力机制

上文中,解码器在各个时间步依赖相同的背景变量来获取输⼊序列信息。当编码器为循环神经⽹络时,背景变量来⾃它最终时间步的隐藏状态或者各个时间步隐藏状态的变换(即背景向量是一个固定的向量)。很明显这样做有两个缺点
(1)中间语义向量无法完全表达整个输入序列的信息
(2)随着输入信息长度的增加,由于向量长度固定,先前编码好的信息会被后来的信息覆盖,丢失很多信息

为了解决上面两个问题,于是引入了 Attention 模型。Attention机制通过在每个时间输入不同的c来解决这个问题;仍然以循环神经⽹络为例,注意⼒机制通过对编码器所有时间步的隐藏状态做加权平均来得到背景变量。解码器在每⼀时间步调整这些权重,即注意⼒权重,从⽽能够在不同时间步分别关注输⼊序列中的不同部分并编码进相应时间步的背景变量。从上文分析中可知,解码器在时间步tt时隐藏状态为st=g(yt1,st1,c)s_t = g(y_{t-1}, s_{t-1}, c),而在带注意力机制的情况下,每个时间步输入的cc不同,因此带注意力机制的解码器时间步tt的隐藏状态为st=g(yt1,st1,ct)s_t = g(y_{t-1}, s_{t-1}, c_t)。这里的关键是如何计算ctc_t以及利用它来更新sts_t

6.1 计算背景变量

下图绘制了注意⼒机制如何为解码器在时间步2计算背景变量。⾸先,函数 aa 根据解码器在时间步1的隐藏状态编码器在各个时间步的隐藏状态计算softmax运算的输⼊。softmax运算输出概率分布并对编码器各个时间步的隐藏状态做加权平均,从⽽得到背景变量。
seq2seq及注意力机制
具体来说,令编码器在时间步 tt 的隐藏状态为hth_t ,且总时间步数为 TT。那么解码器在时间步ii的背景变量为所有编码器隐藏状态的加权平均:
ci=t=1Tαitht\boldsymbol{c}_i=\sum_{t=1}^{T} \alpha_{i t} \boldsymbol{h}_{t}
其中给定ii时,权重αit\alpha_{it}是一个概率分布,为了得到概率分布,,我们可以使⽤
softmax运算:
αit=exp(eit)k=1Texp(eik),t=1,,T\alpha_{i t}=\frac{\exp \left(e_{i t}\right)}{\sum_{k=1}^{T} \exp \left(e_{i k}\right)}, \quad t=1, \ldots, T
现在,我们需要定义如何计算上式中softmax运算的输⼊eite_{i t},由于 eite_{i t}同时取决于解码器的时间步 ii 和编码器的时间步 tt,我们不妨以解码器在时间步i1i-1 的隐藏状态si1s_{i-1}与编码器在时间步tt的隐藏状态hth_t为输入,并通过函数 aa 计算eite_{i t}
eit=a(si1,ht)e_{it}=a\left(\boldsymbol{s}_{i-1}, \boldsymbol{h}_{t}\right)
这⾥函数aa有多种选择, 如 果 两 个 输 ⼊ 向 量 ⻓ 度 相 同 , ⼀ 个 简 单 的 选 择 是 计 算 它 们 的 内 积:a(s,h)=sTha(s, h)=s^Th 。⽽最早提出注意⼒机制的论⽂则将输⼊连结后通过含单隐藏层的多层感知机变换
a(s,h)=vtanh(Wss+Whh)a(\boldsymbol{s}, \boldsymbol{h})=\boldsymbol{v}^{\top} \tanh \left(\boldsymbol{W}_{s} \boldsymbol{s}+\boldsymbol{W}_{h} \boldsymbol{h}\right)
其中vvWsW_sWhW_h都是可以学习的模型参数。

6.2 矢量化计算

⼴义上,注意⼒机制的输⼊包括查询项以及⼀⼀对应的键项值项,其中值项是需要加权平均的⼀组项。在加权平均中,值项的权重来⾃查询项以及与该值项对应的键项的计算。

在上⾯的例⼦中,查询项为解码器的隐藏状态,键项和值项均为编码器的隐藏状态,让我们考虑⼀个常⻅的简单情形,即编码器和解码器的隐藏单元个数均为hh ,且函数a(s,h)=sTha(s, h)=s^Th 。假设我们希望根据解码器单个隐藏状态si1Rh\boldsymbol{s}_{i-1} \in \mathbb{R}^{h} 和编码器所有隐藏状态htRh,t=1,2,...,Th_t \in \mathbb R^{h},t=1, 2,...,T 来计算背景向量ciRhc_i \in \mathbb R^h,我们可以将查询项矩阵QR1×hQ \in \mathbb R^{1 \times h}设为si1s_{i-1},并令键项矩阵KRT×h\boldsymbol K \in \mathbb R^{T \times h}和值项矩阵VRT×h\boldsymbol V \in \mathbb R^{T \times h}相同,且第 tt ⾏均为 hth_t^{\top}。此时,我们只需要通过⽮量化计算
softmax(QK)V\operatorname{softmax}\left(\boldsymbol{Q} \boldsymbol{K}^{\top}\right) \boldsymbol{V}
即可算出转置后的背景向量cic_i^{\top}。当查询项矩阵 QQ 的⾏数为 nn 时,上式将得到 nn⾏的输出矩阵。输出矩阵与查询项矩阵在相同⾏上⼀⼀对应。
seq2seq及注意力机制

6.3 更新隐藏状态

以⻔控循环单元为例,在解码器中我们可以对RNN总结中⻔控循环单元的设计稍作修改,从⽽变换上⼀时间步i1i-1 的输出yi1y_{i-1}、隐藏状态si1s_{i-1}和当前时间步 ii 的含注意⼒机制的背景变量cic_{i}。解码器在时间步 ii 的隐藏状态为
si=zisi1+(1zi)s~i\boldsymbol{s}_{i}=\boldsymbol{z}_{i} \odot \boldsymbol{s}_{i-1}+\left(1-\boldsymbol{z}_{i}\right) \odot \tilde{\boldsymbol{s}}_{i}
其中的重置⻔、更新⻔和候选隐藏状态分别为
ri=σ(Wyryi1+Wsrsi1+Wcrci+br)zi=σ(Wyzyi1+Wszsi1+Wczci+bz)s~i=tanh(Wysyi1+Wss(si1ri)+Wcsci+bs)\begin{aligned} \boldsymbol{r}_{i} &=\sigma\left(\boldsymbol{W}_{y r} \boldsymbol{y}_{i-1}+\boldsymbol{W}_{s r} \boldsymbol{s}_{i-1}+\boldsymbol{W}_{c r} \boldsymbol{c}_{i}+\boldsymbol{b}_{r}\right) \\ \boldsymbol{z}_{i} &=\sigma\left(\boldsymbol{W}_{y z} \boldsymbol{y}_{i-1}+\boldsymbol{W}_{s z} \boldsymbol{s}_{i-1}+\boldsymbol{W}_{c z} \boldsymbol{c}_{i}+\boldsymbol{b}_{z}\right) \\ \tilde{\boldsymbol{s}}_{i} &=\tanh \left(\boldsymbol{W}_{y s} \boldsymbol{y}_{i-1}+\boldsymbol{W}_{s s}\left(\boldsymbol{s}_{i-1} \odot \boldsymbol{r}_{i}\right)+\boldsymbol{W}_{c s} \boldsymbol{c}_{i}+\boldsymbol{b}_{s}\right) \end{aligned}
下图为未作修改的GRU
seq2seq及注意力机制
下图为修改过的GRU
seq2seq及注意力机制

7.reference

动手学深度学习

相关文章: