Backward through the graph a second time error

denvercoder9: <p>I stumbled upon the following error</p>
<pre><code class="lang-auto">RuntimeError: Trying to backward through the graph a second time, but the saved intermediate results have already been freed. Specify retain_graph=True when calling backward the first time.
</code></pre>
<p>in a rather convoluted RNN snippet. I tried to boil the snippet down as much as possible and hope that the error in the snippet below is triggered by a similar reason:</p>
<pre><code class="lang-auto">import torch
import torch.nn as nn


class Cell(nn.Module):
    def __init__(self):
        super(Cell, self).__init__()
        self.state = torch.tensor([[0., ]])
        self.weight = nn.Parameter(torch.tensor(0.), requires_grad=True)

    def forward(self) -&gt; torch.Tensor:
        x = torch.zeros((1, 1))
        x[0, 0] = self.weight

        res = self.state + x
        # res = self.state + self.weight

        self.state = x

        return res


if __name__ == '__main__':
    cell = Cell()

    def _train_once(cell, optimizer):
        optimizer.zero_grad()

        y = cell()
        loss = torch.sum(y)
        loss.backward()

        optimizer.step()

    optimizer = torch.optim.SGD(cell.parameters(), lr=1e-3)
    _train_once(cell, optimizer)
    _train_once(cell, optimizer)
</code></pre>
<p>Can you explain to me how to fix the error (without setting <code>retain_graph=True</code>)? I also don’t understand why the second backpropagation works when replacing <code>res = self.state + x</code> with <code>res = self.state + self.weight</code> …</p>
<p>Thanks for your help!</p>

albanD: <p>Hi,</p>
<p>The problem is that your <code>self.state</code> is kept across iterations. And so the computational graph for the second call actually includes the one from the first call.<br>
You mist likely want to either reset your state. Or <code>.detach()</code> to avoid doing so.</p>

denvercoder9: <p>Great. Thanks for your help! I indeed want to keep the state since the context of this cell is an RNN. Do you know why this isn’t an issue when replacing <code>res = self.state + x</code> with <code>res = self.state + self.weight</code> (i.e, the comment in the snippet)?</p>

albanD: <aside class="quote no-group" data-username="denvercoder9" data-post="3" data-topic="101394">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/denvercoder9/48/30544_2.png" class="avatar"> denvercoder9:</div>
<blockquote>
<p>Do you know why this isn’t an issue when replacing <code>res = self.state + x</code> with <code>res = self.state + self.weight</code> (i.e, the comment in the snippet)?</p>
</blockquote>
</aside>
<p>No the two should give the same result.</p>

denvercoder9: <p>The problem is that they don’t <img src="https://discuss.pytorch.org/images/emoji/apple/see_no_evil.png?v=9" title=":see_no_evil:" class="emoji" alt=":see_no_evil:"></p>

albanD: <p>Could you share a runable code sample that shows the difference please?</p>

denvercoder9: <p>Thanking you again. Just swap the comment in my first post (inside the <code>forward</code> function). These are the lines I am referring to.</p>

albanD: <p>The difference is just that when you use the inplace op, you create a more complex graph and so backward through it twice is actually an issue.</p>
<p>Both cases are wrong as I mentioned above as in both cases, the second call backprop into the graph created by the first one.<br>
It just happens that in the case where you use weights directly, the graph of the first one is trivial and since no buffers are saved, you can actually backprop again into it.<br>
When you use the inplace op in the second case, the graph is not trivial anymore and it actually raises an error.</p>