with torch.set_grad_enabled(True):
最近在跑一个项目时,遇到了标题中提到的报错。
报错代码片段如下:
X = X.clone().detach().requires_grad_(True).cuda()
pred = model(X, timesteps=timesteps)
mask = pred.argmax(-1).eq(y) # stop attacking when misclassified
if (mask == False).all():
return X.detach() # stop loop when all samples are misclassified
loss = nn.CrossEntropyLoss(reduction='none')(pred, y)
loss = torch.mean(loss)
grad, = torch.autograd.grad(loss, [X])
即使在计算梯度之前已经设置了 X.requires_grad_(True)
,并且在调试过程中检查到 loss.requires_grad
是 True
,依然报错:
报错内容:
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
报错原因分析:
虽然代码中 X
设置了 requires_grad_(True)
,并且 loss
的 requires_grad
属性在调试时显示为 True
,但 PyTorch 的自动求导机制在某些情况下默认禁用梯度计算。例如,当程序在测试或推理模式下运行时,梯度计算可能被禁用。这通常发生在没有明确设置为训练模式时(如在验证或推理时),或者是在训练代码块外进行的操作。此时即便 requires_grad
为 True
,也不会触发梯度计算,从而导致 torch.autograd.grad()
无法正确计算梯度。
核心原因在于某些场景下,PyTorch 默认禁用了全局的梯度计算,导致 requires_grad
设置无效化。
解决方法:
为了确保在所有情况下都启用梯度计算,可以在报错的代码前添加以下代码:
with torch.set_grad_enabled(True):
X = X.clone().detach().requires_grad_(True).cuda()
pred = model(X, timesteps=timesteps)
mask = pred.argmax(-1).eq(y) # stop attacking when misclassified
if (mask == False).all():
return X.detach() # stop loop when all samples are misclassified
loss = nn.CrossEntropyLoss(reduction='none')(pred, y)
loss = torch.mean(loss)
grad, = torch.autograd.grad(loss, [X])
torch.set_grad_enabled(True)
明确地打开了全局的梯度计算,确保即使在推理模式下(例如,在 model.eval()
或验证阶段)也可以正常计算梯度。
此设置尤其适用于像攻击算法或其他需要手动控制梯度的情况,确保整个代码块中的计算可以正确追踪梯度。
这样不仅解决了报错,还确保了在任何模式下,计算图都能被构建并计算梯度。