2023年11月29日发(作者:)

警惕!损失LossNan或者超级⼤的原因

转⾃:

前⾔

训练或者预测过程中经常会遇到训练损失值或者验证损失值不正常、⽆穷⼤、或者直接nan的情况:

遇到这样的现象,通常有以下⼏个原因导致:

梯度爆炸造成Loss爆炸

原因很简单,学习率较⾼的情况下,直接影响到每次更新值的程度⽐较⼤,⾛的步伐因此也会⼤起来。如下图,过⼤的学习率会导致⽆法顺

利地到达最低点,稍有不慎就会跳出可控制区域,此时我们将要⾯对的就是损失成倍增⼤(跨量级)。

另外,这种情况很容易在⽹络层数⽐较深的时候出现,借⽤的⼀段话:

这就是典型的梯度爆炸,解决⽅法也很简单,降低初始的学习率,并设置学习率衰减。

检查输⼊数据和输出数据

通常我们都会保证输⼊的数据是否正确(这个要是不能保证那么后续也就没必要继续了..)。⼀般输⼊不正确的话可以⽴马观察出来。

有两种情况可能并不是那么容易检测到:

数据⽐较多,99%的数据是对的,但有1%的数据不正常,或者损坏,在训练过程中这些数据往往会造成nan或者inf,这时候需要仔细

挑选⾃⼰的数据,关于如何挑选数据()。

在神经⽹络中,很有可能在前⼏层的输⼊是正确的,但是到了某⼀层的时候输出就会变成nan或者inf(其中-inf代表负⽆穷,⽽nan代表不存在

的数),这个时候就需要通过debug去⼀⼀检查。

当然我们可以在⾃⼰代码中添加检测函数。

例如在Pytorch框架中我们可以使⽤_anomaly类来监测训练或者预测过程中遇到的隐晦的问题:

>>> import torch

>>> from torch import autograd

>>> class MyFunc(on):

... @staticmethod

... def forward(ctx, inp):

... return ()

... @staticmethod

... def backward(ctx, gO):

... # Error during the backward pass

... raise RuntimeError("Some error in backward")

... return ()

>>> def run_fn(a):

... out = (a)

... return ()

>>> inp = (10, 10, requires_grad=True)

batchNorm可能捣⿁

如果你的⽹络中batchNorm层很多,⽽且充当⽐较重要的⾓⾊,那么可以适当地检查⼀下Tensor在输⼊Batchnorm层后有没有可能变

nan,如果恰好发⽣这种情况,batchNorm层中的移动均值(running_mean)和移动⽅差(running_var)也很有可能都是nan,⽽且这种情

况很有可能发⽣在预测阶段。

这种情况通过发⽣在训练集和验证集是两个截然不同的分布的时候,这是在训练集中学习到的均值和⽅法在验证集中是没有作⽤反⽽会捣

乱。或者在⼀个神经⽹络中存在两种结构不同的阵营:典型的是Unet,当在⾃定义Unet的时候,编码⽹络和解码⽹络如果是两个结构存在

较⼤差异的⽹络,那么在编码阶段学习到的分布在解码阶段就会出现问题。

举个真实的例⼦:Unet + resnet34 表现正常,但是使⽤Unet + resnext50 则造成损失爆炸(将解码阶段的batchnorm层失效后表现正

常)。

当然上述现象出现的原因⼤部分在当我们使⽤()(Pytorch)之后发⽣。如果你在预测阶段也将模型model设置

(True),那么问题可能就不会出现:

解决⽅式:

或者设置Batchnorm中的参数track_running_stats=False使移动均值和移动⽅差不起作⽤:

采⽤stride⼤于kernel size的池化层

在卷积层的卷积步伐⼤于卷积核⼤⼩的时候,有可能产⽣nan

⽐如:

layer {

name: "faulty_pooling"

type: "Pooling"

bottom: "x"

top: "y"

pooling_param {

pool: AVE

stride: 5

kernel: 3