Multi class classification with ignite

Hello, I am trying to train a custom database that I created and my labels are in the following format: 10988, 10995,10995, etc.

So, I’m getting the next error

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..

So, if I check the documentations

if y.max() + 1 > 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)
                )

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

Is there a way I can fix this without changing my database’s labels?

Thanks in advance

Hi @Tanya_Boone

Yes, you have to map the labels to a contiguous format like 0,1,2,3,4,5,6,7,8,9,10,11

The error appears when you compute metrics, so you can perform the mapping with output_transform for the metric:

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)

Hope this helps

1 Like

Thank you. Just one more question :grinning:. If I have this type of training

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(),
    }    

Where should I call the function precision? and also I think the function ot_map_labels should return y_pred and new_y?

What I did is…

  1. Define mapping
  2. define function ot_map_labels
  3. inside update_fn before loss I call precision function, but I didn’t work

Thanks for your help!

OK, I see.

Personally, I’d perform the mapping inside Dataset before the training/validation code:

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

HTH

1 Like

Thanks! I am trying to do it the same way but I get this error


  File "D:/CapsuleNet/CIFAR10/vgg_m_marine.py", line 134, in map_targets_fn
    new_y  = target_mapping[y]

KeyError: tensor(10988)

Seems like y is a tensor coming from your dataset. Maybe, the following would work:

new_y  = target_mapping[y.item()]
1 Like

Apparently it worked. Thank you so much for your support!

1 Like