Copying tensor and gradient computation problem

Ludovic_Denoyer: <p>Hi, when executing the following code, I have the error “Trying to backward through the graph a second time”. But when I remove the copy (and compute backward directly on y.mean() ) then it works. Is someone able to explain why the use of copy_ creates such an error ?</p>
<blockquote>
<p>x=torch.randn(5,3)<br>
m=nn.Linear(3,2)<br>
store=torch.zeros(5,2)</p>
<p>y=m(x)<br>
store.copy_(y)<br>
store.mean().backward()</p>
<p>y=m(x)<br>
store.copy_(y)<br>
store.mean().backward() ==&gt; ERROR</p>
</blockquote>

albanD: <p>Hi,</p>
<p>The thing is that <code>copy_()</code> is modifying store inplace.<br>
So the store used in the first part is actually the same as the one used in the second evaluation. And so running backward on the second one also tries to backward through the first one</p>
<p>You can see that by running in colab:</p>
<pre data-code-wrap="python"><code class="lang-python"># !pip install torchviz

import torch
from torch import nn
from torchviz import make_dot

x=torch.randn(5,3)
m=nn.Linear(3,2)
store=torch.zeros(5,2)

y=m(x)
store.copy_(y)
res = store.mean()
print("First backward...")
res.backward()
make_dot(res)
</code></pre>
<p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/c/3/c34b8a2dbc741b1f480ca615455ed6a2a0429cd5.png" data-download-href="https://discuss.pytorch.org/uploads/default/c34b8a2dbc741b1f480ca615455ed6a2a0429cd5" title="image"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/c/3/c34b8a2dbc741b1f480ca615455ed6a2a0429cd5_2_271x500.png" alt="image" data-base62-sha1="rREWTwnNzzDGq6eSQInEAFERKux" width="271" height="500" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/c/3/c34b8a2dbc741b1f480ca615455ed6a2a0429cd5_2_271x500.png, https://discuss.pytorch.org/uploads/default/optimized/3X/c/3/c34b8a2dbc741b1f480ca615455ed6a2a0429cd5_2_406x750.png 1.5x, https://discuss.pytorch.org/uploads/default/original/3X/c/3/c34b8a2dbc741b1f480ca615455ed6a2a0429cd5.png 2x" data-dominant-color="D1D6D3"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">image</span><span class="informations">440×810 27.1 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div></p>
<pre data-code-wrap="python"><code class="lang-python">y=m(x)
store.copy_(y)
res = store.mean()
print("Before second backward...")
make_dot(res)
</code></pre>
<p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/1/f/1f5dfb1d873b4a4e2505ba2c94198e741ba4b16b.png" data-download-href="https://discuss.pytorch.org/uploads/default/1f5dfb1d873b4a4e2505ba2c94198e741ba4b16b" title="image"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/1/f/1f5dfb1d873b4a4e2505ba2c94198e741ba4b16b_2_351x499.png" alt="image" data-base62-sha1="4tu9AXcgiCX23axkbpkSCPMGuSf" width="351" height="499" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/1/f/1f5dfb1d873b4a4e2505ba2c94198e741ba4b16b_2_351x499.png, https://discuss.pytorch.org/uploads/default/optimized/3X/1/f/1f5dfb1d873b4a4e2505ba2c94198e741ba4b16b_2_526x748.png 1.5x, https://discuss.pytorch.org/uploads/default/original/3X/1/f/1f5dfb1d873b4a4e2505ba2c94198e741ba4b16b.png 2x" data-dominant-color="D8DBD9"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">image</span><span class="informations">686×976 45 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div></p>
<p>You can see that before the second backward, the graph also contains the one from the first backward.</p>

Ludovic_Denoyer: <p>Hi, thanks a lot. But do you understand why it behaves like this ? Since I am replacing the values in the store variable at the second call,  the ‘logical’ stuff would be to have the first branch of the autograd graph removed, am I wrong ?</p>
<p>If no, I have to call a detach_() by myself, right ?</p>

albanD: <p>You can indeed do <code>store = store.detach()</code> to avoid this.</p>
<blockquote>
<p>the ‘logical’ stuff would be to have the first branch of the autograd graph removed, am I wrong ?</p>
</blockquote>
<p>While this is true if you change the whole Tensor, it is not if you replace only a subset of it in the case where store is a view of a bigger Tensor. So it is not that simple I’m afraid.</p>