torch.nn.BCELoss() 两个参数的导数

Derivative in both arguments of torch.nn.BCELoss()

在两个参数上使用 torch.nn.BCELoss() 时,这两个参数都是一些早期计算的结果,我得到一些奇怪的错误,这个问题是关于:

RuntimeError: the derivative for 'target' is not implemented

MCVE如下:

import torch
import torch.nn.functional as F

net1 = torch.nn.Linear(1,1)
net2 = torch.nn.Linear(1,1)
loss_fcn = torch.nn.BCELoss()

x = torch.zeros((1,1))

y = F.sigmoid(net1(x)) #make sure y is in range (0,1)
z = F.sigmoid(net2(y)) #make sure z is in range (0,1)

loss = loss_fcn(z, y) #works if we replace y with y.detach()

loss.backward()

事实证明,如果我们在 y 上调用 .detach(),错误就会消失。但这会导致不同的计算,现在在 .backward()-pass 中,不会计算关于 BCELoss 的第二个参数的梯度。

谁能解释一下我在这种情况下做错了什么?据我所知 torch.nn 中的所有 pytorch 模块都应该支持计算梯度。这个错误消息似乎告诉我导数没有为 y 实现,这有点奇怪,因为你 可以 计算 y 的梯度,但是不是 y.detach() 这似乎是矛盾的。

看来我误解了错误信息。不是 y 不允许计算梯度,而是 BCELoss() 没有能力计算关于第二个参数的梯度。讨论了类似的问题 here

我也遇到了同样的问题。据我所知,BCELoss(input, target)target的第二个参数应该是没有梯度属性的张量。这意味着 target.requires_grad 应该是 False。但是不知道为什么。

通常,target(我们也可以称它为Ground Truth)没有渐变属性。但是target(你代码中的y)是由F.sigmoid(net1(x))计算出来的,也就是说target(net1的输出)已经是一个具有梯度属性的张量了。

所以,你应该试试:

loss = loss_fcn(z, y.detach())

或:

loss = loss_fcn(z, y.data)

也许是这个?

import torch
import torch.nn.functional as F

net1 = torch.nn.Linear(1,1)
net2 = torch.nn.Linear(1,1)
loss_fcn = torch.nn.BCELoss()

x = torch.zeros((1,1))

y = F.sigmoid(net1(x)) #make sure y is in range (0,1)
z = F.sigmoid(net2(y)) #make sure z is in range (0,1)

y.retain_grad()
a = y

loss = loss_fcn(z, a.detach()) #works if we replace y with y.detach()

loss.backward()

print(y.grad)