元素明智的计算打破了autograd
Element wise calculation breaks autograd
我正在使用 pytorch 来计算逻辑回归的损失(我知道 pytorch 可以自动执行此操作,但我必须自己制作)。我的函数在下面定义,但是转换为 torch.tensor 会破坏 autograd 并给我 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)
你的 post 不是很清楚细节,这是单行本的怪物。我首先对其进行了修改以制作一个 minimal, complete, verifiable 示例。如果我误解了你的意图,请指正我,下次你自己做。
import torch
# unroll the one-liner to have an easier time understanding what's going on
def logistic_loss(X, y, w):
elementwise = []
for i in range(X.shape[0]):
mm = torch.matmul(w, X[i, :])
exp = torch.exp(-y[i] * mm)
elementwise.append(torch.log(1 + exp))
return torch.tensor(elementwise, requires_grad=True)
# I assume that's the excepted dimensions of your input
X = torch.randn(5, 30, requires_grad=True)
y = torch.randn(5)
w = torch.randn(30)
# I assume you backpropagate from a reduced version
# of your sum, because you can't call .backward on multi-dimensional
# tensors
loss = logistic_loss(X, y, w).mean()
loss.mean().backward()
print(X.grad)
解决您问题的最简单方法是将 torch.tensor(elementwise, requires_grad=True)
替换为 torch.stack(elementwise)
。您可以将 torch.tensor
视为全新张量的构造函数,如果您的张量更多是某种数学表达式的结果,则应使用 torch.stack
或 torch.cat
.[=21 等操作=]
话虽如此,这段代码仍然非常低效,因为您需要手动循环 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 提供的损失函数更可取。
我正在使用 pytorch 来计算逻辑回归的损失(我知道 pytorch 可以自动执行此操作,但我必须自己制作)。我的函数在下面定义,但是转换为 torch.tensor 会破坏 autograd 并给我 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)
你的 post 不是很清楚细节,这是单行本的怪物。我首先对其进行了修改以制作一个 minimal, complete, verifiable 示例。如果我误解了你的意图,请指正我,下次你自己做。
import torch
# unroll the one-liner to have an easier time understanding what's going on
def logistic_loss(X, y, w):
elementwise = []
for i in range(X.shape[0]):
mm = torch.matmul(w, X[i, :])
exp = torch.exp(-y[i] * mm)
elementwise.append(torch.log(1 + exp))
return torch.tensor(elementwise, requires_grad=True)
# I assume that's the excepted dimensions of your input
X = torch.randn(5, 30, requires_grad=True)
y = torch.randn(5)
w = torch.randn(30)
# I assume you backpropagate from a reduced version
# of your sum, because you can't call .backward on multi-dimensional
# tensors
loss = logistic_loss(X, y, w).mean()
loss.mean().backward()
print(X.grad)
解决您问题的最简单方法是将 torch.tensor(elementwise, requires_grad=True)
替换为 torch.stack(elementwise)
。您可以将 torch.tensor
视为全新张量的构造函数,如果您的张量更多是某种数学表达式的结果,则应使用 torch.stack
或 torch.cat
.[=21 等操作=]
话虽如此,这段代码仍然非常低效,因为您需要手动循环 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 提供的损失函数更可取。