Backward doesnt provide gradients!

username: Shisho_Sama
cooked: <p>I have been trying to get the gradients for input <a href="https://discuss.pytorch.org/t/how-to-use-autograd-to-get-gradients-with-respect-to-the-input/57093">in this thread</a> for more than a week now.<br>
Looking at the <a href="https://pytorch.org/tutorials/beginner/blitz/autograd_tutorial.html" rel="noopener nofollow ugc">official tutorial here</a>, for getting gradients with respect to the input where the tensor used for backward is not a scaler, it says,</p>
<blockquote>
<p>Now in this case <code>y</code> is no longer a scalar. <code>torch.autograd</code> could not compute the full Jacobian directly, but if we just want the vector-Jacobian product, simply pass the vector to <code>backward</code> as argument:<br>
x = torch.randn(3, requires_grad=True)</p>
</blockquote>
<blockquote>
<pre><code class="lang-auto">y = x * 2
while y.data.norm() &lt; 1000:
    y = y * 2

print(y)
v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v)

print(x.grad)
</code></pre>
</blockquote>
<p>However, when I try to sth like  this the input gradient is always None!<br>
The input will only have a gradient if I backprop using the loss1! which doesnt make any sense to me!</p>
<pre><code class="lang-auto">def fc_batchnorm_act(in_, out_, use_bn=True, act=nn.ReLU()):
    return nn.Sequential(nn.Linear(in_,out_),
                         act,
                         nn.BatchNorm1d(out_) if use_bn else nn.Identity())

class Reshape(nn.Module):
    def __init__(self, shape):
        super().__init__()
        self.shape = shape 

    def forward(self, input):
        return input.view(self.shape)

class Contractive_AutoEncoder(nn.Module):
    def __init__(self):
        super().__init__()
        self.encoder = nn.Sequential(Reshape(shape=(-1, 28*28)),
                                     fc_batchnorm_act(28*28, 400, False))

        self.decoder = nn.Sequential(fc_batchnorm_act(400, 28*28, False, nn.Sigmoid()),
                                     Reshape(shape=(-1, 1, 28, 28)))                             
        
    def forward(self, input):
        outputs_e = self.encoder(input)
        outputs = self.decoder(outputs_e)
        return outputs_e, outputs

def loss_function(output_e, outputs, imgs, device):
 
    criterion = nn.MSELoss()
    assert outputs.shape == imgs.shape ,f'outputs.shape : {outputs.shape} != imgs.shape : {imgs.shape}'
    
    imgs.requires_grad = True 
    loss1 = criterion(outputs, imgs)
    # loss1.backward(retain_graph=True)
    output_e.backward(torch.ones(outputs_e.size()).to(device), retain_graph=True)
    print(imgs.grad)
    loss2 = torch.mean(pow(imgs.grad,2))
    imgs.requires_grad = False 
    imgs.grad.data.zero_()
    loss = loss1 + loss2 
    return loss

</code></pre>
<p>and this is how it is used :</p>
<pre><code class="lang-auto">for e in range(epochs):
    for i, (imgs, labels) in enumerate(dataloader_train):
        imgs = imgs.to(device)
        labels = labels.to(device)

        outputs_e, outputs = model(imgs)
        loss = loss_function(outputs_e, outputs, imgs,device)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

    print(f'epoch/epoechs: {e}/{epochs} loss : {loss.item():.4f} ')
</code></pre>
<p>What am I missing here? I’d grately appreciate this</p>

username: Shisho_Sama
cooked: <p>For some weird reason if I set <code>requires_grad</code> outside of the <code>loss_function</code>, the backward works while setting the <code>requires_grad</code> inside loss function fails completely and not even a single iteration happens! This however wont happen if I do<code>loss1.backward()</code>! at all!</p>

username: albanD
cooked: <p>Hi,</p>
<p>Isn’t the problem that <code>imgs</code> is not a leaf tensor? You can check with <code>imgs.is_leaf</code>.<br>
In particular, <code>.grad</code> field is only populated for leaf Tensors. If you want it for other Tensors, you can use the <a href="https://pytorch.org/docs/stable/tensors.html#torch.Tensor.retain_grad" rel="nofollow noopener"><code>imgs.retain_grad()</code></a> function to get the <code>.grad</code> field populated for non-leaf Tensors.</p>

username: Shisho_Sama
cooked: <p>Thanks a lot I really appreciate your kind help. but why does it work when I backprop from loss1 !?<br>
for example</p>
<pre><code class="lang-auto">def loss_function(output_e, outputs, imgs, device):
 
    criterion = nn.MSELoss()
    assert outputs.shape == imgs.shape ,f'outputs.shape : {outputs.shape} != imgs.shape : {imgs.shape}'
    
    imgs.requires_grad = True 
    loss1 = criterion(outputs, imgs)
    loss1.backward(retain_graph=True)
    #output_e.backward(torch.ones(outputs_e.size()).to(device), retain_graph=True)
    print(imgs.grad)
    loss2 = torch.mean(pow(imgs.grad,2))
    imgs.requires_grad = False 
    imgs.grad.data.zero_()
    loss = loss1 + loss2 
    return loss
</code></pre>
<p>If I use <code>loss1.backward(retain_graph=True)</code> I dont get any errors at all! but when I comment this and instead try  to do <code>output_e.backward(torch.ones(outputs_e.size()).to(device), retain_graph=True)</code> it fails.<br>
The only way it works is that I set the <code>imgs.requires_grad</code> inside the training loop that is :</p>
<p>the training loop :</p>
<pre><code class="lang-auto">for e in range(epochs):
    for i, (imgs, labels) in enumerate(dataloader_train):
        imgs = imgs.to(device)
        labels = labels.to(device)

        imgs.requires_grad_(True)

        outputs_e, outputs = model(imgs)

        loss = loss_function(outputs_e, outputs, imgs, lam,device)
        imgs.requires_grad_(False)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    print(f'epoch/epochs: {e}/{epochs} loss: {loss.item():.4f}')
</code></pre>
<p>and the loss :</p>
<pre><code class="lang-auto">def loss_function(output_e, outputs, imgs, device):
 
    criterion = nn.MSELoss()
    assert outputs.shape == imgs.shape ,f'outputs.shape : {outputs.shape} != imgs.shape : {imgs.shape}'
    
    loss1 = criterion(outputs, imgs)
    #loss1.backward(retain_graph=True)
    output_e.backward(torch.ones(outputs_e.size()).to(device), retain_graph=True)
    loss2 = torch.mean(pow(imgs.grad,2))
    imgs.grad.data.zero_()
    loss = loss1 + loss2 
    return loss
</code></pre>
<p>and now both <code>loss.backward</code> and <code>outputs_e.backward()</code> work without a hitch!</p>

username: albanD
cooked: <p>Hoo,<br>
The thing is that the <code>requires_grad</code> flag is not retroactive. If you forwarded through your <code>model</code> with the <code>requires_grad</code> flag being False, then the you cannot get gradients. Your <code>loss1</code> gives you some gradients because you use <code>imgs</code> again after setting the flag.</p>

username: Shisho_Sama
cooked: <p>Thanks a gazillion times <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=9" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>