机器学习数学基础 120 章

上溢、下溢与数值稳定技巧

层级:A|建议先修:03-12、09-01

概率模型常把很多小概率相乘,神经网络常计算很大的指数。直接照抄数学公式,可能得到 0、无穷或 NaN。数值稳定的核心是改写成数学等价、计算范围更安全的形式。

1. 上溢与下溢

  • 上溢:结果绝对值超过浮点格式最大有限值,常变成 \infty
  • 下溢:结果绝对值过小,逐渐进入次正规区或变成 0。

例如 e1000e^{1000} 在常用格式中上溢;连续相乘几百个小于 1 的概率可能下溢为 0。

2. 在对数域计算乘积

L=i=1npi,L=\prod_{i=1}^np_i,

logL=i=1nlogpi.\log L=\sum_{i=1}^n\log p_i.

对数把极小乘积变成中等大小的负数之和。极大似然训练通常最大化 log-likelihood,而不是直接最大化 likelihood。

比较两个正数乘积大小时,只比较它们的对数即可,无需再指数还原。

3. log-sum-exp

要计算

LSE(z)=logiezi,\operatorname{LSE}(z)=\log\sum_i e^{z_i},

m=maxizim=\max_i z_i,则

LSE(z)=m+logiezim.\operatorname{LSE}(z) =m+\log\sum_i e^{z_i-m}.

由于所有 zim0z_i-m\le0,指数项不超过 1,避免上溢;至少一个指数项为 1,也降低全部下溢为 0 的风险。

4. 稳定 Softmax

Softmax 为

pi=ezijezj.p_i=\frac{e^{z_i}}{\sum_je^{z_j}}.

对所有 logits 减去同一常数不改变结果:

pi=ezimjezjm.p_i=\frac{e^{z_i-m}}{\sum_je^{z_j-m}}.

通常取 m=maxjzjm=\max_jz_j。若需要 log-softmax,直接计算

logpi=ziLSE(z)\log p_i=z_i-\operatorname{LSE}(z)

比先求 pip_i 再取对数稳定。

5. 稳定 sigmoid 与 softplus

Sigmoid

σ(x)=11+ex\sigma(x)=\frac1{1+e^{-x}}

x0x\ll0exe^{-x} 可能上溢。可分支计算:

σ(x)={1/(1+ex),x0,ex/(1+ex),x<0.\sigma(x)= \begin{cases} 1/(1+e^{-x}),&x\ge0,\\ e^x/(1+e^x),&x<0. \end{cases}

Softplus log(1+ex)\log(1+e^x) 可稳定写成

max(x,0)+log(1+ex).\max(x,0)+\log(1+e^{-|x|}).

6. 二元交叉熵直接用 logits

令标签 y{0,1}y\in\{0,1\}、logit 为 zz。与 sigmoid 后二元交叉熵等价的稳定形式为

L=max(z,0)yz+log(1+ez).L=\max(z,0)-yz+\log(1+e^{-|z|}).

这避免了先得到精确 0 或 1 的概率再取对数。工程中应使用 binary_cross_entropy_with_logits 一类融合接口。

7. log1pexpm1

xx 很小时:

  • log(1+x) 中的 1+x1+x 可能先舍入成 1;使用 log1p(x)
  • exp(x)-1 中两个接近 1 的数相减会消去;使用 expm1(x)

这些库函数用专门近似保持小量精度。

8. 概率归一化

若只有对数权重 ai=logp~ia_i=\log\tilde p_i,归一化对数概率为

logpi=aiLSE(a).\log p_i=a_i-\operatorname{LSE}(a).

只有最终确实需要普通概率时才指数化。这适用于 HMM、Bayesian 推断、混合模型和采样权重。

9. 避免除以极小数

分母接近 0 会放大误差。常见方法:

  • 对范数、方差分母加入与尺度匹配的 ε\varepsilon
  • 对概率做合理裁剪后再取对数;
  • 使用正则化改善线性系统;
  • 重新参数化保证正数,如用 softplus 表示方差。

加入 ε\varepsilon 会改变数学问题,必须说明其量级和影响,不能作为掩盖错误的万能补丁。

10. 归一化与缩放

输入特征尺度差异过大,会造成梯度和线性系统条件恶化。标准化、中心化、白化和合理参数初始化可让数值落在更安全的范围。

混合精度训练常用 loss scaling:反向前放大损失和梯度,避免低精度梯度下溢;更新前再除回尺度,并检测无穷值动态调整。

11. 检测异常值

训练循环应尽早检测:

  • 输入、参数、激活、损失和梯度是否有限;
  • 第一次出现 NaN/Inf 的层和操作;
  • 梯度范数、激活范围和学习率;
  • 数据中是否存在非法值或除零。

NaN 会沿计算图迅速传播,定位“第一次出现”比只看最终损失更有效。

12. 梯度裁剪

梯度范数裁剪将 gg 缩放为

ggmin(1,cg).g\leftarrow g\min\left(1,\frac{c}{\|g\|}\right).

它可缓解爆炸梯度,却不能修复错误模型、过大学习率或持续数值不稳定。裁剪阈值应被记录和验证。

13. 易错点

  1. Softmax 前减最大值不会改变精确数学结果。
  2. 给所有概率无脑加固定 epsilon 会破坏归一化和概率语义。
  3. log(softmax(z)) 应由 log_softmax(z) 替代。
  4. NaN 不总是上溢造成,也可能来自无效运算、数据缺失或梯度爆炸。

常见问答

Q1:概率已经下溢为 0,再取对数能恢复吗?
不能。必须从一开始就在对数域计算,避免信息先丢失。

Q2:为什么减去最大 logit 后 Softmax 不变?
分子分母都乘以同一个 eme^{-m},比例保持不变。

Q3:概率裁剪会不会让梯度有偏?
会改变原目标,尤其在边界附近。优先使用稳定 logits 公式;裁剪应作为有意识的近似。

Q4:用了 float64 就不需要稳定公式了吗?
仍需要。float64 范围更大、精度更高,但指数和长概率乘积仍可能溢出或下溢。

练习

  1. 稳定计算 log(e1000+e999)\log(e^{1000}+e^{999})
  2. 证明 Softmax 对所有 logits 加同一常数保持不变。
  3. 为什么小 xx 时应使用 log1p(x)
  4. 写出 log 权重 aia_i 归一化为 log 概率的公式。

答案与提示

  1. 1000+log(1+e1)1000+\log(1+e^{-1})
  2. 每项指数都乘 ece^c,在分子分母中相消。
  3. 普通计算会先形成 1+x1+x,小量 xx 可能在舍入中消失;专用函数直接保留小量信息。
  4. logpi=aiLSE(a)\log p_i=a_i-\operatorname{LSE}(a)