我正在尝试使用 pytorch 的 BCELoss 函数计算二元分类问题的交叉熵损失。在修修补补时,我发现了这种奇怪的行为。
from torch import nn
sigmoid = nn.Sigmoid()
loss = nn.BCELoss(reduction="sum")
target = torch.tensor([0., 1.])
input1 = torch.tensor([1., 1.], requires_grad=True)
input2 = sigmoid(torch.tensor([10., 10.], requires_grad=True))
print(input2) #tensor([1.0000, 1.0000], grad_fn=<SigmoidBackward>)
print(loss(input1, target)) #tensor(100., grad_fn=<BinaryCrossEntropyBackward>)
print(loss(input2, target)) #tensor(9.9996, grad_fn=<BinaryCrossEntropyBackward>)
由于 input1 和 input2 具有相同的值,因此不应该返回相同的损失值而不是 100 和 9.9996。正确的损失值应该是 100,因为我乘以 log(0) ~-infinity,在 pytorch 中上限为 -100。 https://pytorch.org/docs/stable/generated/torch.nn.BCELoss.html
这里发生了什么,我哪里出错了?
答案 0 :(得分:2)
sigmoid(10)
不完全等于 1:
>>> 1 / (1 + torch.exp(-torch.tensor(10.))).item()
0.9999545833234493
就你而言:
>>> sigmoid(torch.tensor([10., 10.], requires_grad=True)).tolist()
[0.9999545812606812, 0.9999545812606812]
因此 input1
与 input2
不同:[1.0, 1.0]
vs [0.9999545812606812, 0.9999545812606812]
,
让我们手动计算 BCE:
def bce(x, y):
return - (y * torch.log(x) + (1 - y) * torch.log(1 - x)).item()
# input1
x1 = torch.tensor(1.)
x2 = torch.tensor(1.)
y1 = torch.tensor(0.)
y2 = torch.tensor(1.)
print("input1:", sum([bce(x1, y1), bce(x2, y2)]))
# input2
x1 = torch.tensor(0.9999545812606812)
x2 = torch.tensor(0.9999545812606812)
y1 = torch.tensor(0.)
y2 = torch.tensor(1.)
print("input2:", sum([bce(x1, y1), bce(x2, y2)]))
input1: nan
input2: 9.999631525119185
对于 input1
,我们得到 nan
,但根据文档:
我们的解决方案是 BCELoss 将其对数函数输出限制为大于或等于 -100。这样,我们总是可以有一个有限的损失值和一个线性反向方法。
这就是为什么我们在最终的 100
的 pytorch
输出中有 BCE
。