All my gradients are None, even my pred.grad, after backward() call

username: woojinchokimm
cooked: <p>Hi all,</p>
<p>I am relatively new to Pytorch so please bare me with me <img src="https://discuss.pytorch.org/images/emoji/apple/smiley.png?v=12" title=":smiley:" class="emoji" alt=":smiley:" loading="lazy" width="20" height="20"></p>
<p>I have trained a network that takes as input 3 images. The net is based on this:<br>
<div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/4/7/471533b34f51dd27cf9e8aeff5f19ee35127bfba.png" data-download-href="https://discuss.pytorch.org/uploads/default/471533b34f51dd27cf9e8aeff5f19ee35127bfba" title="1_-9XOKVUfl7D5pn29zK-lTw"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/4/7/471533b34f51dd27cf9e8aeff5f19ee35127bfba_2_263x500.png" alt="1_-9XOKVUfl7D5pn29zK-lTw" data-base62-sha1="a8PkaLihlNdO8KO7LZPUdc26T4S" width="263" height="500" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/4/7/471533b34f51dd27cf9e8aeff5f19ee35127bfba_2_263x500.png, https://discuss.pytorch.org/uploads/default/optimized/3X/4/7/471533b34f51dd27cf9e8aeff5f19ee35127bfba_2_394x750.png 1.5x, https://discuss.pytorch.org/uploads/default/original/3X/4/7/471533b34f51dd27cf9e8aeff5f19ee35127bfba.png 2x" data-dominant-color="E6C4B6"><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">1_-9XOKVUfl7D5pn29zK-lTw</span><span class="informations">501×950 46.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>
<p>After training, I wish a heatmap for each input image for interpretability of results.</p>
<p>I make a prediction based on a triplet of images, and call backward(), but all my parameters and even my loss has no gradient:</p>
<pre><code>pred.retain_grad()
pred[target_class].backward()
print(pred.grad) # gives None!
</code></pre>
<p>Here is the total print on the grad for model parameters:</p>
<pre><code class="lang-auto">trained_model.features_a4c.0.weight None
trained_model.features_a4c.0.bias None
trained_model.features_a4c.1.weight None
trained_model.features_a4c.1.bias None
trained_model.features_a4c.5.weight None
trained_model.features_a4c.5.bias None
trained_model.features_a4c.6.weight None
trained_model.features_a4c.6.bias None
trained_model.linear_block.0.weight None
trained_model.linear_block.0.bias None
trained_model.linear_block.3.weight None
trained_model.linear_block.3.bias None
linear_block.0.weight None
linear_block.0.bias None
linear_block.3.weight None
linear_block.3.bias None

model gradients = None
</code></pre>
<p>I have turned on model parameters requires_grad to True before backwards call, set model.eval().</p>
<p>Here is the gradcam model:</p>
<pre><code class="lang-auto">class MultiInputNet_GradCAM(nn.Module):
    # Implement GradCAM hooks
    def __init__(self, trained_model):
        super().__init__() # inherit methods and attributes of nn.Module
        self.trained_model = trained_model
        self.features_a4c = self.trained_model.features_a4c[:8]
        self.features_a2c = self.trained_model.features_a2c[:8]
        self.features_a3c = self.trained_model.features_a3c[:8]

        # we include the last maxpool2d and dropout in the forward function.
        self.last_maxpool2d = nn.MaxPool2d(kernel_size=(2, 2), padding=1)
        self.last_dropout = nn.Dropout(0.3)
        self.gradients = None

        self.linear_block = self.trained_model.linear_block

    def activations_hook(self, grad):
        self.gradients = grad

    def forward(self, x_a4c, x_a2c, x_a3c):
        x1 = self.features_a4c(x_a4c)
        x2 = self.features_a2c(x_a2c)
        x3 = self.features_a3c(x_a3c)

        h1 = x1.register_hook(self.activations_hook)
        h2 = x2.register_hook(self.activations_hook)
        h3 = x3.register_hook(self.activations_hook)

        x1 = self.last_maxpool2d(x1)
        x1 = self.last_dropout(x1)
        x2 = self.last_maxpool2d(x2)
        x2 = self.last_dropout(x2)
        x3 = self.last_maxpool2d(x3)
        x3 = self.last_dropout(x3)

        x_stack = torch.cat((x1, x2, x3), 1) # concatenate
        x_stack = x_stack.view(x_stack.size(0), -1) # flatten batchwise (not fully), we want size of (batch_size, __)
        out = self.linear_block(x_stack)

        return out

    # method for the gradient extraction
    def get_gradient(self):
        return self.gradients

    # method for the activation extraction
    def get_activations(self, x):
        return self.features(x)
</code></pre>
<p>And finally (sorry for blocky codes :S ):</p>
<pre><code class="lang-auto">def my_gradcam(model, imgs, target_class):
    model.cuda()
    model.eval()

    # get the most likely prediction of the model
    pred = model(imgs[0].cuda(), imgs[1].cuda(), imgs[2].cuda()).argmax(dim=1)
    pred=pred.float()
    pred.requires_grad=True
    pred.retain_grad()

    pred[target_class].backward()
    for name, param in model.named_parameters():
        print(name, param.grad) # returns all None

    # pull the gradients out of the model
    gradients = model.get_gradient() # here self.gradients None too

</code></pre>
<p>Thank you in advance for your help. Any insight will be much appreciated!<br>
Best,<br>
David</p>

username: ptrblck
cooked: <p><code>argmax</code> is not differentiable and will detach the resulting tensor from the computation graph, so you would have to remove it.<br>
I’m not familiar with your use case, but if you are working on e.g. a multi-class classification you should pass the raw logits to <code>nn.CrossEntropyLoss</code> instead.</p>

username: woojinchokimm
cooked: <p>You are my absolute hero Mr. Bialecki.<br>
I’ve been at this for the past two days. I should’ve knocked on the door earlier! <img src="https://discuss.pytorch.org/images/emoji/apple/smiley.png?v=10" title=":smiley:" class="emoji" alt=":smiley:"></p>
<p>Thank you so much!<br>
David</p>

username: M_M
cooked: <p>Hi ,<br>
I have the same Issue I thought also that the problem is in argmax that causes the detach from the graph, But how to calculate loss if i remove argmax<br>
for my exemple i have label of shape <code>  [batch_size,256,256]</code>  and the output of the model of shape<br>
<code> [batch_size, number_of_class, 256,256]</code></p>
<pre><code class="lang-auto">def forward (input):
     output = self.encoder(input)
     output =self.decoder(output)
     output = self.sigmoid(output)
     return output

#
optimizer = torch.optim.Adam(model.parameters(), lr=args.lr_start)

# in train 
images = Variable(images, requires_grad= True).cuda(0) 

logits = model(images)

optimizer.zero_grad()

logits   = torch.argmax(logits,dim=1)

criterion = nn.BCEWithLogitsLoss()

loss = criterion(logits.float(), labels.float())

loss1.backward(retain_graph=True)

optimizer1.step()
</code></pre>
<p>but I still have all the grad parameter set as false even if I loaded data<br>
with requires grad to true<br>
and the error is</p>
<pre><code>Variable._execution_engine.run_backward(
</code></pre>
<p>RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn</p>

username: ptrblck
cooked: <p><code>nn.BCEWithLogitsLoss</code> expects raw logits as the model output, so just remove the <code>argmax</code> as well as the <code>sigmoid</code>.<br>
Also, based on the output shape and the usage of <code>nn.BCEWithLogitsLoss</code> it seems you are working on a multi-label segmentation (each pixel can have zero, one, or multiple classes associated to it).<br>
If that’s not the case and you are working on a multi-class segmentation (each pixel belongs to one class only) use <code>nn.CrossEntropyLoss</code> and also pass the raw logits to this loss function.</p>