pytorch - 当我使用由 torch.nn.function.mse_loss 定义的损失函数时,损失将是 Nan
问题描述
当我使用如下损失函数时,损失总是 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不是等价的吗?
请帮帮我,非常感谢!</p>
解决方案
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
产生不同的梯度,这与它的实现有关。它在这里被广泛讨论。基本上,人们抱怨 nans,因此更改了 lib 以修改此行为,同时承认这里没有数学上正确的答案,因为此导数未定义为 0。
推荐阅读
- python-3.x - 比较两个数组并获取不常见的值
- linux - Imagemagick ftp 和空间
- c# - 根据 Y 值在 Unity 中跳跃不一致
- neo4j - 如何在嵌入式 neo4j 中使用“apoc.util.md5”
- javascript - 将 google doc 转换为 pdf 会导致空白 pdf、google 脚本
- azure-devops - 当我尝试通过 VS2017 打开 VSTS 任务时,日期可见但时间不可见
- sql-server - 动态 SQL 查询以查找表的所有列的缺失值计数
- android - RecyclerView 中的并发修改
- c# - Resharper 是否为 C# 类/方法/属性的 Visual Studio 提供了额外的 XML Doc 功能?
- android - 拥有多个 Launcher Activity