【问题标题】:Pytorch, `backward` RuntimeError: Trying to backward through the graph a second time, but the buffers have already been freedPytorch,`backward` RuntimeError:尝试第二次向后遍历图形,但缓冲区已被释放
【发布时间】:2018-07-15 14:18:37
【问题描述】:

我正在使用 PyTorch (0.4) 实现 DDPG,但在反向传播损失时遇到了困难。 所以,首先我的代码执行更新:

def update_nets(self, transitions):
    """
    Performs one update step
    :param transitions: list of sampled transitions
    """
    # get batches
    batch = transition(*zip(*transitions))
    states = torch.stack(batch.state)
    actions = torch.stack(batch.action)
    next_states = torch.stack(batch.next_state)
    rewards = torch.stack(batch.reward)

    # zero gradients
    self._critic.zero_grad()

    # compute critic's loss
    y = rewards.view(-1, 1) + self._gamma * \
        self.critic_target(next_states, self.actor_target(next_states))

    loss_critic = F.mse_loss(y, self._critic(states, actions),
                             size_average=True)

    # backpropagte it
    loss_critic.backward()
    self._optim_critic.step()

    # zero gradients
    self._actor.zero_grad()

    # compute actor's loss
    loss_actor = ((-1.) * self._critic(states, self._actor(states))).mean()

    # backpropagate it
    loss_actor.backward()
    self._optim_actor.step()

    # do soft updates
    self.perform_soft_update(self.actor_target, self._actor)
    self.perform_soft_update(self.critic_target, self._critic)

其中self._actorself._crticself.actor_targetself.critic_target 是篮网。

如果我运行它,我会在第二次迭代中得到以下错误:

RuntimeError: Trying to backward through the graph a second time, but the buffers have already been freed. Specify retain_graph=True when calling backward the first time.

at 

line 221, in update_nets
    loss_critic.backward()
line 93, in backward
    torch.autograd.backward(self, gradient, retain_graph, create_graph)
line 89, in backward
    allow_unreachable=True)  # allow_unreachable flag

我不知道是什么原因造成的。

到目前为止,我所知道的是,loss_critic.backward() 调用会导致错误。 我已经调试了loss_critic - 它得到了一个有效值。 如果我用一个简单的替换损失计算

loss_critic = torch.tensor(1., device=self._device, dtype=torch.float, requires_grad=True)

包含值 1 的张量可以正常工作。 另外,我已经检查过我没有保存一些可能导致错误的结果。 此外,使用loss_actor 更新演员不会导致任何问题。

有人知道这里出了什么问题吗?

谢谢!

更新

我换了

    # zero gradients
    self._critic.zero_grad()

    # zero gradients
    self._actor.zero_grad()

    # zero gradients
    self._critic.zero_grad()
    self._actor.zero_grad()
    self.critic_target.zero_grad()
    self.actor_target.zero_grad()

(两个调用)但它仍然失败并出现相同的错误。 此外,在一次迭代结束时执行更新的代码

def perform_soft_update(self, target, trained):
    """
    Preforms the soft update
    :param target: Net to be updated
    :param trained: Trained net - used for update
    """
    for param_target, param_trained in \
            zip(target.parameters(), trained.parameters()):
        param_target.data.copy_(
            param_target.data * (
                    1.0 - self._tau) + param_trained * self._tau
        )

【问题讨论】:

标签: neural-network pytorch backpropagation reinforcement-learning loss


【解决方案1】:

我找到了解决方案。 我将张量保存在我的 replay_buffer 中,用于训练目的,我在每次迭代中都使用了它,从而产生了代码 sn-p:

    # get batches
    batch = transition(*zip(*transitions))
    states = torch.stack(batch.state)
    actions = torch.stack(batch.action)
    next_states = torch.stack(batch.next_state)
    rewards = torch.stack(batch.reward)

张量的这种“保存”是问题的根源。所以我更改了我的代码,只保存数据 (tensor.data.numpy().tolist()),并且只在需要时将其放入张量中。

更详细: 在 DDPG 中,我每次迭代都会评估策略,并使用批次进行一个学习步骤。 现在我通过以下方式将评估保存在重放缓冲区中:

action = self.action(state)
...
self.replay_buffer.push(state.data.numpy().tolist(), action.data.numpy().tolist(), ...)

并像这样使用它:

batch = transition(*zip(*transitions))
states = self.to_tensor(batch.state)
actions = self.to_tensor(batch.action)
next_states = self.to_tensor(batch.next_state)
rewards = self.to_tensor(batch.reward)

【讨论】:

  • 你知道为什么保存张量不起作用但保存基础数据有效吗?希望知道答案。
  • 保存张量不起作用的原因是在张量的 autograd-function/prop/... 中路由。我不知道具体情况,但我读到您应该始终保存数据而不是张量(经验法则).. .
  • 澄清:当然你应该使用张量来例如计算你的损失(避免不必要的数据转换,尤其是 cpu-gpu 的..)。但是如果你想保存数据,为了以后使用,你应该保存你需要的数据,而不是洞张量。
  • 错误的原因是(我认为),当你调用 backwards() 时,每个张量的 grad 都会被计算出来。如果您有一个已保存的张量,而该张量已经保存了一个 grad,则计算将失败(因此需要调用 .zero_grad())...
【解决方案2】:

没有在self.actor_targetself.critic_target 上呼叫zero_grad()?还是在self.perform_soft_update() 中调用?

【讨论】:

  • 我没有(因为我认为没有必要)所以我添加了它(我会更新问题)但它仍然失败并出现同样的错误
猜你喜欢
  • 2018-06-24
  • 2020-10-06
  • 2020-07-15
  • 2021-11-18
  • 2021-03-11
  • 2020-11-07
  • 2021-11-19
  • 1970-01-01
  • 2023-02-26
相关资源
最近更新 更多