PyTorch训练MADDPG时因原地操作引发梯度计算RuntimeError求解
问题描述
训练多智能体DDPG(MADDPG)演员-评论家网络,设置10000个episode,每个episode包含25个时间步。训练至第10个episode时,梯度计算环节触发以下错误:
RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.cuda.FloatTensor [64, 100]], which is output 0 of AsStridedBackward0, is at version 3; expected version 2 instead. Hint: enable anomaly detection to find the operation that failed to compute its gradient, with torch.autograd.set_detect_anomaly(True).
用于梯度计算与模型更新的代码片段如下:
for agent_idx, agent in enumerate(self.agents): # torch.autograd.set_detect_anomaly(True) critic_value_ = agent.target_critic.forward(states_, new_actions).flatten() critic_value_[dones[:, 0]] = 0.0 critic_value = agent.critic.forward(states, old_actions).flatten() target = rewards[:, agent_idx] + (agent.gamma * critic_value_) critic_loss = F.mse_loss(target, critic_value) agent.critic.optimizer.zero_grad() critic_loss.backward(retain_graph= True) agent.critic.optimizer.step() actor_loss = agent.critic.forward(states, mu).flatten() actor_loss = -torch.mean(actor_loss) agent.actor.optimizer.zero_grad() actor_loss.backward(retain_graph= True) agent.actor.optimizer.step() agent.update_network_parameters()
使用PyTorch版本为1.13.1+cu116,需解决该梯度计算错误。
解决方案
- 修复核心inplace操作:错误的直接原因是
critic_value_[dones[:, 0]] = 0.0这行代码对计算图中的张量进行了inplace修改,破坏了PyTorch自动梯度追踪的版本一致性。可以通过两种方式替换为非inplace操作:# 方式1:用torch.where创建新张量 critic_value_ = agent.target_critic.forward(states_, new_actions).flatten() critic_value_ = torch.where(dones[:, 0].unsqueeze(-1), torch.zeros_like(critic_value_), critic_value_) # 方式2:先克隆原张量再修改 critic_value_ = agent.target_critic.forward(states_, new_actions).flatten().clone() critic_value_[dones[:, 0]] = 0.0 - 检查目标网络更新逻辑:确认
agent.update_network_parameters()方法中没有对目标网络参数的inplace赋值操作。正确的软更新应该通过copy_方法实现,示例如下:# 目标网络软更新的标准实现(参考) def update_network_parameters(self): tau = self.tau # 更新目标评论家网络 for target_param, local_param in zip(self.target_critic.parameters(), self.critic.parameters()): target_param.data.copy_(tau * local_param.data + (1.0 - tau) * target_param.data) # 更新目标演员网络 for target_param, local_param in zip(self.target_actor.parameters(), self.actor.parameters()): target_param.data.copy_(tau * local_param.data + (1.0 - tau) * target_param.data) - 优化
retain_graph的使用:当前代码中两次反向传播都设置了retain_graph=True,但仅第一次反向传播后需要保留计算图供第二次使用,第二次可以省略该参数(默认值为False),避免不必要的计算图占用和版本混乱:critic_loss.backward(retain_graph=True) agent.critic.optimizer.step() # ... 其他代码 ... actor_loss.backward() # 无需再保留计算图 agent.actor.optimizer.step() - 启用异常检测精准定位:取消代码中
torch.autograd.set_detect_anomaly(True)的注释,重新运行训练,系统会输出触发版本不匹配的具体操作栈,帮助排查其他潜在的inplace操作问题。
内容的提问来源于stack exchange,提问作者Enigmacy
相关产品推荐
相关产品推荐

