Implementing Loss Function for FCN

username: Remote_Senser
cooked: <p>Hello,</p>
<p>I am trying to implement a loss function for an FCN. My output is a tensor of shape (n, c, h, w). My target is of shape (h, w). I would like to calculate a loss between the output and the tensor but the problem is that I have a mask. There is only a certain portion of the image that I am interested in calculating the loss for. I am trying to achieve my goal by unwrapping the image channels into arrays and then applying the mask on it. When I do this, I receive an error:</p>
<p>RuntimeError: Assertion `cur_target &gt;= 0 &amp;&amp; cur_target &lt; n_classes’ failed.  at /pytorch/aten/src/THNN/generic/ClassNLLCriterion.c:93</p>
<p>Please see my code (There may be an easier way to do this as I am new to this):</p>
<pre><code class="lang-auto">def Loss(inp, target, mask):
    mask=torch.from_numpy(np.array(mask, dtype=np.uint8))
    target=target.contiguous().view(-1,1) #Flattening the Target Image
    mask = mask.contiguous().view(-1, 1)
    target = target[~mask] #Masking Target
    n, c, h, w = inp.size()
    inp1=np.zeros((target.shape[0],c)) #Creating new empty array with dimensions of (masked_region, c)
    inp1=torch.from_numpy(inp1)
    for i in range(c):
        inp1[:,i]=inp[0,i,:,:].view(-1,1)[~mask] #Masking the input and filling in the array created
    log_p = F.log_softmax(inp1, dim=1)
    criterion=nn.NLLLoss()
    loss = criterion(log_p, target)
    return loss
</code></pre>
<p>Thanks!</p>

username: ptrblck
cooked: <p>Could you post the shapes of <code>log_p</code> and <code>target</code>?<br>
Note that your target should also contain the batch dimension (<code>[n, h, w]</code>) and should contain class indices in the range <code>[0, nb_classes-1]</code> in the usual use case.<br>
It looks like you are selecting all “valid” pixels using the mask and store them as a flattened version. I would assume that you have to select the corresponding targets in the same way so that the shapes match again.</p>
<p>However, you could probably also use the original output and target with a non-reducing criterion (pass <code>reduction='none' to</code>nn.NLLLoss`) and multiply it with your mask to zero out the unwanted pixel locations.</p>
<p>We could most likely avoid the for loop by using broadcasting, so could you also post the shape of your mask?</p>

username: Remote_Senser
cooked: <p>Hey so here’s the sizes of the variables:<br>
inp getting passed in [1, 10, 256, 256] -&gt; batch size 1, 10 classes, 256 x 256 image<br>
target [256, 256]<br>
mask [256, 256]<br>
log_p after the masking operation: [28585, 10]<br>
target after the masking operation: [28585]</p>
<p>My target contains class values between 0 and 9 for each pixel.</p>
<p>I’m confused when you say to pass the original output and target with a non-reducing criterion then zero out the mask. Isn’t the output of the loss function is a scalar value, how would I zero the mask?</p>

username: ptrblck
cooked: <p>The shapes of <code>log_p</code> and <code>target</code> look alright.<br>
Could you check each target batch for its min and max value, as apparently some value is out of bounds before calling the <code>criterion</code>:</p>
<pre data-code-wrap="python"><code class="lang-python">print(target.min(), target.max())
</code></pre>
<aside class="quote no-group" data-username="Remote_Senser" data-post="3" data-topic="49898">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/letter_avatar_proxy/v4/letter/r/ea5d25/48.png" class="avatar"> Remote_Senser:</div>
<blockquote>
<p>I’m confused when you say to pass the original output and target with a non-reducing criterion then zero out the mask. Isn’t the output of the loss function is a scalar value, how would I zero the mask?</p>
</blockquote>
</aside>
<p>You’ll get a scalar values, since the default reduction is set to <code>'mean'</code>.<br>
If you pass <code>'none'</code>, you’ll get an output of the same shape as <code>target</code>:</p>
<pre data-code-wrap="python"><code class="lang-python">output = torch.randn(10, 10 , requires_grad=True)
target = torch.randint(0, 10, (10,))

loss = F.cross_entropy(output, target, reduction='none')
print(loss.shape)
&gt; torch.Size([10])
</code></pre>
<p>Anyway, since your shapes seem to be OK, you could check the range of each target batch and find the batch which causes the trouble.</p>