1.视频网站:mooc慕课https://mooc.study.163.com/university/deeplearning_ai#/c
2.详细笔记网站(中文):http://www.ai-start.com/dl2017/
3.github课件+作业+答案:https://github.com/stormstone/deeplearning.ai
3.4 改进定向搜索 Fefinements to beam search
上节课中, 你已经学到了基本的束搜索算法(the basic beam search algorithm),这节课里,我们会学到一些技巧, 能够使算法运行的更好。
长度归一化(Length normalization)就是对束搜索算法稍作调整的一种方式,帮助你得到更好的结果,下面介绍一下它。
上节课讲到束搜索就是最大化上图这个概率。
这个乘积就是
P
(
y
<
1
>
.
.
.
y
<
T
y
>
∣
x
)
P(y^{<1>}...y^{<T_y>}|x)
P(y<1>...y<Ty>∣x),可以表示成:
P
(
y
<
1
>
.
.
.
y
<
T
y
>
∣
x
)
=
P
(
y
<
1
>
∣
x
)
P
(
y
<
2
>
∣
x
,
y
<
1
>
)
P
(
y
<
3
>
∣
x
,
y
<
1
>
,
y
<
2
>
)
.
.
.
P
(
y
<
T
y
>
∣
x
,
y
<
1
>
,
y
<
2
>
.
.
.
y
<
T
y
−
1
>
)
P(y^{<1>}...y^{<T_y>}|x)=P(y^{<1>}|x)P(y^{<2>}|x,y^{<1>}) P(y^{<3>}|x,y^{<1>},y^{<2>})...P(y^{<T_y>}|x,y^{<1>},y^{<2>}...y^{<T_y-1>})
P(y<1>...y<Ty>∣x)=P(y<1>∣x)P(y<2>∣x,y<1>)P(y<3>∣x,y<1>,y<2>)...P(y<Ty>∣x,y<1>,y<2>...y<Ty−1>)
这些符号看起来可能比实际上吓人,但这就是我们之前见到的乘积概率(the product probabilities)。如果计算这些,其实这些概率值都是小于1的,通常远小于1。很多小于1的数乘起来,会得到很小很小的数字,会造成数值下溢(numerical underflow)。数值下溢就是数值太小了,导致电脑的浮点表示不能精确地储存,因此在实践中,我们不会最大化这个乘积,而是取 log 值。
如上图,如果在图中上边的公式加上一个 log,最大化这个 log 求和的概率值 ,在选择最可能的句子
y
y
y时,你会得到同样的结果。所以通过取 loig,我们会得到一个数值上更稳定的算法,不容易出现四舍五入的误差,数值的舍入误差(rounding errors)或者说数值下溢(numerical underflow)。
因为 log 函数它是严格单调递增的函数,最大化 P ( y ) P(y) P(y),因为对数函数( log 函数),是严格单调递增的函数,所以最大化 l o g ( P y ∣ x ) log(Py|x) log(Py∣x) 和最大化 P ( y ∣ x ) P(y|x) P(y∣x) 结果一样。如果一个 y y y值能够使前者最大,就肯定能使后者也取最大。所以实际工作中,我们总是记录概率的对数和(the sum of logs of the probabilities),而不是概率的乘积(the production of probabilities)。
对于目标函数(objective function,概率的对数和,上面的公式 a r g m a x ∑ t = 1 T y l o g P ( . . . ) arg max \sum_{t=1}^{T_y} logP(...) argmax∑t=1TylogP(...)),还可以做一些改变,可以使得机器翻译表现的更好。
按照原来的目标函数(original objective,概率的乘积,上面的公式
a
r
g
m
a
x
∏
t
=
1
T
y
P
(
.
.
.
)
arg max\prod_{t=1}^{T_y}P(...)
argmax∏t=1TyP(...)),如果有一个很长的句子,那么这个句子的概率会很低,因为乘了很多项小于1的数字来估计句子的概率。所以如果乘起来很多小于1的数字,那么就会得到一个更小的概率值,所以这个目标函数有一个缺点,它可能不自然地倾向于简短的翻译结果,它更偏向短的输出,因为短句子的概率是由更少数量的小于1的数字乘积得到的,所以这个乘积不会那么小。
顺便说一下,”概率的对数和“也有同样的问题。概率的 log 值通常小于等于1,实际上在上图圆圈处, log 的这个范围内,加起来的项越多,得到的结果越负。
所以对这个算法另一个改变也可以使它表现的更好,也就是我们不再最大化上图这个目标函数了,我们可以把它归一化
,通过除以翻译结果的单词数量
T
y
T_y
Ty(normalize this by the number of words in your translation)。
这样就是取每个单词的概率对数值的平均了,这样很明显地减少了对输出长的结果的惩罚(this significantly reduces the penalty for outputting longer translations.)。
在实践中,有个探索性的方法,相比于直接除 T y T_y Ty,也就是输出句子的单词总数,我们有时会用一个更柔和的方法(a softer approach),在 T y T_y Ty上加上指数 a a a, a a a可以等于0.7。
- a a a如果等于1,就相当于完全用长度来归一化,
- a a a如果等于0, T y T_y Ty的0次幂就是1,就相当于完全没有归一化
这就是在完全归一化和没有归一化之间。 a a a就是算法另一个超参数(hyper parameter),需要调整大小来得到最好的结果。不得不承认,这样用 a a a实际上是试探性的,它并没有理论验证。但是大家都发现效果很好,大家都发现实践中效果不错,所以很多人都会这么做。你可以尝试不同的值,看看哪一个能够得到最好的结果。
总结一下如何运行束搜索算法。
当你运行束搜索时,你会看到很多长度等于1(
T
y
=
1
T_y=1
Ty=1)的句子,很多长度等于2(
T
y
=
2
T_y=2
Ty=2)的句子,很多长度等于3(
T
y
=
3
T_y=3
Ty=3)的句子,等等。可能运行束搜索30步,考虑输出的句子可能达到,比如长度30。因为束宽为3,你会记录所有这些可能的句子长度,长度为1、2、 3、 4 等等一直到30的三个最可能的选择。
然后针对这些所有的可能的输出句子,用上图这个公式给它们打分,取概率最大的几个句子,然后对这些束搜索得到的句子,计算这个目标函数。最后从经过评估的这些句子中,挑选出在归一化的 log 概率目标函数上得分最高的一个(you pick the one that achieves the highest value on this normalized log probability objective.),有时这个也叫作归一化的对数似然目标函数(a normalized log likelihood objective)。
这就是最终输出的翻译结果,这就是如何实现束搜索。这周的练习中你会自己实现这个算法。
最后还有一些实现的细节,如何选择束宽B。
B越大,你考虑的选择越多,你找到的句子可能越好,但是B越大,你的算法的计算代价越大,因为你要把很多的可能选择保存起来。最后我们总结一下关于如何选择束宽B的一些想法。接下来是针对或大或小的B各自的优缺点。
- 如果束宽很大,你会考虑很多的可能,你会得到一个更好的结果,因为你要考虑很多的选择,但是算法会运行的慢一些,内存占用也会增大,计算起来会慢一点。
- 如果你用小的束宽,结果会没那么好,因为你在算法运行中,保存的选择更少,但是你的算法运行的更快,内存占用也小。
在上一节课里,我们例子中用了束宽为3,所以会保存3个可能选择,在实践中这个值有点偏小。
- 在产品中,经常可以看到把束宽设到10,我认为束宽为100对于产品系统来说有点大了,这也取决于不同应用。
- 但是对科研而言,人们想压榨出全部性能,这样有个最好的结果用来发论文,也经常看到大家用束宽为1000或者3000,这也是取决于特定的应用和特定的领域。
在你实现你的应用时,尝试不同的束宽的值,当B很大的时候,性能提高会越来越少。对于很多应用来说,从束宽1,也就是贪心算法,到束宽为3、到10,你会看到一个很大的改善。但是当束宽从1000增加到3000时,效果就没那么明显了。
对于之前上过计算机科学课程的同学来说,如果你熟悉计算机科学里的搜索算法(computer science search algorithms), 比如广度优先搜索(BFS, Breadth First Search algorithms),或者深度优先搜索(DFS, Depth First Search),你可以这样想束搜索,不像其他你在计算机科学算法课程中学到的算法一样。如果你没听说过这些算法也不要紧,但是如果你听说过广度优先搜索BFS和深度优先搜索DFS,不同于这些算法,这些都是精确的搜索算法(exact search algorithms),束搜索运行的更快,但是不能保证一定能找到argmax的准确的最大值。如果你没听说过广度优先搜索和深度优先搜索,也不用担心,这些对于我们的目标也不重要,如果你听说过,这就是束搜索和其他算法的关系。
好,这就是束搜索。这个算法广泛应用在多产品系统或者许多商业系统上,在深度学习系列课程中的第三门课中,我们讨论了很多关于误差分析(error analysis)的问题。事实上在束搜索上做误差分析是我发现的最有用的工具之一。有时你想知道是否应该增大束宽,我的束宽是否足够好,你可以计算一些简单的东西来指导你需要做什么,来改进你的搜索算法。我们在下节课里进一步讨论。