【debug】pytorch损失/梯度出现NaN
排查顺序
最常见的就是出现了除0或者log0这种,看看代码中在这种操作的时候有没有加一个很小的数,但是这个数数量级要和运算的数的数量级要差很多。一般是1e-8。
在optim.step()之前裁剪梯度。
optim.zero_grad() loss.backward() nn.utils.clip_grad_norm(model.parameters, max_norm, norm_type=2) optim.step()
max_norm一般是1,3,5。
前面两条还不能解决nan的话,就按照下面的流程来判断。
...
loss = model(input)
1. 先看loss是不是nan,如果loss是nan,那么说明可能是在forward的过程中出现了第一条列举的除0或者log0的操作
assert torch.isnan(loss).sum() == 0, print(loss)
2. 如果loss不是nan,那么说明forward过程没问题,可能是梯度爆炸,所以用梯度裁剪试试
optim.zero_grad()
loss.backward()
nn.utils.clip_grad_norm(model.parameters, max_norm, norm_type=2)
3.1 在step之前,判断参数是不是nan, 如果不是判断step之后是不是nan
assert torch.isnan(model.mu).sum() == 0, print(model.mu) optim.step()
3.2 在step之后判断,参数和其梯度是不是nan,如果3.1不是nan,而3.2是nan,特别是梯度出现了Nan,考虑学习速率是否太大,调小学习速率或者换个优化器试试。
assert torch.isnan(model.mu).sum() == 0, print(model.mu) assert torch.isnan(model.mu.grad).sum() == 0, print(model.mu.grad)
4. 如果还有问题的话,尝试定位出问题的tensor
梯度NaN定位方法
使用如下代码设置,在出现NaN异常时程序会报错,便于定位错误代码
import torch # 正向传播时:开启自动求导的异常侦测 torch.autograd.set_detect_anomaly(True) # 反向传播时:在求导时开启侦测 with torch.autograd.detect_anomaly(): loss.backward()
常见原因
- 使用了非法的操作如log(0)、÷0等
- 使用FP16
- FP16越界,如使用操作softmax、矩阵乘、EPS>1e-7等,解决方案就是先转换为FP32在运算
- loss scale设置不合适,解决方案是使用‘dynamic’自动搜索
- 很多网友提到,pytorch的求标准差的函数STD可能有问题。如果使用了类似会调用STD函数的各种Norm层就可能导致NAN问题。
- 还有bfloat16 (BF16) 进行混合精度训练时,通常不需要使用
GradScaler,因为BF16拥有与FP32相同的指数范围,能够有效避免梯度下溢的问题,使用scaler反而会导致梯度爆炸。


浙公网安备 33010602011771号