np.exp会返回inf是因为输入值过大(如x>709)超出float64指数范围,导致静默溢出;常用解决法是先用np.clip(x,-700,700)截断再计算,或直接使用scipy.special.softmax等内置稳定实现。

为什么 np.exp 会报错或返回 inf?
根本原因是输入值过大(比如 x > 709),超出 float64 能表示的指数范围,np.exp(x) 直接返回 inf,后续计算(如除法、log)就可能触发 RuntimeWarning 或 nan。这不是“报错”而是静默溢出,但实际效果和报错一样——结果不可用。
用 np.exp 前先做数值截断
最常用也最安全的做法:把过大的输入限制在合理范围内,比如用 np.clip 把输入压到 [-700, 700] 以内(np.exp(700) 已是 ~1e304,足够覆盖绝大多数 softmax 场景)。
-
np.exp(np.clip(x, -700, 700))可避免inf - 若原始数据含极大正值(如 logits 达 1000+),说明模型输出未归一化,应检查前序逻辑
- 注意:
clip是硬截断,对极小负值(如-1000)也会被拉到-700,但np.exp(-700)≈ 0,不影响精度
用 scipy.special.expit 或 logsumexp 替代裸 exp
直接调 np.exp 往往是为算 softmax 或 sigmoid;这些已有稳定实现,不该自己手写。
- 算 sigmoid:用
scipy.special.expit(x),内部做了数值保护,支持任意实数输入 - 算 softmax:用
scipy.special.softmax(x, axis=-1),自动减去最大值再 exp - 手动实现 softmax 时,务必先减去每行最大值:
np.exp(x - np.max(x, axis=-1, keepdims=True)) - 需要 log-sum-exp?别写
np.log(np.sum(np.exp(x))),改用scipy.special.logsumexp(x)
调试时怎么快速定位溢出源头?
别等结果出 nan 再查,提前加一行检测:
立即学习“Python免费学习笔记(深入)”;
assert not np.any(np.isinf(x) | np.isnan(x)), f"input contains inf/nan: {x}"更实用的是监控中间值:
- 打印
np.max(x)和np.min(x),若超过 ±800 就该警惕 - 训练中可在 loss 计算前加
if np.any(np.abs(x) > 800): print("large logits detected") -
np.finfo(float).max返回 ~1.8e308,而np.exp(709.78)就溢出,所以安全上限取 700 更稳妥
真正麻烦的不是溢出本身,而是它常藏在链式计算里——比如一个 np.exp 的输入来自另一个没 clip 的 np.exp 输出,这种嵌套放大容易漏查。


















