0

我正在尝试为 A2C 算法创建一个内存缓冲区,可以在https://github.com/raillab/a2c上看到。缓冲区应该可以保存多次迭代的经验,并在之后使用这些进行反向传播。我当前的实现可以在这里看到: https : //gist.github.com/sava17/0229a2eeca9f289c244b50f6653e8937 内存的保存发生在第 209 行:

 memory = sample(observation)
 replay_buffer.append(memory)

 # Fetch random from memory
 l = random.randint(0,len(replay_buffer))
 # Update the gradients
 actor_loss, critic_loss, entropy_loss = update_gradient(replay_buffer[l-1])

当前的实现将记忆(状态、奖励、掩码、next_state、log_probs 和熵)保存在我保存在列表中的对象中。当前实现在第二次通过反向传播时给出以下错误:

RuntimeError: Trying to backward through the graph a second time (or directly access saved tensors after they have already been freed). Saved intermediate values of the graph are freed when you call .backward() or autograd.grad(). Specify retain_graph=True if you need to backward through the graph a second time or if you need to access saved tensors after calling backward.

如果模型只将当前观察作为输入,而不是保存的记忆,则不会发生此错误。我怀疑该错误是由于在尝试再次对它们进行反向传播时从 log_prob 和熵中删除梯度和熵而导致的。当内存被保存并需要从缓冲区中下次使用时,它会尝试在获取的具有空梯度的内存上反向传播。

由于这个理论,我测试了两种选择。

  1. 从内存中删除 log_prob 和熵,并使用从内存中获取观察值的模型计算它们。这个实现可以运行,因为只有 log_prob 和 entropy 具有渐变的火炬。但是,在此更改之后,该模型无法再在其训练示例(Atari Breakout)上获得任何好的结果。
  2. 在将 log_prob 和熵附加到内存对象之前,将它们包装在 Variable 类中。这也可以运行。我怀疑这是由于制作了两个火炬及其渐变的新副本,而不是保存参考。然而,这也导致模型不再收敛。我怀疑这是由于复制了实际上具有渐变和图形的两个元素。我怀疑我们丢失了他们反向传播到的图,这可能是我们想要训练的模型,因为 log_prob 和 entropy 来自调用模型上的 entropy() 和 log_prob()。
4

0 回答 0