PyTorch关闭梯度累积时报unsupported operand type错误
问题根因
报错和你预判的叶节点原地更新问题无关,从报错栈可以直接定位问题:执行lr * w.grad时w.grad值为None,本质是你自定义的张量w自始至终没有参与前向传播、损失计算的任何环节,完全不在当前迭代的计算图中。
PyTorch调用backward()时,只会给计算图内标记了requires_grad=True的叶节点计算梯度,不在计算图里的张量不会被分配梯度,w.grad默认就是None,和浮点数lr做乘法自然会触发类型错误。
代码现存其他问题
- 类内定义的
loss方法没有加@staticmethod装饰器,你直接全局调用loss(y_pr, y)时会因为缺少self入参触发运行错误。 - 输入张量形状不匹配:输入
x形状为(2,8),经网络输出的y_pr形状为(2,1),但你定义的标签y形状为(8,),计算MSE时会触发隐式广播,损失计算逻辑完全不符合预期。 - 回归任务输出层误用
softmax:softmax会把输出压缩到0-1区间且所有维度和为1,和你标签2-16的取值范围完全不匹配,会导致训练无法收敛。 - 训练时完全没有更新网络
f的参数,就算解决w的梯度问题,网络参数始终停留在初始随机值,训练没有实际效果。 - 你定义的
w既不参与计算也不关联网络参数,更新w不会对网络输出产生任何影响,属于无效代码。
修正后可运行代码
import torch import torch.nn as nn import torch.nn.functional as F class Network(nn.Module): def __init__(self): super().__init__() self.hidden = nn.Linear(8, 125) self.output = nn.Linear(125, 1) def forward(self, x): x = 2 * F.sigmoid(self.hidden(x)) x = self.output(x) # 回归任务去掉输出层softmax return x # 损失函数定义为独立函数,避免类方法调用参数错误 def loss(y_p, y): return ((y_p - y)**2).mean() # 修正标签形状和网络输出对齐 x = torch.tensor([[1.0, 2.0, 3.0, 4.0,5.0,6.0,7.0,8.0],[1.0, 2.0, 3.0, 4.0,5.0,6.0,7.0,8.0]] , dtype = torch.float32) y = torch.tensor([[2.0], [4.0]], dtype = torch.float32 ) X_test = torch.tensor([[5.0, 5.0, 5.0, 5.0 , 5.0 , 5.0, 5.0, 5.0]], dtype = torch.float32 ) lr = 0.001 n = 1000 f = Network() # 用优化器统一管理网络参数更新,替代手动逐参数更新的逻辑 optimizer = torch.optim.SGD(f.parameters(), lr=lr) # 训练循环 for epoch in range(n): optimizer.zero_grad() # 每轮迭代前清零历史梯度 y_pr = f(x) l = loss(y_pr, y) l.backward() optimizer.step() # 自动完成参数更新,无需手动在no_grad下做减法 if epoch % 100 == 0: print(f"epoch {epoch}, 损失值: {l.item():.4f}") print(f"测试集推理结果: {f(X_test).item():.4f}")
如果你确实需要手动更新自定义参数w,只需要两步:一是让w参与前向计算(比如把w作为缩放、偏置项加入网络前向逻辑),二是把w和网络参数一起加入手动更新的参数列表,保证参数在计算图内即可正常获得梯度。
内容的提问来源于stack exchange,提问作者Anshuman Sinha
相关产品推荐
相关产品推荐

