我正在使用PyTorch来计算逻辑回归的损失(我知道PyTorch可以自动完成,但我必须自己实现)。我的函数定义如下,但转换为torch.tensor会破坏自动梯度,并导致w.grad = None。我是PyTorch的新手,所以很抱歉。
logistic_loss = lambda X,y,w: torch.tensor([torch.log(1 + torch.exp(-y[i] * torch.matmul(w, X[i,:]))) for i in range(X.shape[0])], requires_grad=True)
回答:
你的帖子在细节上不够清晰,而且这是一个非常复杂的一行代码。我首先重新编写了它,以创建一个最小、完整、可验证的示例。如果我误解了你的意图,请纠正我,并且请你下次自己做。
解决你问题的简单方法是用torch.stack(elementwise)
替换torch.tensor(elementwise, requires_grad=True)
。你可以将torch.tensor
视为创建全新张量的构造函数,如果你的张量更多的是某种数学表达式的结果,你应该使用像torch.stack
或torch.cat
这样的操作。
尽管如此,这段代码仍然非常低效,因为你手动循环了i
。相反,你可以简单地写成
def logistic_loss_vectorized(X, y, w):
mm = torch.matmul(X, w)
exp = torch.exp(-y * mm)
return torch.log(1 + exp)
这在数学上是等价的,但在实践中会快得多,因为它允许更好的并行化,由于没有显式循环。
请注意,这段代码仍然存在数值问题 – 你在取一个指数的对数,但中间结果,称为exp
,可能会达到非常高的值,导致精度损失。对此有解决方法,这就是为什么PyTorch提供的损失函数更可取的原因。