Inplace operation errors when implementing A2C algorithm

DungNguyen: <p>Hi,<br>
I’m implementing A2C algorithm from scratch. However, I encounter the RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.cuda.FloatTensor [512, 1]], which is output 0 of AsStridedBackward0, is at version 3; expected version 2 instead.<br>
I run in parallel 8 networks to accumulate experiences and optimize for the global network via the optimize function for one episode. The first episode ran okay but then the second failed. The error might be from the critic layer and also because actor and critic share the nonoutput layers then the bug is likely to happen.<br>
My pytorch version is 1.10.2+cu13<br>
Thanks,</p>
<p>class ActorCriticNet(nn.Module):<br>
def <strong>init</strong>(self, scope, n_channels, n_actions):<br>
super(ActorCriticNet, self).<strong>init</strong>()<br>
self.scope = scope<br>
<a href="http://self.net" rel="noopener nofollow ugc">self.net</a> = nn.Sequential(<br>
nn.Conv2d(n_channels, 32, 8, 4),<br>
nn.ReLU(),<br>
nn.Conv2d(32, 64, 4, 2),<br>
nn.ReLU(),<br>
nn.Conv2d(64, 32, 3, 1),<br>
nn.ReLU(),<br>
)<br>
self.fc = nn.Linear(7<em>7</em>32, 512)<br>
self.actor = nn.Linear(512, n_actions)<br>
self.critic = nn.Linear(512, 1)<br>
self.optimizer = optim.Adam(self.parameters(), lr=LR)</p>
<pre><code>def forward(self, x):
    x = self.net(x)
    x = x.view(-1, 7*7*32)
    x = F.relu(self.fc(x))
    policy = F.softmax(self.actor(x), dim=-1)
    value = self.critic(x)
    return policy, value

def optimize(self, workers):
    if self.scope == 'global':
        for worker in workers:
            self.optimizer.zero_grad()
            r = 0
            for reward, proba, val in worker.data[::-1]:
                r = reward + GAMMA*r
                policy_loss = -torch.log(proba) * (r - val)
                entropy_loss = -ENTROPY_WEIGHT * (proba * torch.log(proba))
                value_loss = (r - val) ** 2
                loss = policy_loss + entropy_loss + value_loss
                loss.backward(retain_graph=True)
            self.optimizer.step()</code></pre>

ptrblck: <p>I guess the error is raised, since you are retaining the graph in the <code>backward</code> call:</p>
<pre><code class="lang-python">loss.backward(retain_graph=True)
</code></pre>
<p>Usually, this argument is used as a workaround to try to fix another error and is creating these “inplace manipulation” errors next as the parameters were already updated inplace in the previous iteration.<br>
Could you explain why you are using <code>retain_graph=True</code> in your code?</p>

DungNguyen: <p>When I remove the retain_graph I encounter another 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.<br>
So I follow the hint and also the loss backward a lot of times but I’m not really sure the retain_graph is the best option.</p>

ptrblck: <p>I think we should focus on fixing the first issue properly without using <code>retain_graph=True</code> unless this is really your use case.</p>
<pre><code class="lang-python">RuntimeError: Trying to backward through the graph a second time 
</code></pre>
<p>is raised e.g. if you are appending the current computation graph to the previous one (which was already freed during the previous <code>backward</code> call).<br>
This is often the case e.g. if you are using a recurrent structure without detaching the inputs in the new iteration.<br>
Based on your code I assume that all <code>workers</code> are independent or do they share some parameters, data etc.?<br>
I would probably start checking if</p>
<pre><code class="lang-python">        for worker in workers:
            self.optimizer.zero_grad()
            r = 0
            for reward, proba, val in worker.data[::-1]:
                r = reward + GAMMA*r
                policy_loss = -torch.log(proba) * (r - val)
                entropy_loss = -ENTROPY_WEIGHT * (proba * torch.log(proba))
                value_loss = (r - val) ** 2
                loss = policy_loss + entropy_loss + value_loss
                loss.backward(retain_graph=True)
            self.optimizer.step()
</code></pre>
<p>reuses some tensors (and thus also the computation graph).</p>

DungNguyen: <p>I found out the problem. It’s because I do not reset the worker.data after every episode so the network keeps meeting the same data again and again. retain_graph is unnecessary anyway<br>
Thanks for helping me solve the issue!</p>

fahmyadan: <p>Hello <a class="mention" href="/u/dungnguyen">@DungNguyen</a></p>
<p>It appears as if I’m facing the exact same problem as you, implementing multiple A2C agents in a RL gym env.  I have encountered the same errors and I suspect your solution might be helpful for my use case.</p>
<p>Can you explain what <code>worker.data</code> represents conceptually and how you went about resetting it after every episode?</p>
<p>Thanks in advance <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=12" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>

vmoens: <p>Hi <a class="mention" href="/u/fahmyadan">@fahmyadan</a><br>
Can you check here if one of the errors relates to what you’re seeing?<br>
<a href="https://pytorch.org/rl/reference/generated/knowledge_base/PRO-TIPS.html" class="onebox" target="_blank" rel="noopener nofollow ugc">https://pytorch.org/rl/reference/generated/knowledge_base/PRO-TIPS.html</a></p>

fahmyadan: <p>Hi <a class="mention" href="/u/vmoens">@vmoens</a> ,</p>
<p>I figured out that the issue i was facing was as a result of how i was training the a2c model.</p>
<p>The agent, in my case, is set up to train using experience from within the episodes and update the parameters based on the loss in that episode.</p>
<p>The problem was that i wasn’t resetting the buffer at the end of the episodes and the gradients were being updated by the same experience multiple times which led to the error.</p>
<p>By adding som <code>del action</code> and <code>del reward</code> statements from my buffer at the end of the training logic, i was able to train the algorithm.</p>

fahmyadan: <p>Thanks for all the support <a class="mention" href="/u/vmoens">@vmoens</a></p>