Sequence models & Attention mechanism
3.1 基础模型(Basic Model)
这一周,我们将会学习seq2seq(sequence to sequence)模型
比如现在,我们有一句中文:“很棒的一天!”你想把它翻译成英文“What a nice day!”,这也是很多翻译软件做的事情。和之前一样,我们用
x
<
1
>
,
x
<
2
>
,
x
<
3
>
.
.
.
.
.
.
.
x
<
t
>
.
.
.
.
.
.
.
x^{<1>},x^{<2>},x^{<3>}.......x^{<t>}.......
x<1>,x<2>,x<3>.......x<t>.......来表示输入的句子的单词,然后我们用
y
<
1
>
,
y
<
2
>
,
y
<
3
>
.
.
.
.
.
.
.
y
<
t
>
.
.
.
.
.
.
.
y^{<1>},y^{<2>},y^{<3>}.......y^{<t>}.......
y<1>,y<2>,y<3>.......y<t>.......来表示输出的句子的单词。
首先,我们先建立一个网络,这个网络叫做编码网络(encoder network),它是一个RNN的结构, RNN的单元可以是GRU 也可以是LSTM。每次只向该网络中输入一个法语单词,将输入序列接收完毕后,这个RNN网络会输出一个向量来代表这个输入序列。之后你可以建立一个解码网络,它以编码网络的输出作为输入,编码网络是左边的黑色部分。之后它可以被训练为每次输出一个翻译后的单词,一直到它输出序列的结尾或者句子结尾标记,这个解码网络的工作就结束了。和往常一样我们把每次生成的标记都传递到下一个单元中来进行预测,就像之前用语言模型合成文本时一样。
3.2 选择最可能的句子(Picking the most likely sentence)
这里我们通过机器翻译来理解seq2seq模型
你可以把它看作是一个条件语言模型。机器翻译这里先是将要翻译的句子输入到一个“编码网络”中。这个编码网络的任务就是将这句话产生一个编码,之后将编码输入到RNN中得到翻译后的句子。这里我们想要的输出是一个条件概率最大化的值。就比如这句中文:“Jane九月份将要去非洲。”英文翻译可以有很多种
我们期待的可能是第一句。因为它比较自然,而且还用了ing表将来时。听起来就不是小学生的句子(虽然过了六级也不会第一时间想到第一句 )所以我们期待它能够输出第一句话。而这样的话第一句话在整个可能的翻译中必须出现的可能性是最高的。那么我们的算法就必须能够找到这个最高的概率。
有人可能第一个想法就是贪心地找,生成序列时,每次都找下一个最可能出现的单词。但是这个方法也可能出现问题。就比如上面的翻译。到了第三个词时,going明显出现概率会比较高,所以visiting果断被淘汰了。但是这又不符合我们的需求,所以这里需要更好的方法。接下来继续介绍一种做法——定向搜索。
3.3 集束搜索(Beam Search)
贪心算法只会挑出最可能的那一个单词,然后继续。而集束搜索则会考虑多个选择,集束搜索算法会有一个参数B,叫做集束宽(beam width)。在这个例子中我把这个集束宽设成3,这样就意味着集束搜索不会只考虑一个可能结果,而是一次会考虑3个。所以我们是像正常那样操作,先看第一个词,假设我们这里单词表有10000个词。我们从中过了一遍,选择出了in,jane, september作为候选的第一个词。
第二步,就是使用已经预测好的第一个单词来预测第二个单词。也是要每个都全部要过一遍,也就是得到30000个结果。然后从这30000个结果中得到最佳的3个结果。比如是:in September,jane is,jane visits。然后我们保存这三个结果,接下来第三步,就将这三个段放入RNN中继续得到第3个词。
以上就是集束搜索的基本步骤,重复这些步骤,通过修改参数B来改变考虑的个数。事实上还有一些额外的提示和技巧的改进能够使集束算法更高效,我们下节中一探究竟。
3.4 改进集束搜索(Refinements to Beam Search)
Length Normalization
我们之前使用的函数来估计概率的是一个乘法。本来概率就是小于1的数值,全部乘起来会非常小,所以这时候就要请对数函数来帮忙了。对数可以将乘法转化为加法。就如下面图片中的式子一样。其实这个就像一个最大似然法的流程。计算完似然函数后,也可以对它进行归一化。这里归一化系数可以是句子的长度,也就是除以句子中单词的个数。也可以加上一个指数,这个指数也可以当作一个超参数来处理。通过除以翻译结果的单词数量。这样就是取每个单词的概率对数值的平均了,这样很明显地减少了对输出长的结果的惩罚。
discussion
最后还有一些实现的细节,如何选择束宽B。B越大,你考虑的选择越多,你找到的句子可能越好,但是B越大,你的算法的计算代价越大,因为你要把很多的可能选择保存起来。最后我们总结一下关于如何选择束宽B的一些想法。接下来是针对或大或小的B各自的优缺点。如果束宽很大,你会考虑很多的可能,你会得到一个更好的结果,因为你要考虑很多的选择,但是算法会运行的慢一些,内存占用也会增大,计算起来会慢一点。而如果你用小的束宽,结果会没那么好,因为你在算法运行中,保存的选择更少,但是你的算法运行的更快,内存占用也小。在前面视频里,我们例子中用了束宽为3,所以会保存3个可能选择,在实践中这个值有点偏小。在产品中,经常可以看到把束宽设到10。
这里还有要注意的是,集束搜索不像BFS和DFS一样是一种精确的搜索算法,它本质上只是把贪心的范围扩大了一些,得到的并不是最优解。
3.5 集束搜索的误差分析(Error analysis in beam search)
在第三门课里,我们学习了误差分析能够帮助集中时间做项目中最有用的工作,束搜索不总是输出可能性最大的句子,它仅记录着B为前3或者10或是100种可能。那么如果束搜索算法出现错误会怎样呢?
本节中,将会学习到误差分析和束搜索算法是如何相互起作用的,以及怎样才能发现是束搜索算法出现了问题,还是你的RNN模型出了问题。我们先来看看如何对束搜索算法进行误差分析。
现在,我们假设训练集中有人类的翻译,称作
y
∗
y^*
y∗。然后是算法输出的翻译
y
^
\hat{y}
y^.先来看一下这两个条件概率
P
(
y
∗
∣
x
)
P(y^*|x)
P(y∗∣x)和
P
(
y
^
∣
x
)
P(\hat{y}|x)
P(y^∣x)有什么不同。有两种情况:
第一种情况,RNN模型的输出结果
P
(
y
∗
∣
x
)
P(y^*|x)
P(y∗∣x)大于
P
(
y
^
∣
x
)
P(\hat{y}|x)
P(y^∣x),这意味束搜索算法选择了
y
∗
y^*
y∗.你得到的方式是,你用一个RNN模型来计算
P
(
y
∣
x
)
P(y|x)
P(y∣x),然后束搜索算法做的就是尝试寻找使
P
(
y
∣
x
)
P(y|x)
P(y∣x)最大的y,不过在这种情况下,相比于
P
(
y
^
∣
x
)
P(\hat{y}|x)
P(y^∣x),
P
(
y
∗
∣
x
)
P(y^*|x)
P(y∗∣x)的值更大,因此束搜索算法实际上不能够给你一个能使最大化的值,因为束搜索算法的任务就是寻找一个的值来使这项更大,但是它却选择了
P
(
y
^
∣
x
)
P(\hat{y}|x)
P(y^∣x),而实际上能得到更大的值。因此这种情况下你能够得出是束搜索算法出错了。那另一种情况是怎样的呢?
第二种情况是 P ( y ∗ ∣ x ) P(y^*|x) P(y∗∣x)小于或等于 P ( y ^ ∣ x ) P(\hat{y}|x) P(y^∣x).这两者之中总有一个是真的。在我们的例子中, y ∗ y^* y∗是比 y ^ 更 好 的 翻 译 结 果 , 不 过 根 据 R N N 模 型 的 结 果 , 也 就 是 说 , 相 比 于 \hat{y}更好的翻译结果,不过根据RNN模型的结果,也就是说,相比于 y^更好的翻译结果,不过根据RNN模型的结果,也就是说,相比于P(\hat{y}|x) , , ,P(y^*|x)$成为输出的可能更小。因此在这种情况下,看来是RNN模型出了问题。同时可能值得在RNN模型上花更多时间。这里略过了有关长度归一化的细节,如果用了某种长度归一化,那么你要做的就不是比较这两种可能性大小,而是比较长度归一化后的最优化目标函数值。不过现在先忽略这种复杂的情况。第二种情况表明虽然是一个更好的翻译结果,RNN模型却赋予它更低的可能性,是RNN模型出现了问题。
这就是束搜索算法中的误差分析,通过特定的误差分析过程是十分有用的,它可以用于分析到底是搜索方法出现了问题还是RNN模型出现了问题。