Change float labels to integer labels for binary segmentation

username: Patrice
cooked: <pre><code>         Dear engineers,
</code></pre>
<p>I am sorry if my question might seem silly, but I would like to learn. I am quite new to programming and segmentation tasks. In effect, I am having a dataset with labels that are not in the form of [0,1] as It should be for a binary segmentation task. The readme of the data says that the probability of the label ranges from 0 to 1 and that I should use a threshold value of 0.5 to adjust the data before feeding into the network. Please, I would like to get a better understanding of this concept as well as how I can modify the label before feeding the data into the network. When I input the data and labels to the network without thresholding the labels, the network cannot detect anything.</p>
<p>Any suggestions and/or comments would be highly appreciated</p>
<p>Best regards,</p>

username: ptrblck
cooked: <p>Could you explain a bit how you are feeding the target to the network?<br>
Usually you would feed the data into the model and use its output and target to calculate the loss.<br>
You don’t need to apply a threshold on the target to calculate the loss.<br>
However you might want to apply a threshold on the model outputs to get the class predictions (for a binary use case).</p>

username: Patrice
cooked: <p>I am grateful for your reply sir.</p>
<aside class="quote no-group" data-username="ptrblck" data-post="2" data-topic="79610">
<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/ptrblck/48/1823_2.png" class="avatar"> ptrblck:</div>
<blockquote>
<p>You don’t need to apply a threshold on the target to calculate the loss.</p>
</blockquote>
</aside>
<p>Yes, you are right. I am not applying a threshold on the target to calculate the loss.</p>
<aside class="quote no-group" data-username="ptrblck" data-post="2" data-topic="79610">
<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/ptrblck/48/1823_2.png" class="avatar"> ptrblck:</div>
<blockquote>
<p>Could you explain a bit how you are feeding the target to the network?</p>
</blockquote>
</aside>
<p>I am feeding the target directly without  considering any threshold.</p>
<p>Am I supposed to apply a threshold to the target before feeding into the network?  I have noticed that the loss could decrease normally without anything strange. However, The testing results were very bad ( dice = 0.002).</p>
<p>Please, I would like to know when and how should the threshold be applied</p>
<p>Thank you for your time and patience</p>

username: ptrblck
cooked: <aside class="quote no-group" data-username="Patrice" data-post="3" data-topic="79610">
<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/p/e274bd/48.png" class="avatar"> Patrice:</div>
<blockquote>
<p>Am I supposed to apply a threshold to the target before feeding into the network?</p>
</blockquote>
</aside>
<p>Usually not, but I might misunderstand your use case.<br>
Do you want to apply a threshold to the target or your model outputs?<br>
The latter case would make sense, while I’m not sure about the former one.</p>

username: Patrice
cooked: <aside class="quote no-group" data-username="ptrblck" data-post="4" data-topic="79610">
<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/ptrblck/48/1823_2.png" class="avatar"> ptrblck:</div>
<blockquote>
<p>Do you want to apply a threshold to the target or your model outputs?<br>
The latter case would make sense, while I’m not sure about the former one.</p>
</blockquote>
</aside>
<p>From your explanation, I think that the threshold should be applied to the model outputs instead.</p>
<p>Please, how should it be done?</p>
<p>In the mean time I had tried to apply a threshold to the target before feeding into the network (this could be seen as a data preprocessing step). I did it with the following lines of code</p>
<pre><code class="lang-auto">label  = np.asarray(label)
    label = label.reshape(128, 128, 128)
    label = np.where(label &gt; 0.5, 1, 0)
</code></pre>
<p>Please, I would like to know which one is logical and more appropriate. I would also like to know the reasons</p>
<p>Really appreciate</p>

username: ptrblck
cooked: <p>If your target is a probability between 0 and 1, you could directly use it in <code>nn.BCEWithlogitsLoss</code>.<br>
You don’t need to apply a threshold on the model output to calculate the loss, but could use it to get the predictions and calculate the accuracy.<br>
If your model outputs are logits, you could use a threshold of <code>0.0</code>.</p>

username: Patrice
cooked: <aside class="quote no-group" data-username="ptrblck" data-post="6" data-topic="79610">
<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/ptrblck/48/1823_2.png" class="avatar"> ptrblck:</div>
<blockquote>
<p>If your target is a probability between 0 and 1, you could directly use it in <code>nn.BCEWithlogitsLoss</code> .</p>
</blockquote>
</aside>
<p>Thank you very much for the suggestion. I am using  a customized loss function consisting of the combination of cross_entropy loss and dice loss.</p>
<aside class="quote no-group" data-username="ptrblck" data-post="6" data-topic="79610">
<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/ptrblck/48/1823_2.png" class="avatar"> ptrblck:</div>
<blockquote>
<p>If your model outputs are logits, you could use a threshold of <code>0.0</code> .</p>
</blockquote>
</aside>
<p>In this case, how should the threshold be applied? Please, could you provide a sample code?</p>

username: ptrblck
cooked: <aside class="quote no-group" data-username="Patrice" data-post="7" data-topic="79610">
<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/p/e274bd/48.png" class="avatar"> Patrice:</div>
<blockquote>
<p>I am using a customized loss function consisting of the combination of cross_entropy loss and dice loss.</p>
</blockquote>
</aside>
<p>Could you post the custom loss and explain what your model outputs?<br>
Since you are using <code>nn.CrossEntropyLoss</code>, I assume your model returns an output in the shape <code>[batch_size, 2, height, width]</code>? If that’s the case, you should not apply any threshold, but get the predicted classes via <code>preds = torch.argmax(output, 1)</code>.</p>
<aside class="quote no-group" data-username="Patrice" data-post="7" data-topic="79610">
<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/p/e274bd/48.png" class="avatar"> Patrice:</div>
<blockquote>
<p>In this case, how should the threshold be applied? Please, could you provide a sample code?</p>
</blockquote>
</aside>
<p>If your model returns logits of the shape <code>[batch_size, 1, height, width]</code>, you could get the predictions via: <code>preds = output &gt; 0.0</code>. However, see the comment before, as I’m skeptical what your model returns.</p>

username: Patrice
cooked: <aside class="quote no-group" data-username="ptrblck" data-post="8" data-topic="79610">
<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/ptrblck/48/1823_2.png" class="avatar"> ptrblck:</div>
<blockquote>
<p>Could you post the custom loss and explain what your model outputs?<br>
Since you are using <code>nn.CrossEntropyLoss</code> , I assume your model returns an output in the shape <code>[batch_size, 2, height, width]</code> ? If that’s the case, you should not apply any threshold, but get the predicted classes via <code>preds = torch.argmax(output, 1)</code> .</p>
</blockquote>
</aside>
<p>My loss function is as follows.</p>
<pre><code class="lang-auto">             outputs = net(volume_batch)
            
            loss_seg= F.cross_entropy(outputs,label_batch.long())
            outputs_soft= F.softmax(outputs,dim=1)
            loss_seg_dice = dice_loss(outputs_soft[:,1,:,:,:],label_batch == 1)
            loss= loss_seg + loss_seg_dice
</code></pre>
<aside class="quote no-group" data-username="ptrblck" data-post="8" data-topic="79610">
<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/ptrblck/48/1823_2.png" class="avatar"> ptrblck:</div>
<blockquote>
<p>If your model returns logits of the shape <code>[batch_size, 1, height, width]</code></p>
</blockquote>
</aside>
<p>The shape of my model output is [4,1,128,128,128]. It is a 3D model and I have set 4 as batch size.</p>

username: ptrblck
cooked: <p>The output shape won’t work for a binary classification using <code>F.cross_entropy</code> and you should get an error, if <code>label_batch</code> contains zeros and ones (for both classes).</p>
<p><code>nn.CrossEntropyLoss</code> expects an output in the shape <code>[batch_size, nb_classes=2, depth, height, width]</code> in your use case, and a target in the shape <code>[batch_size, depth, height, width]</code> containing values in the range <code>[0, 1]</code>.</p>
<p>Also, based on your given shape, <code>outputs_soft[:,1,:,:,:]</code> should give you an <code>IndexError</code>.</p>
<p>Could you double check the shapes, please?</p>

username: Patrice
cooked: <aside class="quote no-group" data-username="ptrblck" data-post="10" data-topic="79610">
<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/ptrblck/48/1823_2.png" class="avatar"> ptrblck:</div>
<blockquote>
<p><code>nn.CrossEntropyLoss</code> expects an output in the shape <code>[batch_size, nb_classes=2, depth, height, width]</code> in your use case, and a target in the shape <code>[batch_size, depth, height, width]</code> containing values in the range <code>[0, 1]</code> .</p>
</blockquote>
</aside>
<p>I am sorry for there was a mistake with the output shape. My output shape is [4,2, 128,128,128]. The target shape is [4,1,128,128,128].</p>
<p>The outputs_soft is obtained as follows.</p>
<pre><code class="lang-auto">outputs_soft= F.softmax(outputs,dim=1)
</code></pre>
<p>And computing the dice_loss</p>
<pre><code class="lang-auto"> loss_seg_dice = dice_loss(outputs_soft[:,1,:,:,:],label_batch == 1)
</code></pre>
<p>does not give any error.</p>

username: ptrblck
cooked: <p>Thanks for the update.</p>
<aside class="quote no-group" data-username="Patrice" data-post="11" data-topic="79610">
<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/p/e274bd/48.png" class="avatar"> Patrice:</div>
<blockquote>
<p>My output shape is [4,2, 128,128,128]. The target shape is [4,1,128,128,128].</p>
</blockquote>
</aside>
<p>This should raise an error in <code>F.cross_entropy</code>, as the target contains a channel dimension, which is not expected.</p>

username: Patrice
cooked: <p>Dear sir,<br>
My sincere apologies. I have crosschecked everything and you are right. I have been on this bug for almost two days now.</p>
<p>target size = [4,128,128,128]<br>
outputs size = [4,2,128,128,128]<br>
With this loss function, how should I apply the threshold to the model output?</p>
<pre><code class="lang-auto">            outputs = net(volume_batch)
            
            loss_seg= F.cross_entropy(outputs,label_batch.long())
            outputs_soft= F.softmax(outputs,dim=1)
            loss_seg_dice = dice_loss(outputs_soft[:,1,:,:,:],label_batch == 1)
            loss= loss_seg + loss_seg_dice
</code></pre>
<p>My sincere gratitude for your time, patience and kindness</p>

username: ptrblck
cooked: <p>You don’t need to apply a threshold for these shapes and use case.<br>
The <code>dice_loss</code> should probably get the predicted class labels via:</p>
<pre><code class="lang-python">preds = torch.argmax(outputs, 1)
</code></pre>
<p>Could you remove the <code>softmax</code> and pass <code>preds</code> to <code>dice_loss</code>?</p>

username: Patrice
cooked: <p>Thank you sir! I will do so and see how it goes</p>

username: Patrice
cooked: <p>I have removed the softmax and have modified the loss as you suggested.</p>
<pre><code class="lang-auto">                outputs = net(volume_batch)                                                        
                loss_seg= F.cross_entropy(outputs,label_batch.long())
                outputs_soft= torch.argmax(outputs, 1)
                loss_seg_dice = dice_loss(outputs_soft,label_batch == 1)
                loss= loss_seg+ loss_seg_dice
</code></pre>
<p>However, the computed dice score = 0.000 and It does not change after training for more than 300 epochs. Please, what could be the problem?</p>

username: ptrblck
cooked: <p>Your <code>dice_loss</code> implementation might be wrong or the inputs are not what I would expect.<br>
Could you post the code for the <code>dice_loss</code> implementation, please?</p>

username: Patrice
cooked: <p>Hello sir,<br>
The dice_loss implementation is as follows:</p>
<pre><code class="lang-auto">def dice_loss(score, target):
    target = target.float()
    smooth = 1e-5
    intersect = torch.sum(score * target)
    y_sum = torch.sum(target * target)
    z_sum = torch.sum(score * score)
    loss = (2 * intersect + smooth) / (z_sum + y_sum + smooth)
    loss = 1 - loss
    return loss
</code></pre>
<aside class="quote no-group" data-username="ptrblck" data-post="17" data-topic="79610">
<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/ptrblck/48/1823_2.png" class="avatar"> ptrblck:</div>
<blockquote>
<p>the inputs are not what I would expect.</p>
</blockquote>
</aside>
<p>As I explained earlier, the problem is about the targets. The targets are not in the form of 0 (background) and 1(foreground) as it should be in the case of binary segmentation. Instead, the values of the foreground are float values ranging from 0.1 to 1. After reading online, I found that it could also be seen as a regression problem rather than classification. I am yet to get a clear picture of everything given that I am a beginner. Please, any explanation and suggestions would be highly appreciated.</p>

username: ptrblck
cooked: <aside class="quote no-group" data-username="Patrice" data-post="18" data-topic="79610">
<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/p/e274bd/48.png" class="avatar"> Patrice:</div>
<blockquote>
<p>The targets are not in the form of 0 (background) and 1(foreground) as it should be in the case of binary segmentation. Instead, the values of the foreground are float values ranging from 0.1 to 1.</p>
</blockquote>
</aside>
<p>Thanks for mentioning it again.<br>
The dice loss is used for discrete data, so I doubt it can work for a regression task.</p>
<p>Since your labels are in the range <code>[0, 1]</code>, I would again recommend to use <code>nn.BCEWithLogitsLoss</code>.</p>
<p>Alternatively, since you are already rounding the targets to 0 and 1 to be able to use <code>F.cross_entropy</code>, you could also apply the same for the dice loss calculation.</p>

username: Patrice
cooked: <aside class="quote no-group" data-username="ptrblck" data-post="19" data-topic="79610">
<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/ptrblck/48/1823_2.png" class="avatar"> ptrblck:</div>
<blockquote>
<p>Alternatively, since you are already rounding the targets to 0 and 1 to be able to use <code>F.cross_entropy</code> , you could also apply the same for the dice loss calculation.</p>
</blockquote>
</aside>
<p>Yes sir, that is what I have applied so far and it seems to work</p>
<pre><code class="lang-auto">label  = np.asarray(label)
    label = label.reshape(128, 128, 128)
    label = np.where(label &gt; 0.5, 1, 0)
</code></pre>
<p>Thank you very much for following up.</p>