【问题记录】PyTorch NaN RuntimeError: Function ‘MulBackward0‘ returned nan values in its 0th output. 深度学习

报错:

  1. RuntimeError: Function ‘MulBackward0’ returned nan values in its 0th output.
  2. RuntimeError: Function ‘ExpBackward0’ returned nan values in its 0th output.
  3. 以及其他的nan错误

以此代码为例:

out  = model(input)
pred = out ** (1/4)
loss = 2*nn.MSELoss()(pred ,y)+0.1*nn.L1Loss()(pred ,y)

loss.backward()
optimizer.step()

怎么定位bug位置?

loss.backward()后加入如下代码

loss.backward()

for name, param in model.named_parameters():
    if param.grad is not None and torch.isnan(param.grad).any():
        print("nan gradient found")
        print("name:",name)
        print("param:",param.grad)
        raise SystemExit

打印出反向传播的梯度为NaN的模块名称和参数.

1.找到与之相关的Loss函数,

分别令这些Loss为零

out  = model(input)
pred = out ** (1/4)
loss = 0*nn.MSELoss()(pred ,y)+0.1*nn.L1Loss()(pred ,y)
# loss = 2*nn.MSELoss()(pred ,y)+0*nn.L1Loss()(pred ,y)
# loss = 2*nn.MSELoss()(pred ,y)+0.1*nn.L1Loss()(pred ,y)

loss.backward()
optimizer.step()

测试置零后是否还有NaN错误,如果没有,那就是找对了.
如果所有的Loss置零后还是有NaN问题,则可能是网络中参数的问题,本文不讨论。

2.查看这个Loss函数的变量

假设将nn.MSELoss()(pred ,y)置零后NaN错误消失了。

溯源该损失函数的变量pred,找到pred = out ** (1/4)
试着把它改成pred = out,发现正确运行!
则问题就是出在pred = out ** (1/4)这句代码。

3.诊断

问题在于pred的梯度为 1 4 out − 3 4 {1\over4}\text{out}^{-{3\over4}} 41out43
out = 0 \text{out}=0 out=0时, out − 3 4 ∣ o u t = 0 → NaN \text{out}^{-{3\over4}}|_{out=0} \rightarrow \text{NaN} out43out=0NaN

因此前向传播是是正确的,反向传播报错。

但也不是立马就报错,因为只有出现 out = 0 \text{out}=0 out=0才会有问题,所以甚至可以训练几个周期,后来才报错。

找到病因,对症下药即可:

# pred = out ** (1/4)
eps = 1e-5
red = (out+eps) ** (1/4)

总结

NaN问题一般都是由于定义域引起的。

常见的 log ⁡ ( x ) \log(x) log(x), 1 / x 1/x 1/x, x \sqrt x x 都容易出现此类问题。

同时导数的定义域也是要考虑的因素。

x 1 4 x^{1\over 4} x41的导数就是 1 4 x 3 / 4 {1\over 4 x^{3/4}} 4x3/41,原函数可以取 0 0 0 ,但导数却不可以,容易被忽视。

你可能感兴趣的:(深度学习,pytorch,python)