我们先结合上篇文章的内容,将 language model 和 Machine translation model 做一个对比:
可以看到,机器翻译模型的后半部分其实就是语言模型,Andrew 将其称之为 “条件语言模型”.
1. Encoder-Decoder
Source 和 Target 分别由各自的单词序列构成:
Encoder 顾名思义就是对输入句子Source进行编码,将输入句子通过非线性变换转化为中间语义表示C:
对于 Decoder 来说,其任务是根据句子 Source 的 中间语义表示 C 和 之前已经生成的历史信息
来生成 i时刻 要生成的单词
每个 都依次这么产生,那么看起来就是整个系统根据输入 句子Source 生成了目标句子Target。
(1). 如果Source是中文句子,Target是英文句子,那么这就是解决机器翻译问题;
(2). 如果Source是一篇文章,Target是概括性的几句描述语句,那么这是文本摘要;
(3). 如果Source是一句问句,Target是一句回答,那么这是问答系统。
Encoder-Decoder框架 不仅仅在文本领域广泛使用,在语音识别、图像处理等领域也经常使用.
Learning Phrase Representations using RNN Encoder–Decoder for Statistical Machine Translation
1.1 encoder
用函数 表达 RNN 隐藏层的变换:
然后 Encoder 通过自定义函数 将各个时间步的隐藏状态变换为背景变量
例如,当选择 时,背景变量是输入序列最终时间步的隐藏状态 。
以上描述的编码器是一个单向的 RNN,每个时间步的隐藏状态只取决于该时间步及之前的输入子序列。我们也可以使用 Bi-RNN 构造编码器。 这种情况下,编码器每个时间步的隐藏状态同时取决于该时间步之前和之后的子序列(包括当前时间步的输入),并编码了整个序列的信息。
1.2 decoder
上小节 Encode 编码器输出的背景变量 编码了整个输入序列 的信息。
给定 train sample 的 input sequence: ,对每个时间步 (符号与 input sequence 或 encoder 的时间步 有区别), decoder 输出 的条件概率将基于之前的 output sequence: 和 .
即:
为此,我们可以使用另一个RNN
作为解码器。 在输出序列的时间步 ,解码器将上一时间步的输出 以及背景变量 作为输入,并将它们与上一时间步的隐藏状态 变换为当前时间步的隐藏状态 。因此,我们可以用函数 表达解码器隐藏层的变换:
可使用自定义的 output layer 和 softmax 计算 ,计算当前时间步输出 的概率分布.
1.3 decoder greedy search
在语言模型之前有一 个条件也就是被翻译的句子:
但是我们知道翻译是有很多种方式的,同一句话可以翻译成很多不同的句子,那么如何判断哪一句子是最好的呢?
还是翻译上面那句话,有如下几种翻译结果:
- “Jane is visiting China in September.”
- “Jane is going to visit China in September.”
- “In September, Jane will visit China”
- “Jane’s Chinese friend welcomed her in September.”
- …
得到最好的翻译结果,转换成数学公式就是:
那么 Greedy Search 就是每次输出的那个都必须是最好的。还是以翻译那句话为例。
现在假设通过贪婪搜索已经确定最好的翻译的前两个单词是:"Jane is "
然后因为 “going” 出现频率较高和其它原因,所以根据贪婪算法得出此时第三个单词的最好结果是 “going”。
所以据贪婪算法最后的翻译结果可能是下图中的第二个句子,但第一句可能会更好.
所以 Greedy Search 的缺点是局部最优并不代表全局最优. Greedy Search 更加短视,看的不长远。
1.4 decoder beam search
Beam Search 是 greedy search 的加强版本,首先要预设一个值 beam width,这里等于 3
(如果等于 1 就是 greedy search)。然后在每一步保存最佳的 3 个结果进行下一步的选择,以此直到遇到句子的终结符.
1.4.1 step 1
如下图示,因为beam width=3,所以根据输入的需要翻译的句子选出 3 个 最可能的输出值。
即选出 最大的前3个值。 假设分别是 “in”, “jane”, "september"
1.4.2 step 2
以"in"为例进行说明,其他同理.
如下图示,在给定被翻译句子 和确定 = “in” 的条件下,下一个输出值的条件概率是 。
此时需要从 10000 种可能中找出条件概率最高的前 3 个.
又由公式:
我们此时已经得到了给定输入数据,前两个输出值的输出概率比较大的组合了.
另外 2 个单词也做同样的计算
此时我们得到了 9 组 , 此时我们再从这 9组 中选出概率值最高的前 3 个。
如下图示,假设是这3个:
- “in september”
- “jane is”
- “jane visits”
1.4.3 step 3
继续 step 2 的过程,根据 选出 最大的前3个组合.
后面重复上述步骤得出结果.
1.4.4 summary
总结一下上面的步骤就是:
- (1). 经过 encoder 以后,decoder 给出最有可能的三个开头词依次为 “in”, “jane”, “september”
- (2). 经 step 1 得到的值输入到 step 2 中,最可能的三个翻译为 “in september”, “jane is”, “jane visits”
(这里,september开头的句子由于概率没有其他的可能性大,已经失去了作为开头词资格)
- (3). 继续这个过程…
1.5 refinements to beam search
所以要满足 , 也就等同于要满足
但是上面的公式存在一个问题,因为概率都是小于1的,累乘之后会越来越小,可能小到计算机无法精确存储,所以可以将其转变成 log 形式(因为 log 是单调递增的,所以对最终结果不会有影响),其公式如下:
But!!!上述公式仍然存在bug,观察可以知道,概率值都是小于1的,那么log之后都是负数,所以为了使得最后的值最大,那么只要保证翻译的句子越短,那么值就越大,所以如果使用这个公式,那么最后翻译的句子通常都是比较短的句子,这显然不行。
所以我们可以通过归一化的方式来纠正,即保证平均到每个单词都能得到最大值。其公式如下:
归一化的确能很好的解决上述问题,但是在实际运用中,会额外添加一个参数 , 其大小介于 0 和 1 之间
为输出句子中单词的个数, 是一个超参数 (可以设置为 0.7)
== 1. 则代表 完全用句子长度归一化
== 0. 则代表 没有归一化
== 0~1. 则代表 在 句子长度归一化 与 没有归一化 之间的折中程度.beam width = B = 3**10**100 是会有一个明显的增长,但是 B 从 1000 ~ 3000 是并没有一个明显增长的.
1.6 train seq2seq model
根据最大似然估计,我们可以最大化输出序列基于输入序列的条件概率
\begin{split}\begin{aligned} {P}(y\_1, \ldots, y\_{T'} \mid x\_1, \ldots, x\_T) &= \prod\_{t'=1}^{T'} {P}(y\_{t'} \mid y\_1, \ldots, y\_{t'-1}, x\_1, \ldots, x\_T)\\\\ &= \prod\_{t'=1}^{T'} {P}(y\_{t'} \mid y\_1, \ldots, y\_{t'-1}, \boldsymbol{c}), \end{aligned}\end{split}
并得到该输出序列的损失
在模型训练中,所有输出序列损失的均值通常作为需要最小化的损失函数。在图中所描述的模型预测中,我们需要将decode在上一个时间步的输出作为当前时间步的输入。与此不同,在训练中我们也可以将标签序列在上一个时间步的标签作为decode在当前时间步的输入。这叫做强制教学(teacher forcing)。
1.7 summary
- 编码器 - 解码器(seq2seq)可以输入并输出不定长的序列。
- 编码器—解码器使用了两个 RNN。
- 在编码器—解码器的训练中,我们可以采用 teacher forcing。(这也是 Seq2Seq 2 的内容)
2. Seq2Seq 框架2
Seq2Seq model 来自于 “Sequence to Sequence Learning with Neural Networks”
其模型结构图如下所示:
与上面模型最大的区别在于其source编码后的 向量 直接作为 Decoder RNN 的 init state,而不是在每次decode时都作为 RNN cell 的输入。此外,decode 时 RNN 的输入是 label,而不是前一时刻的输出。
Encoder 阶段:
每个词经过 RNN 都会编码为 hidden (e0,e1,e2), source序列 的编码向量e 就是 最终的 hidden state e2
Tips: 这里 是 hidden state, 并没有经过 g 和 softmax .
Decoder 阶段:
e向量 仅作为 RNN 的 init state 传入decode模型,每一时刻输入都是前一时刻的正确label。直到最终输入
3. Seq2Seq Attention
请务必要阅读: 张俊林 深度学习中的注意力模型(2017版)
decode 在各个时间步依赖相同的 背景变量 来获取输入序列信息。当 encode 为 RNN 时,背景变量 来自它最终时间步的 hidden state。
英语输入:“They”、“are”、“watching”、“.”
法语输出:“Ils”、“regardent”、“.”翻译例子:输入为英语序列“They”、“are”、“watching”、“.”,输出为法语序列“Ils”、“regardent”、“.”。,decode 在生成输出序列中的每一个词时可能只需利用输入序列某一部分的信息。例如,在输出序列的时间步 1,解码器可以主要依赖“They”、“are”的信息来生成“Ils”,在时间步 2 则主要使用来自“watching”的编码信息生成“regardent”,最后在时间步 3 则直接映射句号“.”。这看上去就像是在 decode 的每一时间步对输入序列中不同时间步的编码信息分配不同的注意力一样。这也是注意力机制的由来 1。
仍以 RNN 为例,Attention 通过对 Encode 所有时间步的隐藏状态做加权平均来得到背景变量。Decode 在每一时间步调整这些权重,即 Attention weight,从而能够在不同时间步分别关注输入序列中的不同部分并编码进相应时间步的背景变量。本节我们将讨论 Attention机制 是怎么工作的。
在“encoder-decoder(seq2seq)”, Decoder 在时间步 的 hidden state
在 Attention机制 中, Decoder 的每一时间步将使用可变的背景变量
关键是如何计算背景变量 和如何利用它来更新隐藏状态 。以下将分别描述这两个关键点。
3.1 计算背景变量 c
其中给定 时,权重 在 的值是一个概率分布。为了得到概率分布,可以使用 softmax 运算:
现在,我们需要定义如何计算上式中 softmax 运算的输入 。由于 同时取决于decode的时间步 和encode的时间步 ,我们不妨以解码器在时间步 的隐藏状态 与编码器在时间步 的隐藏状态 为输入,并通过函数 计算 :
这里函数 a 有多种选择,如果两个输入向量长度相同,一个简单的选择是计算它们的内积 。而最早提出Attention机制的论文则将输入连结后通过含单隐藏层的多层感知机MLP 变换
其中 都是可以学习的模型参数。
3.2 update hidden state
以 GRU 为例,在解码器中我们可以对 GRU 的设计稍作修改。解码器在时间步 的隐藏状态为
其中的重置门、更新门和候选隐含状态分别为 :
\begin{split}\begin{aligned} \boldsymbol{r}\_{t'} &= \sigma(\boldsymbol{W}\_{yr} \boldsymbol{y}\_{t'-1} + \boldsymbol{W}\_{sr} \boldsymbol{s}\_{t' - 1} + \boldsymbol{W}\_{cr} \boldsymbol{c}\_{t'} + \boldsymbol{b}\_r),\\\\ \boldsymbol{z}\_{t'} &= \sigma(\boldsymbol{W}\_{yz} \boldsymbol{y}\_{t'-1} + \boldsymbol{W}\_{sz} \boldsymbol{s}\_{t' - 1} + \boldsymbol{W}\_{cz} \boldsymbol{c}\_{t'} + \boldsymbol{b}\_z),\\\\ \tilde{\boldsymbol{s}}\_{t'} &= \text{tanh}(\boldsymbol{W}\_{ys} \boldsymbol{y}\_{t'-1} + \boldsymbol{W}\_{ss} (\boldsymbol{s}\_{t' - 1} \odot \boldsymbol{r}\_{t'}) + \boldsymbol{W}\_{cs} \boldsymbol{c}\_{t'} + \boldsymbol{b}\_s), \end{aligned}\end{split}
其中含下标的 W 和 b 分别为 GRU 的权重参数和偏差参数。
3.3 attention summary
- 可以在decode的每个时间步使用不同的背景变量,并对输入序列中不同时间步编码的信息分配不同的注意力。
- Attention机制可以采用更为高效的矢量化计算。
除此之外模型为了取得比较好的效果还是用了下面三个小技巧来改善性能:
深层次的LSTM:作者使用了4层LSTM作为encoder和decoder模型,并且表示深层次的模型比shallow的模型效果要好(单层,神经元个数多)。
将source进行反序输入:输入的时候将“ABC”变成“CBA”,这样做的好处是解决了长序列的long-term依赖,使得模型可以学习到更多的对应关系,从而达到比较好的效果。
注意力机制是一种思想,可以有多种不同的实现方式,在 Seq2Seq 模型以外的场景也有不少应用
4. Attention 本质思想
把Attention机制从上文讲述例子中的Encoder-Decoder框架中剥离,并进一步做抽象,可以更容易懂:
4.1 Attention 的三阶段
- 第一个阶段根据Query和Key计算两者的相似性或者相关性;
- 第二个阶段对第一阶段的原始分值进行归一化处理;
- 根据权重系数对Value进行加权求和。
4.2 Self Attention
Attention顾名思义,指的不是Target和Source之间的Attention机制,而是Source内部元素之间或者Target内部元素之间发生的Attention机制,也可以理解为Target=Source这种特殊情况下的注意力计算机制。
引入Self Attention后会更容易捕获句子中长距离的相互依赖的特征,因为如果是RNN或者LSTM,需要依次序序列计算,对于远距离的相互依赖的特征,要经过若干时间步步骤的信息累积才能将两者联系起来,而距离越远,有效捕获的可能性越小。
请务必要阅读: 张俊林 深度学习中的注意力模型(2017版)
Checking if Disqus is accessible...