gpt4 book ai didi

python - 损失函数中的所有变量都必须是 pytorch 中带有 grads 的张量吗?

转载 作者:行者123 更新时间:2023-12-04 02:42:45 26 4
gpt4 key购买 nike

我有以下功能


def msfe(ys, ts):
ys=ys.detach().numpy() #output from the network
ts=ts.detach().numpy() #Target (true labels)
pred_class = (ys>=0.5)
n_0 = sum(ts==0) #Number of true negatives
n_1 = sum(ts==1) #Number of true positives
FPE = sum((ts==0)[[bool(p) for p in (pred_class==1)]])/n_0 #False positive error
FNE = sum((ts==1)[[bool(p) for p in (pred_class==0)]])/n_1 #False negative error
loss= FPE**2+FNE**2

loss=torch.tensor(loss,dtype=torch.float64,requires_grad=True)


return loss

我想知道 Pytorch 中的 autograd 是否正常工作,因为 ysts没有 grad旗帜。

所以我的问题是:在 FPE,FNE,ys,ts,n_1,n_0 之前,所有变量( optimizer.step() )都必须是张量吗?工作,或者它只是最后一个函数( loss )是可以的吗?

最佳答案

您想通过 optimizer.step() 优化的所有变量需要有渐变。

在您的情况下,它将是 y由网络预测,所以你不应该detach它(来自图表)。

通常你不会改变你的targets ,所以那些不需要渐变。你不应该detach不过,默认情况下,张量不需要梯度,也不会反向传播。
Loss如果它的成分(至少一种)有渐变,就会有渐变。

总的来说,您很少需要手动处理它。

顺便提一句。 不要使用 numpy使用 PyTorch,很少有这种情况。您可以在 numpy 上执行您可以执行的大部分操作。 PyTorch 张量上的数组。

顺便说一句。没有 Variable 这样的东西在 pytorch不再,只有需要梯度的张量和不需要的张量。

不可微分

1.1 现有代码的问题

实际上,您正在使用不可微分的函数(即 >=== )。那些只会在输出的情况下给你带来麻烦,因为那些需要梯度(你可以使用 ==>= 来表示 targets)。

下面我附上了您的损失函数,并在评论中概述了其中的问题:

# Gradient can't propagate if you detach and work in another framework
# Most Python constructs should be fine, detaching will ruin it though.
def msfe(outputs, targets):
# outputs=outputs.detach().numpy() # Do not detach, no need to do that
# targets=targets.detach().numpy() # No need for numpy either
pred_class = outputs >= 0.5 # This one is non-differentiable
# n_0 = sum(targets==0) # Do not use sum, there is pytorch function for that
# n_1 = sum(targets==1)

n_0 = torch.sum(targets == 0) # Those are not differentiable, but...
n_1 = torch.sum(targets == 1) # It does not matter as those are targets

# FPE = sum((targets==0)[[bool(p) for p in (pred_class==1)]])/n_0 # Do not use Python bools
# FNE = sum((targets==1)[[bool(p) for p in (pred_class==0)]])/n_1 # Stay within PyTorch
# Those two below are non-differentiable due to == sign as well
FPE = torch.sum((targets == 0.0) * (pred_class == 1.0)).float() / n_0
FNE = torch.sum((targets == 1.0) * (pred_class == 0.0)).float() / n_1
# This is obviously fine
loss = FPE ** 2 + FNE ** 2

# Loss should be a tensor already, don't do things like that
# Gradient will not be propagated, you will have a new tensor
# Always returning gradient of `1` and that's all
# loss = torch.tensor(loss, dtype=torch.float64, requires_grad=True)

return loss

1.2 可能的解决方案

因此,您需要摆脱 3 个不可微分的部分。原则上,您可以尝试使用网络的连续输出来近似它(前提是您使用 sigmoid 作为激活)。这是我的看法:
def msfe_approximation(outputs, targets):
n_0 = torch.sum(targets == 0) # Gradient does not flow through it, it's okay
n_1 = torch.sum(targets == 1) # Same as above
FPE = torch.sum((targets == 0) * outputs).float() / n_0
FNE = torch.sum((targets == 1) * (1 - outputs)).float() / n_1

return FPE ** 2 + FNE ** 2

请注意,要最小化 FPE outputs会努力成为 zero在指数上 targets为零。 FNE 类似, 如果目标是 1 , 网络会尝试输出 1以及。

注意这个想法与 BCELoss 的相似性(二元交叉熵)。

最后,您可以运行此示例,仅用于完整性检查:
if __name__ == "__main__":
model = torch.nn.Sequential(
torch.nn.Linear(30, 100),
torch.nn.ReLU(),
torch.nn.Linear(100, 200),
torch.nn.ReLU(),
torch.nn.Linear(200, 1),
torch.nn.Sigmoid(),
)
optimizer = torch.optim.Adam(model.parameters())
targets = torch.randint(high=2, size=(64, 1)) # random targets
inputs = torch.rand(64, 30) # random data
for _ in range(1000):
optimizer.zero_grad()
outputs = model(inputs)
loss = msfe_approximation(outputs, targets)
print(loss)
loss.backward()
optimizer.step()

print(((model(inputs) >= 0.5) == targets).float().mean())

关于python - 损失函数中的所有变量都必须是 pytorch 中带有 grads 的张量吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58560316/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com