Why are gradients given by Pytorch 0.4.0 and 0.4.1 are different when backward?

Arenops: <pre><code class="lang-auto">import torch
import torch.nn as nn

x = torch.ones([1], requires_grad=True)
w = torch.tensor([0.2], requires_grad=True)
print('x====: {}'.format(x))
print('w====: {}'.format(w))

def f(x):
    x = x.cuda()
    return torch.pow(x, 2).sum()
    # return x*x*x.sum()

def SGD(grad, lr=0.2):
    return -lr*grad

def optimizer(grad):
    return -w*grad

sum_losses = 0

for i in range(2):

    loss = f(x)
    # print(i, loss)

    sum_losses += loss
    loss.backward(torch.ones_like(loss), retain_graph=True)
    print('x.grad: {}'.format(x.grad))
    print('w1.grad: {}'.format(w.grad))

    update = optimizer(x.grad)
    x = x + update
    print('x-:{}'.format(x))
    print('x-.grad: {}'.format(x.grad))

    x.retain_grad()
    update.retain_grad()

sum_losses.backward()
print('w.grad: {}'.format(w.grad))

w_update = SGD(w.grad, lr=0.1)
w = w + w_update
print('w====: {}'.format(w))
</code></pre>
<p>Pytorch 0.4.1 print as follow:</p>
<pre><code class="lang-auto">x====: tensor([1.], requires_grad=True)
w====: tensor([0.2000], requires_grad=True)
x.grad: tensor([2.])
w1.grad: None
x-:tensor([0.6000], grad_fn=&lt;ThAddBackward&gt;)
x-.grad: None
x.grad: tensor([1.2000])
w1.grad: tensor([-3.8400])
x-:tensor([0.3600], grad_fn=&lt;ThAddBackward&gt;)
x-.grad: None
w.grad: tensor([-7.6800])
w====: tensor([0.9680], grad_fn=&lt;ThAddBackward&gt;)
</code></pre>
<p>Pytorch0.4.0 print as follow:</p>
<pre><code class="lang-auto">x====: tensor([ 1.])
w====: tensor([ 0.2000])
x.grad: tensor([ 2.])
w1.grad: None
x-:tensor([ 0.6000])
x-.grad: None
x.grad: tensor([ 1.2000])
w1.grad: tensor([-2.4000])
x-:tensor([ 0.3600])
x-.grad: None
w.grad: tensor([-6.2400])
w====: tensor([ 0.8240])
</code></pre>
<p>I change function optimizer as follow and the problem is solved, but still confused.</p>
<pre><code class="lang-auto">def optimizer(grad):
    return w*(-grad)
</code></pre>

ptrblck: <p>It looks like your colleague posted the same question <a href="https://discuss.pytorch.org/t/gradients-given-by-pytorch-0-4-0-and-0-4-1-are-different-when-backward/61447/2">here</a>.<br>
I would ask to only keep one topic alive and keep all answers there.</p>

albanD: <p>Hi,</p>
<p>Have you tried running this with a more recent version of pytorch.<br>
Which result is the expected one?</p>

Arenops: <p>Hi, I’ ve tried running the code with Pytorch 1.0.0. The print resuls are the same with Pytorch 0.4.1.</p>

albanD: <p>Running your code with the latest pytorch raises:</p>
<pre><code class="lang-python">x-:tensor([0.6000], grad_fn=&lt;AddBackward0&gt;)
x-.grad: None
Traceback (most recent call last):
  File "foo.py", line 28, in &lt;module&gt;
    loss.backward(torch.ones_like(loss), retain_graph=True)
  File "torch/tensor.py", line 195, in backward
    torch.autograd.backward(self, gradient, retain_graph, create_graph)
  File "torch/autograd/__init__.py", line 99, in backward
    allow_unreachable=True)  # allow_unreachable flag
RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.FloatTensor [1]] is at version 1; expected version 0 instead. Hint: enable anomaly detection to find the operation that failed to compute its gradient, with torch.autograd.set_detect_anomaly(True).
</code></pre>
<p>The problem is that the way the <code>x.grad</code> is updated during the forward in old version was done with the unsafe <code>.data</code>. And so the inplace operation was not properly detected.<br>
This is a good example where the use of <code>.data</code> is dangerous and should be replaced by <code>.detach()</code> or <code>with torch.no_grad()</code>.</p>
<p>You can fix your current code by doing this in old versions:</p>
<pre><code class="lang-python">def optimizer(grad):
    return -w*grad.clone()
</code></pre>

as754770178: <p>(post withdrawn by author, will be automatically deleted in 24 hours unless flagged)</p>

as754770178: <p>I want to know why report the error in the the latest pytorch.<br>
Why this error caused by update <code>x.grad</code>, I think this caused by <code>x = x + update</code>.  Because <code>loss.backward()</code> calculate the grad of <code>x</code>. So I think change <code>x</code> cause the error.</p>
<p>Why I change to <code>return w * (-grad)</code>, the code also can execution.</p>

Arenops: <p>I fix the function optimizer as follows and it works, but i’m still confused why they works</p>
<pre><code class="lang-auto">def optimizer(grad):
    return w*(-grad)
</code></pre>

albanD: <p>HI,</p>
<p>The problem is that the multiplication needs the values of its operands to compute the backpass.<br>
If for any reason this operand is modified inplace, the computed gradient will be wrong.<br>
The old implementation that was using <code>.data</code> for gradient accumulation was not notifying the autograd of the inplace operation and thus the gradient were wrong.<br>
The new implementation that uses <code>torch.no_grad()</code> does notify the autograd and so throws an error.</p>
<p>Both my suggestion with <code>.clone()</code> and your change to do <code>-grad</code> make a copy of <code>grad</code> before passing it to the multiplication. Thus when <code>grad</code> is modified inplace, it does not modify the value needed by the multiplication to compute its backward.<br>
So this will compute the correct gradient.</p>

as754770178: <p>Thanks. I want to make sure my understanding is correct.<br>
1.<br>
In cycle, the first loss calculate by <code>loss = f(x)</code>, but the following loss calculate by</p>
<pre><code class="lang-auto">update = optimizer(x.grad)
x = x + update
loss = f(x)
</code></pre>
<p>Every tensor keeps a version counter. When exec <code>loss.backward</code>, the Function save new version counter of the tensor, and check in backward.<br>
when exec <code>loss.backward</code>, calculate the grad from bottom, so <code>x.grad</code> change. but not yet calculate the grad about <code>-w*grad</code>, so the program report error.</p>
<ol start="2">
<li>
</li>
</ol>
<p>In cycle, autograd records a new graph every time. If I change <code>loss.backward(torch.ones_like(loss), retain_graph=True)</code> to <code>loss.backward(torch.ones_like(loss), retain_graph=False)</code>, the program not report error in cycle. But sum_losses rely on all subgraph that recorded in cycle. So <code>sum_losses.backward() </code> will report error.</p>

albanD: <p>Hi,</p>
<p>I’m not sure to understand what you mean here.<br>
The main point is that <code>loss.backward()</code> used to modified <code>x.grad</code> in an unsafe way. So if an operation used <code>x.grad</code>, then the wrong behavior you observe will happen.</p>

UmEr_ANsari: <p>I am trying to transform a code written in PyTorch 0.2 to PyTorch version 1.7.<br>
Somehow I managed to run the code in PyTorch 1.7 but the results are different from the original code.<br>
I believe the loss computed in these two versions is different.</p>
<p>The link of the code is written in PyTorch 0.2:</p><aside class="onebox githubblob">
  <header class="source">

      <a href="https://github.com/cai-lw/KBGAN/blob/master/base_model.py" target="_blank" rel="noopener nofollow ugc">github.com</a>
  </header>

  <article class="onebox-body">
    <h4><a href="https://github.com/cai-lw/KBGAN/blob/master/base_model.py" target="_blank" rel="noopener nofollow ugc">cai-lw/KBGAN/blob/master/base_model.py</a></h4>


    <pre><code class="lang-py">import torch
import torch.nn as nn
import torch.nn.functional as nnf
from config import config
from torch.autograd import Variable
from torch.optim import Adam
from metrics import mrr_mr_hitk
from data_utils import batch_by_size
import logging


class BaseModule(nn.Module):
    def __init__(self):
        super(BaseModule, self).__init__()

    def score(self, src, rel, dst):
        raise NotImplementedError

    def dist(self, src, rel, dst):
        raise NotImplementedError
</code></pre>


  This file has been truncated. <a href="https://github.com/cai-lw/KBGAN/blob/master/base_model.py" target="_blank" rel="noopener nofollow ugc">show original</a>

  </article>

  <div class="onebox-metadata">
    
    
  </div>

  <div style="clear: both"></div>
</aside>

<p>Can you suggest changes in gen_step() and dis_step() in the base_model.py file in order to transform it to 1.7?<br>
Thanks</p>