PyTorch控制问题训练中出现原地操作错误求助
问题:PyTorch训练控制问题神经网络时的原地操作错误
错误信息
RuntimeError: 梯度计算所需的某个变量被原地操作修改了:[torch.cuda.FloatTensor [32, 4]],它是AsStridedBackward0的输出0,当前版本为2;预期版本为1。提示:回溯信息上方会显示计算梯度失败的操作。相关变量是在那里或之后的某处被修改的。祝你好运!
完整代码
导入与配置
# SOME IMPORTS import torch import torch.autograd as autograd from torch import Tensor import torch.nn as nn import torch.optim as optim # Device configuration device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # PARAMETERS OF THE PROBLEM layers = [4, 32, 32, 4] # Layers of the NN steps = 10000 # Simulation steps train_step = 1 # 每train_step步训练一次NN lr = 1e-3 # 学习率
网络定义
# 简单前馈网络定义 class FCN(nn.Module): def __init__(self,layers): super(FCN, self).__init__() # 调用父类的__init__方法 self.linears = [] for i in range(len(layers)-2): self.linears.append( nn.Linear(layers[i], layers[i+1]) ) self.linears.append( nn.ReLU() ) self.linears.append( nn.Linear(layers[-2], layers[-1]) ) self.linear_stack = nn.Sequential(*self.linears) # 前向传播 def forward(self,x): out = self.linear_stack(x) return out
模型初始化
model = FCN(layers) model.to(device) params = list(model.parameters()) optimizer = torch.optim.Adam(model.parameters(),lr=lr,amsgrad=False)
损失与模拟函数
def simulate(state_old, model): state_new = model(state_old) return state_new def lossNN(state_old,state_new, model): error = torch.sum( (state_old-state_new)**2 ) return error
训练代码(原报错版本)
torch.autograd.set_detect_anomaly(True) state_old = torch.Tensor([0.01, 0.01, 0.5, 0.1]).to(device) for i in range(steps): state_new = simulate(state_old, model) if i%train_step == 0: optimizer.zero_grad() loss = lossNN(state_old, state_new, model) loss.backward(retain_graph=True) optimizer.step() state_old = state_new if (i%1000)==0: print(loss) print(state_new)
问题原因与解决方法
核心原因
retain_graph=True强制保留了过时的计算图,后续optimizer.step()更新模型参数后,旧计算图引用的参数版本与当前版本不匹配state_old = state_new直接赋值让state_old持续关联之前的计算图,梯度计算时出现变量版本冲突
修正步骤
- 移除
retain_graph=True:单次训练不需要保留计算图,反向传播后计算图会自动释放 - 用
detach()断开计算图:将state_old = state_new改为state_old = state_new.detach(),让新的输入张量不关联之前的梯度信息
修正后的训练代码
torch.autograd.set_detect_anomaly(True) state_old = torch.Tensor([0.01, 0.01, 0.5, 0.1]).to(device) for i in range(steps): state_new = simulate(state_old, model) if i%train_step == 0: optimizer.zero_grad() loss = lossNN(state_old, state_new, model) loss.backward() # 移除不必要的retain_graph=True optimizer.step() state_old = state_new.detach() # 断开计算图,避免梯度链混乱 if (i%1000)==0: print(loss) print(state_new)
额外说明
detach()返回无梯度的张量副本,适合控制问题的状态传递场景,因为状态迭代不需要追溯历史梯度- 若需保留梯度(如递归训练),可改用
state_new.clone(),但当前场景detach()更高效
内容的提问来源于stack exchange,提问作者Marco
相关产品推荐
相关产品推荐

