Seq2seq

Seq2seq全名是Sequence-to-sequence,也就是从序列到序列的过程,是近年当红的模型之一。Seq2seq被广泛应用在机器翻译、聊天机器人甚至是图像生成文字等情境。
seq2seq 是一个Encoder–Decoder 结构的网络,它的输入是一个序列,输出也是一个序列, Encoder 中将一个可变长度的信号序列变为固定长度的向量表达,Decoder 将这个固定长度的向量变成可变长度的目标的信号序列。

整个过程可以用下面这张图来诠释:

Seq2seq结构

其中,X、Y均由各自的单词序列组成(X,Y可以是同一种语言,也可以是两种不同的语言)。
Encoder:是将输入序列通过非线性变换编码成一个指定长度的向量$C$(中间语义表示),得到$c$有多种方式,最简单的方法就是把Encoder的最后一个隐状态赋值给$c$,还可以对最后的隐状态做一个变换得到$c$,也可以对所有的隐状态做变换。
Decoder:是根据向量$C$(encoder的输出结果)和之前生成的历史信息$y1$,$y2$,…,$yn$来生成$i$时刻要生成的单词$yi$。

  • 编码阶段
    在RNN中,当前时间的隐藏状态由上一时间的状态和当前时间输入决定的,即:
    $$
    h_t = f(h_{t-1},x_t)
    $$
    获得了各个时间段的隐藏层以后,再将隐藏层的信息汇总,生成最后的语义向量
    $$
    C = q(h_1,h_2,h_3,…,h_x)
    $$
    当然,有一种最简单的方法是将最后的隐藏层作为语义向量C,即
    $$
    C = q(h_1,h_2,h_3,…,h_x) = h_x
    $$
  • 解码阶段
    可以看做编码的逆过程。这个阶段,我们根据给定的语义向量$C$和之前已经生成的输出序列$y_1$,$y_2$,…,$y_{t-1}$来预测下一个输出的单词$y_t$,即
    $$
    y_t = \argmax P(y_t)=\sum_{t=1}^T p(y_t|y_1,…,t_{t-1},C)
    $$
    也可以写作
    $$
    y_t = g({y_1,…,y_{t-1}},C)
    $$
    在RNN中,也可以简化成
    $$
    y_t = g(y_{t-1},s_t,C)
    $$
    其中$s$是输出RNN(即RNN解码器)中的隐藏层,$C$代表之前编码器得到的语义向量,$y_{t-1}$表示上个时间段的输出,反过来作为这个时间段的输入。$g$可以是一个非线性的多层神经网络,产生词典中各个词语属于$y_t$的概率。

Attention模型

encoder-decoder模型虽然非常经典,但是局限性也非常大。最大的局限性就在于编码和解码之间的唯一联系就是一个固定长度的语义向量C。也就是说,编码器要将整个序列的信息压缩进一个固定长度的向量中去。但是这样做有两个弊端,一是语义向量无法完全表示整个序列的信息,二是先输入的内容携带的信息会被后输入的信息稀释掉。输入序列越长,这个现象就越严重。这就使得在解码的时候一开始就没有获得输入序列足够的信息, 那么解码时准确率就要打一定折扣。
为了解决上述问题,在 Seq2Seq出现一年之后,Attention模型被提出了。该模型在产生输出的时候,会产生一个注意力范围来表示接下来输出的时候要重点关注输入序列的哪些部分,然后根据关注的区域来产生下一个输出,如此反复。attention 和人的一些行为特征有一定相似之处,人在看一段话的时候,通常只会重点注意具有信息量的词,而非全部词,即人会赋予每个词的注意力权重不同。attention 模型虽然增加了模型的训练难度,但提升了文本生成的效果。模型的大概示意图如下。

attention 模型

每一个$c$会自动去选取与当前所要输出的$y$最合适的上下文信息。具体来说,我们用 $a_{ij}$ 衡量编码中第$j$阶段的$h_j$和解码时第$i$阶段的相关性,最终Decoder中第$i$阶段的输入的上下文信息 $c_i$ 就来自于所有 $h_j$对 $a_{ij}$的加权和。
Attention的原理就是计算当前输入序列与输出向量的匹配程度,匹配度高也就是注意力集中点其相对的得分越高,其中Attention计算得到的匹配度权重,只限于当前序列对,不是像网络模型权重这样的整体权重。

attention 模型实例

输入的序列是“我爱中国”,因此,Encoder中的$h_1$、$h_2$、$h_3$、$h_4$就可以分别看做是“我”、“爱”、“中”、“国”所代表的信息。在翻译成英语时,第一个上下文$c_1$应该和“我”这个字最相关,因此对应的 $a_{11}$就比较大,而相应的 $a_{12}$ 、$a_{13}$ 、 $a_{14}$ 就比较小。$c_2$应该和“爱”最相关,因此对应的 $a_{22}$ 就比较大。最后的$c_3$和$h_3$、$h_4$最相关,因此 $a_{33}$ 、 $a_{34}$的值就比较大。具体模型权重 $a_{ij}$ 是如何计算出来的呢?

当前输出词$Y_i$针对某一个输入词$j$的注意力权重由当前的隐层$H_i$,以及输入词$j$的隐层状态($h_j$)共同决定;然后再接一个$sofrmax$得到0-1的概率值。即通过函数$F(h_j,H_i)$来获得目标单词$Y_i$和每个输入单词对应的对齐可能性。

Attention算法过程

1)encode对输入序列编码得到最后一个时间步的状态$c$,和每个时间步的输出$h$,其中$c$又作为decode的初始状态$z_0$。

2)对于每个时间步的输出$h$与$z_0$做匹配也就是match操作,得到每个时间步的匹配向量$α_{01}$,如图。

Attention算法过程1

3)对所有时间步的输出$h$与$z_0$的匹配度$α_0$,使用softmax做归一化处理,得到各个时间步对于$z_0$的匹配分数。

4)求各个时间步的输出$h$与匹配分数的加权求和得到$c_0$,作为decode的下一个时间步的输入,如图。

Attention算法过程2

5)计算各个时间步的输出$h$与$z_1$的匹配度得到$c_1$作为decode下一个时间步的输入,如此一步一步重复下去,如图。

Attention算法过程3

这样就可以把每个时间步重要的信息传给decode中,以上就是Attention机制的处理过程。其中match操作一般是求两个向量的相似度,通常有如下方法:
1)余弦相似度
2)一个简单的神经网络,输入为$h$和$w$,输出为$α$
3)或者矩阵变换(Multiplicative attention,Luong et al., 2015)

图解Attention模型

图解Attention模型

(1)$h_t=RNN_{enc}(x_t,h_{t-1})$,Encoder方面接受的是每一个单词word embedding,和上一个时间点的hidden state。输出的是这个时间点的hidden state。
(2)$s_t=RNN_{dec}(\hat{y_{t-1}},s_{t-1})$, Decoder方面接受的是目标句子里单词的word embedding,和上一个时间点的hidden state。
(3)$c_i=\sum_{j=1}^{T_x} \alpha_{ij}h_j$, context vector是一个对于encoder输出的hidden states的一个加权平均。
(4)$\alpha_{ij}=\frac{\exp(e_{ij})}{\sum_{k=1}^{T-x} \exp(e_{ik}) }$, 每一个encoder的hidden states对应的权重。
(5)$e_{ij}=score(s_i,h_j)$, 通过decoder的hidden states加上encoder的hidden states来计算一个分数,用于计算权重(4)
(6)$\hat{s_t}=tanh(W_c|c_t;s_t)$, 将context vector 和 decoder的hidden states 串起来。
(7)$p(y_t|y<t,x)=softmax(W_s \hat{s_t})$,计算最后的输出概率。

CNN的seq2seq

现在大多数场景下使用的Seq2Seq模型是基于RNN构成的,虽然取得了不错的效果,但也有一些学者发现使用CNN来替换Seq2Seq中的encoder或decoder可以达到更好的效果。最近,FaceBook发布了一篇论文:《Convolutional Sequence to Sequence Learning》,提出了完全使用CNN来构成Seq2Seq模型,用于机器翻译,超越了谷歌创造的基于LSTM机器翻译的效果。此网络获得暂时性胜利的重要原因在于采用了很多的窍门,这些技巧值得学习:
•捕获long-distance依赖关系
底层的CNN捕捉相聚较近的词之间的依赖关系,高层CNN捕捉较远词之间的依赖关系。通过层次化的结构,实现了类似RNN(LSTM)捕捉长度在20个词以上的Sequence的依赖关系的功能。

改进

Attention model虽然解决了输入句仅有一个context vector的缺点,但依旧存在不少问题。
1.context vector计算的是输入句、目标句间的关联,却忽略了输入句中文字间的关联,和目标句中文字间的关联性;
2.不管是Seq2seq或是Attention model,其中使用的都是RNN,RNN的缺点就是无法平行化处理,导致模型训练的时间很长,有些论文尝试用CNN去解决这样的问题,像是Facebook提出的Convolutional Seq2seq learning,但CNN实际上是透过大量的layer去解决局部信息的问题,在2017年,Google提出了一种叫做”The transformer”的模型,透过self attention、multi-head的概念去解决上述缺点,完全舍弃了RNN、CNN的构架。
Seq2Seq的核心部分是其解码部分,大部分改进基于此:
greedy search:基础解码方法
beam search:对greedy search的改进
attention:它的引入使得解码时,每一步可以有针对地关注与当前有关的编码结果,从而减小了编码器输出表示的学习难度,也更容易学到长期的依赖关系。
memory network:从外部获取知识。
其他方法:
堆叠多层RNN的Decoder
增加dropout机制
与Encoder建立残差连接

Self attention

传统的rnn难于并行,而流行的attention模型往往会利用rnn。总之为了解决无法并行训练问题,google提出了self-attention,完全摒弃了rnn单元,从而做到并行训练。
Attention函数的本质可以被描述为一个查询(query)到一系列(键key-值value)对的映射,如下图。

Self attention

在计算attention时主要分为三步,第一步是将query和每个key进行相似度计算得到权重,常用的相似度函数有点积,拼接,感知机等;然后第二步一般是使用一个softmax函数对这些权重进行归一化;最后将权重和相应的键值value进行加权求和得到最后的attention。目前在NLP研究中,key和value常常都是同一个,即key=value。

Self attention

Attention is all you need

Attention is all you need 是google机器翻译团队在2017年nips上发表的论文,
主要亮点在于:
1)不同于以往主流机器翻译使用基于RNN的seq2seq模型框架,该论文用attention机制代替了RNN搭建了整个模型框架。
2)提出了多头注意力(Multi-headed attention)机制方法,在编码器和解码器中大量的使用了多头自注意力机制(Multi-headed self-attention)。
3)在WMT2014语料中的英德和英法任务上取得了先进结果,并且训练速度比主流模型更快。
该论文模型的整体结构如下图,还是由编码器和解码器组成,在编码器的一个网络块中,由一个多头attention子层和一个前馈神经网络子层组成,整个编码器栈式搭建了N个块。类似于编码器,只是解码器的一个网络块中多了一个多头attention层。为了更好的优化深度网络,整个网络使用了残差连接和对层进行了规范化(Add&Norm)。

Self attention

多头attention(Multi-head attention)结构如下图,Query,Key,Value首先进过一个线性变换,然后输入到放缩点积attention,注意这里要做h次,其实也就是所谓的多头,每一次算一个头。而且每次Q,K,V进行线性变换的参数W是不一样的。然后将h次的放缩点积attention结果进行拼接,再进行一次线性变换得到的值作为多头attention的结果。可以看到,google提出来的多头attention的不同之处在于进行了h次计算而不仅仅算一次,论文中说到这样的好处是可以允许模型在不同的表示子空间里学习到相关的信息,后面还会根据attention可视化来验证。

Self attention

那么在整个模型中,是如何使用attention的呢?如下图,首先在编码器到解码器的地方使用了多头attention进行连接,K,V,Q分别是编码器的层输出(这里K=V)和解码器中都头attention的输入。其实就和主流的机器翻译模型中的attention一样,利用解码器和编码器attention来进行翻译对齐。然后在编码器和解码器中都使用了多头自注意力self-attention来学习文本的表示。Self-attention即K=V=Q,例如输入一个句子,那么里面的每个词都要和该句子中的所有词进行attention计算。目的是学习句子内部的词依赖关系,捕获句子的内部结构。

Self attention

对于使用自注意力机制的原因,论文中提到主要从三个方面考虑(每一层的复杂度,是否可以并行,长距离依赖学习),并给出了和RNN,CNN计算复杂度的比较。如果输入序列n小于表示维度d的话,每一层的时间复杂度self-attention是比较有优势的。当n比较大时,作者也给出了一种解决方案self-attention(restricted)即每个词不是和所有词计算attention,而是只与限制的r个词去计算attention。在并行方面,多头attention和CNN一样不依赖于前一时刻的计算,可以很好的并行,优于RNN。在长距离依赖上,由于self-attention是每个词和所有词都要计算attention,所以不管他们中间有多长距离,最大的路径长度也都只是1。可以捕获长距离依赖关系。

self-attention可以是一般attention的一种特殊情况,在self-attention中,Q=K=V每个序列中的单元和该序列中所有单元进行attention计算。Google提出的多头attention通过计算多次来捕获不同子空间上的相关信息。self-attention的特点在于无视词之间的距离直接计算依赖关系,能够学习一个句子的内部结构,实现也较为简单并行可以并行计算。从一些论文中看到,self-attention可以当成一个层和RNN,CNN,FNN等配合使用,成功应用于其他NLP任务。