Error with loss.backward()

username: Kartik_Kannapur
cooked: <p>Hello community,</p>
<p>I am working on creating a binary classifier by using the Transformer-Encoder architecture.<br>
Most of my code is based on this blog - <a href="http://nlp.seas.harvard.edu/2018/04/03/attention.html" rel="nofollow noopener">http://nlp.seas.harvard.edu/2018/04/03/attention.html</a> and</p>
<pre><code class="lang-auto">class TransformerModel(nn.Module):
    """
    """   
        
        
    def __init__(self, n_token, n_dim_model, n_head, n_hidden, n_blocks, dropout=0.5):
        super(TransformerModel, self).__init__()
        
        # #Multi Headed Attention Layer
        self_attention = MultiHeadedAttention(n_head, n_dim_model)
        # #Feedforward Layer
        feed_forward = FeedForwardLayer(n_dim_model, n_hidden, dropout)
        # #Positional Encoding
        positional_encoding = PositionalEncoding(n_dim_model, dropout)
        
        encoder_layer = EncoderLayer(n_dim_model, copy.deepcopy(self_attention), copy.deepcopy(feed_forward), dropout)
        self.encoder = Encoder(encoder_layer, n_blocks)

        embedding = Embeddings(n_dim_model, n_token)
        self.src_embed = nn.Sequential(embedding, copy.deepcopy(positional_encoding))
        
        # Fully-Connected Layer
        self.fc = nn.Linear(n_dim_model, 2)
    
        # Softmax non-linearity
        self.softmax = nn.Softmax()
        
        

    def forward(self, x):
        
        # # x dimension[k, batch_size = 64]
        embedded_sents = self.src_embed(x.permute(1,0)) # shape = (batch_size=64, k, d_model=256)        
        encoded_sents = self.encoder(embedded_sents)
        
        # Convert input to (batch_size, d_model) for linear layer
        final_feature_map = encoded_sents[:,-1,:] # #Output of this is shape ([64, 256])
        final_out = self.fc(final_feature_map) # #output of tjhis is shape torch.Size([64, 2])
        
        return self.softmax(final_out)  # #output of tjhis is shape torch.Size([64, 2])
</code></pre>
<p>and my model training step is</p>
<pre><code class="lang-auto">def train(model, iterator, optimizer, criterion):
    
    epoch_loss = 0

    model.train()
    
    for batch in iterator:
        
        # #Reset gradients after every batch
        optimizer.zero_grad()
        
        predictions = model(batch.X)
       
        predictions =  torch.max(predictions.data, 1)[1]
        predictions = predictions.float()
       
        loss = criterion(predictions, batch.label)
        loss.backward()  # #Error Here

        optimizer.step()
       
        epoch_loss += loss.item()
        
    return epoch_loss/len(iterator) 
</code></pre>
<p>Error message is</p>
<pre><code class="lang-auto">~/anaconda3/envs/pytorch_p36/lib/python3.6/site-packages/torch/tensor.py in backward(self, gradient, retain_graph, create_graph)
    164                 products. Defaults to ``False``.
    165         """
--&gt; 166         torch.autograd.backward(self, gradient, retain_graph, create_graph)
    167 
    168     def register_hook(self, hook):

~/anaconda3/envs/pytorch_p36/lib/python3.6/site-packages/torch/autograd/__init__.py in backward(tensors, grad_tensors, retain_graph, create_graph, grad_variables)
     97     Variable._execution_engine.run_backward(
     98         tensors, grad_tensors, retain_graph, create_graph,
---&gt; 99         allow_unreachable=True)  # allow_unreachable flag
    100 
    101 

RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
</code></pre>
<p>Any suggestions or help around this would be really appreciated!<br>
Thank you</p>

username: yash1994
cooked: <p>Hi,</p>
<p>From your code, it seems like that you are passing actual prediction value (not logits) to the loss function. It depends on which loss function you are using, <code>nn.CrossEntropyLoss</code> and <code>nn.BCEWithLogitsLoss</code> comes with internal implementation of softmax (so you have to just pass the output of last fully connected layer to loss function). <code>nn.NLLLoss</code> and <code>nn.BCELoss</code> loss function requires softmax to be applied beforehand. But any of these loss functions don’t require the following operations you’ve performed (because these operations are implemented internally).</p>
<pre><code class="lang-auto">predictions =  torch.max(predictions.data, 1)[1]
predictions = predictions.float()
</code></pre>
<p>Just remove softmax operation from your <code>model.forward</code> function. And use any of <code>nn.CrossEntropyLoss</code>  and  <code>nn.BCEWithLogitsLoss</code> loss function and remove those two operations. For more details go to <a href="https://pytorch.org/docs/stable/nn.html#loss-functions" rel="nofollow noopener">Pytorch’s official doc of loss functions</a>.</p>

username: Kartik_Kannapur
cooked: <aside class="quote no-group" data-username="yash1994" data-post="2" data-topic="73328">
<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/yash1994/48/21611_2.png" class="avatar"> yash1994:</div>
<blockquote>
<p><code>nn.NLLLoss</code> and <code>nn.BCELoss</code> loss function requires softmax to be applied beforehand. But any of these loss functions don’t require the following operations you’ve performed (because these operations are implemented internally).</p>
</blockquote>
</aside>
<p>Hi <a class="mention" href="/u/yash1994">@yash1994</a><br>
Thank you so much for your response.<br>
I am using <code>nn.BCEWithLogitsLoss</code> as my loss function. As you had suggested, I removed the softmax operation from my <code>model.forward</code> function and the two lines related to <code>predictions</code> that you had highlightened.</p>
<p>I receive the following error</p>
<p><code>Value Error: Target size (torch.Size[64)) must be the same as the input size (torch.Size([64,2]))</code></p>
<p>My updated model training step is as below and I’m guessing the size of <code>predictions</code> is [64,2] while the size of <code>batch.label</code> is [64]</p>
<pre><code class="lang-auto"># #Reset gradients after every batch
        optimizer.zero_grad()
        
        predictions = model(batch.X)
       
        loss = criterion(predictions, batch.label)
        loss.backward()  # #Error Here

        optimizer.step()
</code></pre>
<p>Any suggestions on resolving this?</p>

username: yash1994
cooked: <p>Hi <a class="mention" href="/u/kartik_kannapur">@Kartik_Kannapur</a>,</p>
<p><code>nn.BCEWithLogitsLoss</code> loss function needs one-hot-encoded vector as target. Currently, your target tensor would be in the following format (assuming binary classification):</p>
<pre><code class="lang-auto">tensor([1, 0, 0, 1]) # integer encoded
</code></pre>
<p>It can be one-hot-encoded in the following manner.</p>
<pre><code class="lang-auto">tensor([[0, 1], [1, 0], [1, 0], [0, 1]]) # one-hot encoded
</code></pre>

username: Kartik_Kannapur
cooked: <p><a class="mention" href="/u/yash1994">@yash1994</a> Brilliant! That helped resolve the issue. Thank you so much for your time!</p>