当我使用如下损失函数时,损失总是 Nan:
def Myloss1(source, target):
loss = torch.nn.functional.mse_loss(source, target, reduction="none")
return torch.sum(loss).sqrt()
...
loss = Myloss1(s, t)
loss.backward()
但是当我使用以下损失函数时,训练变得正常:
def Myloss2(source, target):
diff = target - source
loss = torch.norm(diff)
return loss
...
loss = Myloss2(s, t)
loss.backward()
为什么不能用‘Myloss1’来训练?Myloss1和Myloss2不是等价的吗?
请帮帮我,非常感谢!
答案 0 :(得分:0)
Myloss1
和 Myloss2
确实应该是等价的。它们至少为我尝试过的所有张量返回相同的值。
关于Nan,让我们先试着找出它发生的时间。这里唯一可能的罪魁祸首是 sqrt
,它在 0 中不可微。而且确实:
y = torch.randn(2,3)
x = y.clone()
x.requires_grad_(True)
Myloss1(x,y).backward()
print(x.grad.data)
>>> [[nan, nan, nan], [nan, nan, nan]]
另一方面:
Myloss2(x,y).backward()
print(x.grad.data)
>>> [[-0., -0., -0.],[-0., -0., -0.]]
在这两个结果中,只有第一个在数学上是“准确的”。计算平方根在 0 处的导数会产生除以 0。这就是为什么在训练神经网络或其他任何东西时,不使用 sqrt
。你应该使用
good_loss = torch.nn.MSELoss(reduction='mean') # or ='sum' if you prefer
这个函数到处都是可微的,你不会再有麻烦了。
至于为什么您的 Myloss2
会产生不同的梯度,这与其实现有关。它被广泛讨论here。基本上,人们抱怨 nans,因此更改了 lib 以修改此行为,同时承认此处没有数学上正确的答案,因为此导数未定义为 0。