Multi class classification with ignite

username: Tanya_Boone
cooked: <p>Hello, I am trying to train a custom database that I created and my labels are  in the following format: 10988, 10995,10995, etc.</p>
<p>So, I’m getting the next error</p>
<pre><code class="lang-auto">Engine run is terminating due to exception: y_pred contains less classes than y. Number of predicted classes is 12 and element in y has invalid class = 10999..
</code></pre>
<p>So, if I check the documentations</p>
<pre><code class="lang-auto">if y.max() + 1 &gt; num_classes:
                raise ValueError(
                    "y_pred contains less classes than y. Number of predicted classes is {}"
                    " and element in y has invalid class = {}.".format(num_classes, y.max().item() + 1)
                )
</code></pre>
<p>What I think is that pytorch wants my labels to be in the format 0,1,2,3,4,5,6,7,8,9,10,11</p>
<p>Is there a way I can fix this without changing my database’s labels?</p>
<p>Thanks in advance</p>

username: vfdev-5
cooked: <p>Hi <a class="mention" href="/u/tanya_boone">@Tanya_Boone</a></p>
<p>Yes, you have to map the labels to a contiguous format like <code>0,1,2,3,4,5,6,7,8,9,10,11</code></p>
<p>The error appears when you compute metrics, so you can perform the mapping with <code>output_transform</code> for the metric:</p>
<pre><code class="lang-python">from ignite.metrics import Precision

labels_mapping = {
    10988: 0,
    10995: 1,
    ...
}


def ot_map_labels(output):
    y_pred, y = output
    new_y = labels_mapping[y]
    return y_pred, y

precision = Precision(output_transform=ot_map_labels)
</code></pre>
<p>Hope this helps</p>

username: Tanya_Boone
cooked: <aside class="quote no-group" data-username="vfdev-5" data-post="2" data-topic="108141">
<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/vfdev-5/48/3535_2.png" class="avatar"> vfdev-5:</div>
<blockquote>
<p><code>precision = Precision(output_transform=ot_map_labels)</code></p>
</blockquote>
</aside>
<p>Thank you. Just one more question <img src="https://discuss.pytorch.org/images/emoji/apple/grinning.png?v=12" title=":grinning:" class="emoji" alt=":grinning:" loading="lazy" width="20" height="20">. If I have this type of training</p>
<pre><code class="lang-auto">def update_fn(engine, batch):
    
    model.train()
    
    x = convert_tensor(batch[0], device=device, non_blocking=True)
    y = convert_tensor(batch[1], device=device, non_blocking=True)
    
    y_pred = model(x)
    
    # Compute loss 
    loss = criterion(y_pred, y)    

    optimizer.zero_grad()
    if use_amp:
        with amp.scale_loss(loss, optimizer, loss_id=0) as scaled_loss:
            scaled_loss.backward()
    else:
        loss.backward()
    optimizer.step()
    
    return {
        "batchloss": loss.item(),
    }    
</code></pre>
<p>Where should I call the function precision? and also I think the function ot_map_labels should return y_pred and new_y?</p>
<p>What I did is…</p>
<ol>
<li>Define mapping</li>
<li>define function ot_map_labels</li>
<li>inside update_fn before loss I call precision function, but I didn’t work</li>
</ol>
<p>Thanks for your help!</p>

username: vfdev-5
cooked: <p>OK, I see.</p>
<p>Personally, I’d perform the mapping inside <code>Dataset</code> before the training/validation code:</p>
<pre><code class="lang-python">train_dataset = ...  # your training dataset
val_dataset = ...  # your validation dataset etc

class TransformedDataset(torch.utils.data.Dataset):
    def __init__(self, dataset, transform_fn):
        self.dataset = dataset
        self.transform_fn = transform_fn

    def __len__(self):
        return len(self.dataset)

    def __getitem__(self, index):
        dp = self.dataset[index]
        return self.transform_fn(dp)


from functools import partial

labels_mapping = {
    10988: 0,
    10995: 1,
    ...
}


def map_targets_fn(dp, target_mapping):
    x, y = dp
    new_y  = target_mapping[y]
    return x, new_y


train_dataset = TransformedDataset(train_dataset, partial(map_targets_fn, target_mapping=labels_mapping))
val_dataset = TransformedDataset(val_dataset, partial(map_targets_fn, target_mapping=labels_mapping))

# same code as before without any change to metrics
</code></pre>
<p>HTH</p>

username: Tanya_Boone
cooked: <p>Thanks! I am trying to do it the same way but I get this error</p>
<pre><code class="lang-auto">
  File "D:/CapsuleNet/CIFAR10/vgg_m_marine.py", line 134, in map_targets_fn
    new_y  = target_mapping[y]

KeyError: tensor(10988)

</code></pre>

username: vfdev-5
cooked: <p>Seems like <code>y</code> is a tensor coming from your dataset. Maybe, the following would work:</p>
<pre><code class="lang-python">new_y  = target_mapping[y.item()]
</code></pre>

username: Tanya_Boone
cooked: <p>Apparently it worked. Thank you so much for your support!</p>