Right way to make one hot encoding for segmentation?

username: John1231983
cooked: <p>I have a target with size of <code>NxHxW</code>, where N is batch size. I want to make one hot encoding with the output size of <code>NxCxHxW</code> for image segmentation.</p>
<pre><code class="lang-auto">def one_hot(targets):    
    targets_extend=targets.clone()
    targets_extend.unsqueeze_(1) # convert to Nx1xHxW
    one_hot = torch.cuda.FloatTensor(targets_extend.size(0), C, targets_extend.size(2), targets_extend.size(3)).zero_()
    one_hot.scatter_(1, targets_extend, 1) 
    return one_hot
</code></pre>
<p>In the above code, I have used <code>targets_extend=targets.clone()</code>, because the  targets will be used in the cross-entropy loss (only allows the size of <code>NxHxW</code>, instead of <code>Nx1xHxW</code>). More clears, the output of one hot encoding is used for BCE loss, while the <code>targets</code> used in the cross-entropy loss. Is my way (<code>targets_extend=targets.clone()</code>) correct in the making one hot encoding? Can I use <code>targets_extend=targets.detach()</code>? Thanks</p>

username: ptrblck
cooked: <p>I would stick with <code>.clone</code>, since <code>.detach</code> still uses the same underlying data.<br>
Your inplace <code>unsqueeze_</code> will therefore also unsqueeze <code>targets</code>:</p>
<pre><code class="lang-python">x = torch.ones(10)
y = x.detach()
y.unsqueeze_(0)
print(x.shape)
&gt; torch.Size([1, 10])
print(y.shape)
&gt; torch.Size([1, 10])
</code></pre>
<p>May I ask, why you need the <code>BCELoss</code>?<br>
It doesn’t seem like you have a multi-label setup or are you manipulating the <code>one_hot</code> target somehow afterwards?</p>

username: John1231983
cooked: <p>Thanks. I used it for computing the adversarial loss of multiple class ( likes 21 classes in voc). Meanwhile, the cross entropy is for segmentation loss. As I mentioned, the cross entropy expects the targets size of NxHxW, while BCELoss is NxCxHxW. So, your answer is using .clone, Am I right?</p>

username: ptrblck
cooked: <p>Yes, I would use <code>clone</code> and provide two different targets for the different criteria.</p>

username: rushin682
cooked: <p>This solution is good when we have the target segmentations in the range of the index we are mapping to.<br>
i.e if C classes, the intensity of the segmentation mask ranges from 1 to C.</p>
<p>However, how do we one-hot encode a segmentation mask with 5 classes but intensities in the range 0,255 with only 5 unique values in the mask?</p>
<p>Please let me know if the question is not clear.</p>

username: Jaideep_Valani
cooked: <p><a class="mention" href="/u/ptrblck">@ptrblck</a><br>
true_1_hot = torch.eye(num_classes)[targs.squeeze(1)]</p>
<p>how does this work</p>
<p>num_classes=4</p>
<p>shape of targs after squeeze is  BS,H,W<br>
resultant shape is</p>
<p>BS,H,W,4</p>
<p>I fail to understand this</p>

username: ptrblck
cooked: <p><code>torch.eye(num_classes)</code> will create a tensor in the shape <code>[num_classes, num_classes]</code> with 1s in its diagonal. <code>[targs.squeeze(1)]</code> will then index this tensor “row-wise” and return the one-hot encoded tensor.<br>
You would get the same output using <code>F.one_hot(targs, num_classes=num_classes)</code>.</p>
<p>To dig into the indexing using multiple dimensions, check this example code snippet:</p>
<pre><code class="lang-python">a = torch.arange(10)
b = torch.randint(0, 10, (16,))

# index with "flat" dimension
out_b = a[b]

# index with multiple dimensions
c = b.view(2, 2, 2, 2)
out_c = a[c]

# compare
print((out_b == out_c.view(-1)).all())
&gt; tensor(True)
</code></pre>