RuntimeError: multi-target not supported (newbie)

cerkauskas: <p>Hello. I have a problem when training CNN.</p>
<p>I use one-hot encoding for classes (I want to have probabilities for each class). My dataset is 256x256 RGB images and batch size is 4, so inputs size is (4, 3, 256, 256). I have 120 classes, so labels size is (4, 120) and outputs size is (4, 120) too. Shapes indeed are correct.</p>
<p>Here is how I train my network:</p>
<pre><code class="lang-python">criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=1e-4, momentum=0.9)

running_loss = 0.0

for i, data in enumerate(loader, 0):
    # get the inputs
    labels, inputs, filename = data

    # wrap them in Variable
    inputs, labels = Variable(inputs.cuda()), Variable(labels.cuda())

    # zero the parameter gradients
    optimizer.zero_grad()

    # forward + backward + optimize
    outputs = model(inputs)
    print(inputs.size(), labels.size(), outputs.size())

    loss = criterion(outputs, labels)
    loss.backward()
    optimizer.step()

    # print statistics
    running_loss += loss.data[0]
</code></pre>
<p>Shapes are correct, but I get error <code>RuntimeError: multi-target not supported at /pytorch/torch/lib/THCUNN/generic/ClassNLLCriterion.cu:19</code> at line <code>loss = criterion(outputs, labels)</code>.</p>
<p>What am I doing wrong?</p>
<p>Thank you very much in advance!</p>

ptrblck: <p><code>CrossEntropyLoss</code> does not expect a one-hot encoded vector as the target, but class indices:</p>
<blockquote>
<p>The input is expected to contain scores for each class.<br>
input has to be a 2D Tensor of size (minibatch, C).<br>
This criterion expects a class index (0 to C-1) as the target for each value of a 1D tensor of size minibatch</p>
</blockquote>

cerkauskas: <p>Okay, got it.</p>
<p>I tried <code>loss = criterion(torch.max(outputs, 1)[1], torch.max(labels, 1)[1])</code>, to get indices, but it produces <code>KeyError: &lt;class 'torch.cuda.LongTensor'&gt;</code>.<br>
How else I could get indices?</p>

ptrblck: <p>Your outputs should keep the size <code>(minibatch, C)</code>.</p>
<p>Try this code snippet:</p>
<pre><code>criterion = nn.CrossEntropyLoss()

output = Variable(torch.randn(10, 120).float())
target = Variable(torch.FloatTensor(10).uniform_(0, 120).long())

loss = criterion(output, target)</code></pre>

cerkauskas: <p>Great! It works.</p>
<p>I solved it using <code>loss = criterion(outputs, torch.max(labels, 1)[1])</code></p>
<p>Thank you very much!</p>

kickbox: <p>Thanks for sharing. This worked for…</p>

TahaMagdy: <aside class="quote no-group" data-username="ptrblck" data-post="2" data-topic="10216">
<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>class indices</p>
</blockquote>
</aside>
<p>Please, what are class indices?!<br>
Are they objects that can be accessed by indices?!</p>

ptrblck: <p>No, they are just values representing a class.<br>
For example:</p>
<pre><code class="lang-auto">0 - class0, 
1 - class1,
...
</code></pre>

TahaMagdy: <p>It was confusing at first; So it is the index of the correct class.<br>
Everything is so clear now.</p>
<p>Thank You</p>

jhonatandasilva: <p>Sorry for the ignorance, but what is the point to one hot encoding if you’ll transform into a integer in the end? I was making a CNN with the following encoding</p>
<pre><code class="lang-auto">def encode(self):
        """ One of the ways to make the encoding """
        df = pd.read_csv('../input/train.csv')
        unique_classes = pd.unique(df['Id'])
        encoding = dict(enumerate(unique_classes))
        encoding = {value: key for key, value in encoding.items()}
        df = df.replace(encoding)
        return df
</code></pre>
<p>With this I had no problems. In the end is the same encoding just a list of enumerated numbers from the classes?</p>
<pre><code class="lang-auto">target = Variable(torch.FloatTensor(10).uniform_(0, 120).long())
</code></pre>

ptrblck: <p>Using <code>nn.CrossEntropyLoss</code> or <code>nn.NLLLoss</code> there is no point in creating one-hot encoded targets.<br>
However if the targets are already stored as such, you could use the code snippets from this thread to get the class indices.</p>
<p>I’m not completely sure what your code snippet does exactly, but if you get the class index for each corresponding sample, it should work fine.<br>
However, I’m not sure if <code>pd.unique</code> sorts the data or not. Sorting might destroy the data to target mapping, so you should check it.</p>

jhonatandasilva: <p>Thanks, I’ll be checking it out</p>

heethesh: <p>Making it a 2D tensor still did not work for me. CrossEntropyLoss takes a 1D tensor. I had to squeeze the last dimension with  <code>target.squeeze(1)</code>  so it becomes a 1D tensor of size (batch, ).</p>

Priyanka_Chaudhary: <p>Hi,<br>
I solved using the squeeze function. Hope it helps.</p>
<pre><code class="lang-auto">loss_func = torch.nn.CrossEntropyLoss() 
loss = loss_func(outputs, labels.squeeze())
</code></pre>

sai_tharun: <p>You can also try this</p>
<pre><code class="lang-auto">labels = np.argmax(labels,axis=1)
</code></pre>

Dalmas_Otieno: <p>Thank you so much. This has saved me</p>

Resnet_18: <p>Hi <a class="mention" href="/u/ptrblck">@ptrblck</a>:<br>
Could you please help me out, I have tow classes 0 and 1 and I am using nn.CrossEntropyLoss() as criterion. (generally I am using the Siamese network in case you feel there is something different, but it is not important for this question as I get the output as required (batch size, number of classes) and the target label of size (batch size).<br>
I followed all other threads and this one and tried all proposed solutions but still get this error. Can you have a look, please! I have been stuck with this for ages.<br>
the shape of all what I have is printed in the output cell:<br>
Code:</p>
<pre><code class="lang-auto">`model.train() # prep model for training
        for i, batch in enumerate(train_loader, 0):
            x1, x2, label, _, _ = batch
            x1, x2, label= x1.to(device), x2.to(device), label.to(device)
            # clear the gradients of all optimized variables
            optimizer.zero_grad()
            # forward pass: compute predicted outputs by passing inputs to the model
            output = model.forward(x1, x2)
            # calculate the loss
            print('output', output)
            print('output.data', output.data)
            print('torch.max(label, 1)[1]', torch.max(label, 1)[1])
            print('target label', label)
            print('torch.max(output, 1)[1]', torch.max(output, 1)[1])
            _, predicted= torch.max(output, 1)
            print('predicted', predicted)
            loss = criterion(output.data, label.long())
            # backward pass: compute gradient of the loss with respect to model parameters
            loss.backward()
            # perform a single optimization step (parameter update)
            optimizer.step()
            # record training loss
            train_losses.append(loss.item())
 `
</code></pre>
<h2>Output:<br>
training has started</h2>
<h2>output tensor([[-0.0406, -0.0517],<br>
[-0.0390, -0.0647],<br>
[-0.0264, -0.0449],<br>
[-0.0102, -0.0353],<br>
[-0.0430, -0.0276],<br>
[-0.0200, -0.0663],<br>
[-0.0251, -0.0698],<br>
[-0.0400, -0.0760],<br>
[-0.0667, -0.0711],<br>
[-0.0206, -0.0685],<br>
[-0.0214, -0.0880],<br>
[-0.0150, -0.0579],<br>
[ 0.0153, -0.0565],<br>
[-0.0247, -0.0516],<br>
[-0.0076, -0.0543],<br>
[-0.0179, -0.0716]], device=‘cuda:0’, grad_fn=)<br>
output.data tensor([[-0.0406, -0.0517],<br>
[-0.0390, -0.0647],<br>
[-0.0264, -0.0449],<br>
[-0.0102, -0.0353],<br>
[-0.0430, -0.0276],<br>
[-0.0200, -0.0663],<br>
[-0.0251, -0.0698],<br>
[-0.0400, -0.0760],<br>
[-0.0667, -0.0711],<br>
[-0.0206, -0.0685],<br>
[-0.0214, -0.0880],<br>
[-0.0150, -0.0579],<br>
[ 0.0153, -0.0565],<br>
[-0.0247, -0.0516],<br>
[-0.0076, -0.0543],<br>
[-0.0179, -0.0716]], device=‘cuda:0’)<br>
torch.max(label, 1)[1] tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], device=‘cuda:0’)<br>
target label tensor([[1.],<br>
[0.],<br>
[1.],<br>
[1.],<br>
[0.],<br>
[1.],<br>
[0.],<br>
[1.],<br>
[0.],<br>
[0.],<br>
[0.],<br>
[1.],<br>
[1.],<br>
[1.],<br>
[0.],<br>
[1.]], device=‘cuda:0’)<br>
torch.max(output, 1)[1] tensor([0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], device=‘cuda:0’)<br>
predicted tensor([0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], device=‘cuda:0’)</h2>
<p>RuntimeError                              Traceback (most recent call last)<br>
 in ()<br>
2 # early stopping patience; how long to wait after last time validation loss improved.<br>
3 patience = 20<br>
----&gt; 4 model, train_loss, valid_loss = train_model(model, batch_size, patience, n_epochs)</p>
<p>4 frames<br>
/usr/local/lib/python3.6/dist-packages/torch/nn/functional.py in nll_loss(input, target, weight, size_average, ignore_index, reduce, reduction)<br>
1869                          .format(input.size(0), target.size(0)))<br>
1870     if dim == 2:<br>
-&gt; 1871         ret = torch._C._nn.nll_loss(input, target, weight, _Reduction.get_enum(reduction), ignore_index)<br>
1872     elif dim == 4:<br>
1873         ret = torch._C._nn.nll_loss2d(input, target, weight, _Reduction.get_enum(reduction), ignore_index)</p>
<p>RuntimeError: multi-target not supported at /pytorch/aten/src/THCUNN/generic/ClassNLLCriterion.cu:15</p>
<p>I tried without “.data” as well it did not work.</p>
<p>I look forward to your favourable reply!</p>

ptrblck: <p>It looks like your <code>label</code> tensor has the shape <code>[16, 1]</code> instead of <code>[16]</code>.<br>
Could you squeeze the unnecessary dimension using <code>label = label.squeeze(1)</code> and pass it to the criterion.<br>
Also, pass <code>output</code> directly to the criterion, not <code>output.data</code>, and call the model directly via <code>model(x1, x2)</code> instead of <code>model.forward</code>.</p>

Resnet_18: <aside class="quote no-group" data-username="ptrblck" data-post="20" data-topic="10216">
<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>label.squeeze(1)</p>
</blockquote>
</aside>
<p>Thank you very much, you are absolutely the best!!! <img src="https://discuss.pytorch.org/images/emoji/apple/smiley.png?v=12" title=":smiley:" class="emoji" alt=":smiley:" loading="lazy" width="20" height="20"> <a class="mention" href="/u/ptrblck">@ptrblck</a><br>
The only thing I had to change is to make the label long after squeezing. Otherwise everything worked like magic &lt;3</p>

shyu: <p>Thanks for your great work!</p>