Grad is None when doing loss.backward

username: duskybomb
cooked: <p>I am trying to calculate the gradient (d(loss)/dj). But I get grad is None</p>
<pre><code class="lang-auto">class model(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc = nn.Linear(256, 2)
        
    def forward(self, j, labels):
        e = self.fc(j)
        print(labels.shape)
        print(e.shape)

        j.requires_grad = True
        
        with torch.enable_grad():
            loss = F.cross_entropy(e, labels, reduction='sum')
            j.retain_grad()
            loss.backward()
            grad = j.grad.detach()
            
        return grad
</code></pre>

username: albanD
cooked: <p>Hi,</p>
<p>The problem I think is that you set <code>j.requires_grad</code> after you used it. So the graph is not created when you do the forward.<br>
You should move this at the beginning of the <code>forward()</code> function.</p>

username: fotinidelig
cooked: <p>Hello!</p>
<p>I’m experiencing the same problem but due to something different probably.<br>
This is my code, I’m declaring requires_grad_(True) and then doing loss.backward() but in the end None is printed which is very odd… I’m using the newest version of torch/torchvision 1.9.1 and 0.10.1 respectively. If anyone has a clue for what might be happening let me know!</p>
<pre><code class="lang-auto">    net.eval()

    adv_x = x.clone().detach().float().requires_grad_(True)

    # start from a random point near x
    rand = torch.zeros_like(x).uniform_(-eps, eps).float()
    adv_x = adv_x + rand
    adv_x = torch.clamp(adv_x, x_min, x_max)

    if not targeted:
        target = torch.argmax(net.forward(x))

    criterion = nn.CrossEntropyLoss()
    for _ in range(n_iters):
        pred = net.forward(adv_x)
        loss = criterion(pred, target)
        if targeted:
            loss = -loss
        loss.backward()
        print(adv_x.grad)
</code></pre>

username: ptrblck
cooked: <p>You are replacing the original <code>adv_x</code> leaf tensor:</p>
<pre><code class="lang-python">x = torch.randn(1)
adv_x = x.clone().detach().float().requires_grad_(True)
print(adv_x.requires_grad)
&gt; True
print(adv_x.is_leaf)
&gt; True
</code></pre>
<p>here:</p>
<pre><code class="lang-python">eps = 1e-6
rand = torch.zeros_like(x).uniform_(-eps, eps).float()
adv_x = adv_x + rand
x_min, x_max = -1, 1
adv_x = torch.clamp(adv_x, x_min, x_max)
print(adv_x.requires_grad)
&gt; True
print(adv_x.is_leaf)
&gt; False
</code></pre>
<p>If you are trying to access the <code>.grad</code> attribute of <code>adv_x</code>, you will also get a warning which explains the returned <code>None</code> value:</p>
<pre><code class="lang-python">y = adv_x * 2
y.backward()
print(adv_x.grad)
&gt; None
UserWarning: The .grad attribute of a Tensor that is not a leaf Tensor is being accessed. Its .grad attribute won't be populated during autograd.backward(). If you indeed want the gradient for a non-leaf Tensor, use .retain_grad() on the non-leaf Tensor. If you access the non-leaf Tensor by mistake, make sure you access the leaf Tensor instead. See github.com/pytorch/pytorch/pull/30531 for more information.
</code></pre>

username: fotinidelig
cooked: <p>Thank you, I solved it by doing</p>
<pre><code class="lang-auto">adv_x = adv_x.clone().detach().float().requires_grad_(True)
</code></pre>
<p>in each iteration!</p>

username: ptrblck
cooked: <p>I don’t know where exactly you are creating this cloned tensor, but alternatively you could also use other variable names to make sure that the original <code>adv_x</code> isn’t overwritten.</p>

username: fotinidelig
cooked: <p>Hm yes indeed but adv_x is updated later in the code and in my algorithm the grad is computed from the start of each iteration, with the new value of adv_x. Meaning I would have to clone a variable there either way (obviously my code before wouldn’t have worked properly, the grad would be wrong :))! Thanks!</p>