04 改进集束搜索(Refinements to Beam Search)
04 改进集束搜索(Refinements to Beam Search)
这一节在讲什么
上一节已经知道束搜索怎么跑了,这一节讲两个实战里非常重要的改进:
- 用
log概率代替原始概率连乘 - 用长度归一化,避免模型偏爱短句子
为什么不能直接乘概率
整句概率是:
\[P(y\mid x)=\prod_{t=1}^{T_y} P(y^{\langle t \rangle} \mid x, y^{\langle 1:t-1 \rangle})\]问题在于:每一项都小于 1。
例如:
- $0.6 \times 0.5 \times 0.7 \times 0.4$ 会越来越小
- 句子越长,乘出来的值越接近 0
这样容易造成数值下溢(underflow),也就是电脑存不准那么小的数。
所以要取对数
因为对数函数单调递增,所以:
\[\arg\max_y P(y\mid x) \quad \text{和} \quad \arg\max_y \log P(y\mid x)\]得到的最优 $y$ 是一样的。
而且:
\[\log P(y\mid x) = \sum_{t=1}^{T_y} \log P(y^{\langle t \rangle} \mid x, y^{\langle 1:t-1 \rangle})\]这样就把“连乘”变成了“连加”,数值稳定很多。
但还会有第二个问题:偏爱短句子
即使用对数后,长句子还是更吃亏。
因为:
- 每一项的 $\log$ 通常是负数
- 句子越长,负数加得越多
- 总分就越低
结果就是模型可能不自然地偏向更短的翻译。
长度归一化怎么做
最简单的做法是除以输出长度 $T_y$:
\[\text{score}(y) = \frac{1}{T_y} \sum_{t=1}^{T_y} \log P(y^{\langle t \rangle} \mid x, y^{\langle 1:t-1 \rangle})\]这样相当于求“每个词平均的对数概率”,而不是整句总和。
你可以把它理解为:
不再因为句子长就天然吃亏,而是看平均质量。
更常用的柔和版本
课程里还讲了一个更常见的经验式写法:
\[\text{score}(y) = \frac{1}{T_y^{\alpha}} \sum_{t=1}^{T_y} \log P(y^{\langle t \rangle} \mid x, y^{\langle 1:t-1 \rangle})\]其中:
- $\alpha = 0$ 表示完全不做长度归一化
- $\alpha = 1$ 表示完全按长度平均
- 实战里常会试 $\alpha = 0.7$
这是个经验超参数,没有非常漂亮的理论推导,但实践中往往有效。
束宽 $B$ 怎么选
这一节也顺带讲了束宽选择。
如果 $B$ 大
优点:
- 搜索更充分
- 更可能找到更好的句子
缺点:
- 更慢
- 占更多内存
如果 $B$ 小
优点:
- 更快
- 更省资源
缺点:
- 容易错过更好候选
课程里提到:
- 教学示例常用 $B=3$
- 产品里常见 $B=10$
- 做研究时甚至有人用到更大的束宽
小白可以怎么理解长度归一化
假设两句候选:
- 句子 A:很短,只说了一半
- 句子 B:更完整,但词更多
如果只看总概率,A 可能更高,因为它少乘了很多次小于 1 的数。
但显然,A 未必是更好的翻译。
长度归一化就是在纠正这个偏差。
这一节最该记住的公式
原始目标
\[P(y\mid x)=\prod_{t=1}^{T_y} P(y^{\langle t \rangle} \mid x, y^{\langle 1:t-1 \rangle})\]对数形式
\[\log P(y\mid x) = \sum_{t=1}^{T_y} \log P(y^{\langle t \rangle} \mid x, y^{\langle 1:t-1 \rangle})\]长度归一化
\[\text{score}(y) = \frac{1}{T_y^{\alpha}} \sum_{t=1}^{T_y} \log P(y^{\langle t \rangle} \mid x, y^{\langle 1:t-1 \rangle})\]这一节最该记住的要点
要点 1:连乘概率容易数值下溢
所以实战几乎都改用对数和。
要点 2:不做长度归一化会偏向短句
这是束搜索常见偏差。
要点 3:长度归一化本质是在做公平比较
它避免“句子短所以天然得分高”。
要点 4:束宽是效果和成本的折中
没有固定万能值,要试验。
这一节一句话总结
实战中的束搜索不会直接比原始概率,而是比“长度归一化后的对数概率分数”,这样既更稳定,也更不容易偏向过短的输出。
本文由作者按照 CC BY 4.0 进行授权