跳到主内容
快讯直播
AI智模界
AI 词典

数值稳定性:loss 为什么会突然变成 NaN

数值稳定性(numerical stability)说的是:在有限精度的浮点数上做计算,结果是否还能保持有意义。它出问题的信号基本只有两个——NaN(Not a Number,不是数)和 inf(Infinity,无穷大)。训练时 loss 打出 nan,或者几步之后参数全变成 nan,通常就是这两个值一路传染上来的。

浮点数像一把刻度不均匀的尺子:有效位数固定,量程也固定。大到超出量程的读数记成 inf,小到读不出来的量直接记成 0。深度学习中绝大多数 NaN,来自下面四种越界。

一、exp 溢出。 softmax、sigmoid、attention 打分都要算 exp(x)。float16 能表示的最大值是 65504,而 exp(11.1) 就已经超过它。只要某个 logit 大于 11,exp 完就是 inf,再进 softmax 的除法就变成 inf/inf = NaN。标准解法是利用 softmax 的平移不变性:先减去最大值,exp(x − max) 最大只会是 1。

二、log(0)。 交叉熵、KL 散度里全是 log(p)。p 来自 softmax,在 float16 下小于约 6e-8 就下溢成 0,于是 log(0) = −inf,loss 直接变 inf。实践里要么给参数加 eps,要么直接用框架里融合好的 log_softmax / cross_entropy,内部已经做过稳定化处理。

三、除零。 AI 词典:LayerNorm">LayerNorm 除以标准差、各种归一化除以范数、算比率。分母为 0 时,非零除以 0 得到 inf,0 除以 0 得到 NaN。给分母加 eps 是标配,但 eps 选得太小(比如 1e-8 在 float16 里就等于 0)等于没加。

四、NaN 会传染。 inf − inf、0 × inf 都得到 NaN。NaN 一旦出现,反向传播的梯度全是 NaN,优化器一步更新就把所有参数写成 NaN,模型彻底报废。所以要在第一个 NaN 出现的位置抓,而不是看最后那行 loss。

格式指数位尾数位大致量程有效十进制位
float16510±65504约 3 位
bfloat1687±3.4e38约 2 位
float32823±3.4e38约 7 位

float16 的短板不是精度,是量程太窄;bfloat16 反过来,量程和 float32 一样宽,精度更差。混合精度训练中把 loss 乘一个缩放系数再反传(loss scaling),就是为了让梯度避开 float16 的下溢区。

和相邻概念的区别:梯度爆炸(gradient exploding)是数值仍然合法、只是太大,梯度裁剪能救;NaN 是数值已经不合法,裁剪一个 NaN 还是 NaN。前者是量级问题,后者是定义域问题——给 log 传了 0、给 exp 传了一个太大的数、给除法传了 0 分母,都属于“这个函数在该点上没有定义”。

对从业者的实际意义:看到 nan 不必急着重启,按顺序查一遍——先在 loss 之前逐层打印 min/max 和 isnan,定位第一处异常;再检查所有 log、exp、sqrt、除法和归一化;最后看学习率是不是大到让参数本身爆掉。一句话记住:NaN 不是“训练崩了”的原因,而是某个表达式在某个 dtype 下越界的证据。

AI 生成本文由 AI 基于公开信息自动生成,仅供参考。