In-place operation causing RuntimeError: Trying to backward through the graph a second time

William_Caster: <p>Hi there, I’m new to PyTorch and I’ve been trying to fix a runtime error without success. I have defined a custom layer that has the following forward pass:</p>
<pre><code class="lang-auto">  def forward(self, x):

      w_times_x = torch.mm(x, self.weights.t() + (torch.mul(self.alphas, self.h_ij)).t())

      yout = torch.add(w_times_x, self.bias)

      self.h_ij = .99 * self.h_ij + .01 * torch.ger(x[0], yout[0]).t()

      return yout
</code></pre>
<p>Only <strong>self.weights</strong> and <strong>self.alphas</strong> are parameters of the model. The tensor <strong>self.h_ij</strong> is simply accumulating the product of units’ <strong>i</strong> and <strong>j</strong> activations over forward passes (for that I’m doing batch size of 1 such that the training samples are presented sequentially so that the updated value of <strong>self.h_ij</strong> and the end of the forward pass is used during the forward pass of the next training sample).</p>
<p>The training loop is the following:</p>
<pre><code class="lang-auto">for epoch in range(num_epochs):
    for batch_inputs, batch_outputs in dataloader:

        optimizer.zero_grad()

        predictions = model(batch_inputs)
        loss = loss_function(predictions, batch_outputs)

        loss.backward()
        optimizer.step()
</code></pre>
<p>The problem I’m having is that after the first .backward() call I get a <strong>RuntimeError: Trying to backward through the graph a second time (or directly access saved tensors after they have already been freed)</strong>. At the end of this error message it’s suggested I use <strong>.backward(retain_graph=True)</strong>. If I do that I get a different error message <strong>RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation</strong>.</p>
<p>What am I doing wrong? I now that if I call <strong>self.h_ij.detach_()</strong> at the end of the forward method I got get the first error but this will remove (if I understand correctly) <strong>self.h_ij</strong> from the computational graph, so it won’t be taken in consideration when computing the gradients wrt to <strong>self.alpha</strong>.</p>
<p>Another way I can avoid the error is by simply “rebuilding” the tensor (like in the code bellow) but I think this must be braking the computational graph somehow.</p>
<pre><code class="lang-auto">def rebuild_h_ij(self):

    _aux = self.h_ij.tolist().copy()

    self.h_ij = torch.zeros((self.size_out, self.size_in), requires_grad = False)

    self.h_ij = torch.tensor(_aux, requires_grad = False, dtype = torch.float32)
</code></pre>
<p>Some help with this would be rather appreciated. Thx in advance.</p>

KFrank: <p>Hi William!</p>
<aside class="quote no-group quote-modified" data-username="William_Caster" data-post="1" data-topic="184063" data-full="true">
<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/william_caster/48/61958_2.png" class="avatar"> William_Caster:</div>
<blockquote>
<pre><code class="lang-auto">  def forward(self, x):

      w_times_x = torch.mm(x, self.weights.t() + (torch.mul(self.alphas, self.h_ij)).t())

      yout = torch.add(w_times_x, self.bias)

      self.h_ij = .99 * self.h_ij + .01 * torch.ger(x[0], yout[0]).t()

      return yout
</code></pre>
<p>Only <strong>self.weights</strong> and <strong>self.alphas</strong> are parameters of the model. The tensor <strong>self.h_ij</strong> is simply accumulating the product of units’ <strong>i</strong> and <strong>j</strong></p>
<p>…</p>
<p>The problem I’m having is that after the first .backward() call I get a <strong>RuntimeError: Trying to backward through the graph a second time</strong>.</p>
<p>…</p>
<p>I get a different error message <strong>RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation</strong>.</p>
</blockquote>
</aside>
<p><code>w_times_x</code> depends on your trainable parameters, so <code>yout</code> does as well,<br>
and after you accumulated into <code>h_ij</code>, <code>h_ij</code> does to.</p>
<p>The first time through your training loop, <code>h_ij</code> doesn’t yet depend on your<br>
layer parameters when you compute <code>yout</code>, so backpropagating through<br>
<code>yout</code> doesn’t backpropagate through <code>h_ij</code>.  But the second time through<br>
your training loop, <code>h_ij</code> depends on the parameters through the<br>
computation graph that was created during the first loop iteration which<br>
was freed when you called <code>loss.backward()</code> in the first iteration.</p>
<p>Hence your first error.</p>
<p>If you use <code>retain_graph = True</code>, that graph is saved instead of<br>
freed.  But when you try to use it, autograd detects that your call to<br>
<code>optimizer.step()</code> has modified various parameters – that are used<br>
in the first-iteration computation graph – inplace, which would prevent<br>
autograd from computing the gradient correctly were it to try.</p>
<p>Hence your second error.</p>
<p>You have to figure out what the correct logic of your training should be.<br>
After you’ve gone through your training loop 100 times, say, when you<br>
call <code>loss.backward()</code> in the 101st iteration, do you really want to<br>
backpropagate through the computation of <code>h_ij</code> 100 times, once (again)<br>
for each time it was computed in the 100 previous iterations?</p>
<p>Best.</p>
<p>K. Frank</p>