Model Backward(): RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn

tsuijenk: <p>Hello,</p>
<p>I’ve been struggling for a while with the runtime error. I have visited most, if not all, of the posts on this forum that has this error, and tried to replicate the solution, but I still cannot fix it. Any suggestions would be appreciated! <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=10" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>
<p>Essentially, I have a custom PyTorch dataset class, where I set requires_grad=False for both input x and groundtruth y. I read that this is a must in order to iterate through the dataloader, and this seems to work.</p>
<p>But I also read on this forum that I have to set input x with requires_grad=True before passing into the network, since I had previously set it to False.</p>
<p>But as for groundtruth, despite we use it in the loss function, do we still need to set requires_grad=True for that? I’ve tried that and still get the same runtime error.</p>
<p>Essentially, my code runs past the validation sanity check. It was able to generate the losses twice at Epoch 0, before running into an error.</p>
<p>For all the losses generated at Epoch 0, I see that there’s grad_fn being recorded. So I really don’t understand where there is an error.</p>
<pre><code class="lang-auto">Epoch 0:   0%|                                                                                                     | 0/16 [00:00&lt;00:00, 5011.12it/s]

{'loss1': tensor(1.0887e+15), 'loss2': tensor(11.4520, grad_fn=&lt;DivBackward0&gt;), 'loss3': tensor(2.0911, grad_fn=&lt;LogBackward0&gt;)}
tensor(1.0887e+15, grad_fn=&lt;AddBackward0&gt;)

{'loss1': tensor(1.0894e+15), 'loss2': tensor(11.4538, grad_fn=&lt;DivBackward0&gt;), 'loss3': tensor(2.0907, grad_fn=&lt;LogBackward0&gt;)}
tensor(1.0894e+15, grad_fn=&lt;AddBackward0&gt;)

Traceback (most recent call last):
....
</code></pre>
<p>Below is the training step:</p>
<pre><code class="lang-auto">    def training_step(self, train_batch, batch_idx):
        
        # x = (2,8,img_yaxis,img_xaxis) images, y = groundtruth
        x, y = train_batch

        # Set requires_grad = True
        x = torch.tensor(x, requires_grad=True)
        
        out = self.network(x)

        loss_func = ls.Loss(y[0])
    
        # Out = Tensor([probability_map, gene_map])
        # probability map: 3D (3 batches, 572, 572)
        # barcode gene map: 4D (3 batches, 16, 572, 572)
        probability_map = out[:, 0, :,:]
        gene_map = out[:, 1:17, :,:]
        
        # Now probability_map is 3D (3 batches, 572, 572).
        # So we cast it back to 4D (3 batches, 1, 572, 572).
        probability_map = probability_map[:, None, :, :]
        
        num_batches = probability_map.shape[0]
        
        # FAST COMPUTATION OF LOSS WITHOUT FOR-LOOP using MAP()
        loss = list(map(loss_func, probability_map, gene_map))

        for idx in range(num_batches):
            
            self.log('train_loss', loss[idx])
        
        return torch.mean(torch.FloatTensor(loss))
</code></pre>

ptrblck: <aside class="quote no-group" data-username="tsuijenk" data-post="1" data-topic="139929">
<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/tsuijenk/48/45140_2.png" class="avatar"> tsuijenk:</div>
<blockquote>
<p>But I also read on this forum that I have to set input x with requires_grad=True before passing into the network, since I had previously set it to False.</p>
</blockquote>
</aside>
<p>No, this would only be needed, if you really want to calculate gradients in the input (e.g. for adversarial attacks).</p>
<aside class="quote no-group" data-username="tsuijenk" data-post="1" data-topic="139929">
<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/tsuijenk/48/45140_2.png" class="avatar"> tsuijenk:</div>
<blockquote>
<p>But as for groundtruth, despite we use it in the loss function, do we still need to set requires_grad=True for that? I’ve tried that and still get the same runtime error.</p>
</blockquote>
</aside>
<p>This is also not needed and I don’t know right now a valid use case where the targets need gradients.</p>
<p>Could you explain how this return value is treated?</p>
<pre data-code-wrap="python"><code class="lang-python">return torch.mean(torch.FloatTensor(loss))
</code></pre>
<p>Are you calling <code>backward()</code> on this averaged loss? If so, this won’t work since you are recreating a new tensor and will thus break the computation graph. Try to use <code>torch.stack</code> or <code>torch.cat</code> instead.</p>

tsuijenk: <p>Hi Piotr,</p>
<p>Thank you very much for your quick reply! I had been stuck on this runtime error for two days! Glad to have some pointers.</p>
<blockquote>
<p>No, this would only be needed, if you really want to calculate gradients in the input (e.g. for adversarial attacks).</p>
</blockquote>
<p>But in my custom dataset class, I specifically set inputs’s require_grad=False. If I don’t reset it to True before passing into the network, doesn’t it mean that there will be no grad_fn being tracked?</p>
<blockquote>
<p>Are you calling <code>backward()</code> on this averaged loss? If so, this won’t work since you are recreating a new tensor and will thus break the computation graph. Try to use <code>torch.stack</code> or <code>torch.cat</code> instead.</p>
</blockquote>
<p>Yes, I believe the backward() is called. The idea of using an average loss is because in the case where batch_size &gt;= 2, the network architecture will be analyzing multiple batches at once, hence multiple losses.</p>
<p>I assumed that there is no way that we can call backward() on these losses one by one, hence I took an average loss. What’s your suggestions? If we “return” a vector of three losses (say we have batch_size = 3), how is backward() being called on this vector of losses?</p>
<p><code>return torch.mean(torch.FloatTensor(loss))</code></p>
<p>To be more specific about this line, “loss” is a list of Tensor floats resulting from the map() function. Then we convert it to a Torch Float Tensor vector and then we take average.</p>
<p>Looking forward to your reply! Many thanks! <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=12" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>

ptrblck: <aside class="quote no-group" data-username="tsuijenk" data-post="3" data-topic="139929">
<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/tsuijenk/48/45140_2.png" class="avatar"> tsuijenk:</div>
<blockquote>
<p>But in my custom dataset class, I specifically set inputs’s require_grad=False. If I don’t reset it to True before passing into the network, doesn’t it mean that there will be no grad_fn being tracked?</p>
</blockquote>
</aside>
<p>I assume you are concerned about the <code>grad_fn</code> of the intermediate activations and thus the computation graph: no, this won’t be a problem since you are only changing if the input should get gradients and are not changing anything else in the model. Here is a small example:</p>
<pre data-code-wrap="python"><code class="lang-python"># standard use case
x = torch.randn(1, 1)
print(x.requires_grad)
# &gt; False

lin = nn.Linear(1, 1)
out = lin(x)
print(out.grad_fn)
# &gt; &lt;AddmmBackward0 object at 0x7fcea08c5610&gt;
out.backward()
print(lin.weight.grad)
# &gt; tensor([[-0.9785]])
print(x.grad)
# &gt; None

# input requires grad
x = torch.randn(1, 1, requires_grad=True)
print(x.requires_grad)
# &gt; True

lin = nn.Linear(1, 1)
out = lin(x)
print(out.grad_fn)
# &gt; &lt;AddmmBackward0 object at 0x7fcea08d4640&gt;
out.backward()
print(lin.weight.grad)
# &gt; tensor([[1.6739]])
print(x.grad)
# &gt;tensor([[0.0300]])
</code></pre>
<p>Both approaches work with the difference that the second one will calculate gradients for the input, which is usually not needed.</p>
<aside class="quote no-group" data-username="tsuijenk" data-post="3" data-topic="139929">
<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/tsuijenk/48/45140_2.png" class="avatar"> tsuijenk:</div>
<blockquote>
<p>Then we convert it to a Torch Float Tensor vector and then we take average.</p>
</blockquote>
</aside>
<p>Use <code>torch.stack</code>.</p>

tsuijenk: <p>Thank you so much, Piotr! My code is finally running like a blast! Thank you so much!</p>