Getting zero gradient while applying torch.autograd.grad(loss, x, allow_unused=True)[0] in GNN

ahmadqassemi: <p>Hi Guys,</p>
<p>I’m trying to apply noises to samples, here are the features of nodes in the graph, during test phase in graph neural networks (to perturb samples). The noises should be added to samples in the (opposite) direction of gradient. The following codes are part of the main code that I call the function and the next one is the function I wrote to apply perturb samples. It is almost three weeks that I’ve tried to solve it and couldn’t <img src="https://discuss.pytorch.org/images/emoji/apple/frowning.png?v=12" title=":frowning:" class="emoji" alt=":frowning:" loading="lazy" width="20" height="20"></p>
<p>Could you please have a look to see if you have any idea how to solve it.</p>
<p>with torch.set_grad_enabled(‘test’ in phase):</p>
<pre><code>                x, p_logits = GNN(data.x, data.edge_index, data.edge_weight)

                if mode == 'Supervised':

                    loss = criterion_BCE(p_logits, data.y)

                elif mode == 'Unsupervised':

                    sum_rates_continuous_p = torch.sum(calc_rates(data.h, torch.sigmoid(p_logits).view(-1, k), P_max, noise_var), dim=1)

                    loss = - torch.mean(sum_rates_continuous_p)

                else:

                    raise ValueError('Mode {} not supported! (Supported modes: Supervised/Unsupervised)'.format(mode))

                if 'test' in phase:

                    loss.backward(retain_graph=True)

                data.x = fgsm_attack_new(loss, data.x, epsilon=.1)

                sum_rates = torch.sum(calc_rates(data.h, 1. * (p_logits &gt; 0).view(-1, k), P_max, noise_var), dim=1)

                all_rates.extend(sum_rates.detach().cpu().numpy().tolist())

                all_losses.append(loss.item())

                all_accs.append(torch.mean(1. * ((p_logits &gt; 0) == data.y)))
</code></pre>
<hr>
<p>My function is</p>
<p>def fgsm_attack_new(loss, x, epsilon):</p>
<pre><code>#x.requires_grad = True

x = Variable(x, requires_grad=True)

grad = torch.autograd.grad(loss, x, allow_unused=True)

grad = np.array(grad,dtype=float)

np.nan_to_num(grad, copy=False)

torch.tensor(grad, dtype=torch.float)

print("grad is:{}".format(grad))

perturebed_x = x - epsilon * grad

perturebed_x = torch.clamp(perturebed_x, 0, 1)

return perturebed_x</code></pre>

ptrblck: <p>In these lines of code:</p>
<pre><code class="lang-python">x = Variable(x, requires_grad=True)
grad = torch.autograd.grad(loss, x, allow_unused=True)
</code></pre>
<p>it seems you are setting a newly initialized tensor as the <code>input</code> argument, which was not used to calculate the <code>loss</code>. To avoid the expected error:</p>
<pre><code class="lang-python">RuntimeError: One of the differentiated Tensors appears to not have been used in the graph. Set allow_unused=True if this is the desired behavior.
</code></pre>
<p>you have most likely used <code>allow_unused=True</code>. While this would get rid of the error, it won’t calculate any valid gradient, since <code>x</code> was still not used in the loss calculation.<br>
Here is a small working example:</p>
<pre><code class="lang-python">x = nn.Parameter(torch.randn(1, 1))
loss = x * 2
grad = torch.autograd.grad(loss, x, allow_unused=False)
print(grad)
# (tensor([[2.]]),)
</code></pre>
<p>PS: <code>Variable</code>s are deprecated since PyTorch <code>0.4</code>, so remove them and just use tensors.</p>

ahmadqassemi: <p>Hello ptrblck,</p>
<p>Thanks a lot for your great response! Sorry for my late action as I am sick today and couldn’t check your response sooner.</p>
<p>Your both points regarding “x is not used to calculate loss” and “Variable is deprecated” are great. Thanks a lot again.</p>
<p>Sincerely,<br>
Ahmad</p>