最近在复现一个图像分割的模型,用的是PyTorch 1.13,数据集大概两万张。训练到第3个epoch左右loss突然变成NaN,试过Adam和SGD都一样。学习率已经降到1e-4了,加了梯度裁剪也没什么效果。检查过数据没有脏数据,输入也normalize了。网络里用了BatchNorm和残差连接,不确定是不是跟这个有关。有没有大佬遇到过类似情况,一般从哪入手排查比较好?
PyTorch训练时loss突然变NaN,换了几个优化器都没用,有人遇到过吗?
全部回复
共 7 条BN在batch小的时候确实容易炸,我之前也是第3个epoch开始NaN,换成GroupNorm就好了。
我之前也踩过这个坑,第3个epoch才炸,大概率不是数据的问题,更像是某些层在训练过程中把数值推到了极端。你可以先试试在backward里加个hook,把每层梯度的norm打出来,看看到底是哪一层先爆的,比盲调优化器有用多了。BatchNorm在batch比较小或者某些通道方差接近0的时候,确实容易放大数值,特别是配合残差结构。另外损失函数里如果有log或者除法,记得加eps,像分割常用的dice或者focal,分母没保护的话很容易出NaN。还有个容易忽略的点是混合精度,如果你开了amp,fp16溢出会直接变NaN,可以先关掉跑一遍确认。我之前最后是靠把BN换成GroupNorm加上在loss里clamp才稳住的,你可以从梯度hook入手,定位到具体层再决定怎么改。
BN在batch小的时候确实容易炸,试试换成GroupNorm或LayerNorm?
第3个epoch才炸,感觉像是训练过程中某个中间量慢慢飘了。我之前遇到过类似情况,最后查出来是BatchNorm在某个小batch上方差趋近0,除出来直接炸了,你可以试试打印每层的输出范围看看到底是哪一层先出问题。另外残差连接里如果有一路数值持续放大也容易这样,加个weight decay或者调小初始化试试?
这个现象我也踩过坑,第3个epoch才炸有点像某个batch里出现了极端值,不一定是数据脏,可能是增强后的图或者mask边界出了状况。BatchNorm在batch size偏小的时候统计量会很不稳,残差连接又会把异常值一路放大,两个凑一起确实容易在第几个epoch突然崩。建议你先在loss变NaN前的那几十步把每层的梯度norm和激活值max打出来,看是哪一层先冒头的。另外可以试试把BatchNorm换成GroupNorm,或者在残差分支上加个小的epsilon,很多时候就压住了。还有个容易忽略的点是AMP混合精度,如果开了的话scaler没调好也会在中期炸掉,先关掉跑一遍确认一下。如果换了优化器都一样,那基本能排除优化器本身,重点往数值稳定性和某个特定样本上查。
试试把BN的eps调大点,或者检查下有没有除零的地方,我之前也是这问题。
BN在batch小的时候容易出问题,试试换成GroupNorm或者调大batch size?