Transfer learning for multi-label classification from a single-label model


I’ve had great success with building multi-class, single-label classifiers as described in the official PyTorch transfer learning tutorial. I have a couple of use cases that require a multi-label image classifier, and I was wondering whether/how I could use the same pre-trained model (e.g. ResNet-101) to train a multi-label classifier. I understand that I need to use a different loss function, but I’m not sure how I can get the resulting model to generate multi-label predictions.

The loss function should ensure your model predicts multi-label outputs.
Since you most likely have to change the last layer(s) of the model, the classifier has to learn it’s output distributions from scratch.
What are your doubts about it? Maybe I’m missing a point here.

@ptrblck, I don’t think you’re missing anything, it’s more likely that I am. :smile: My only experience with PyTorch has been fine-tuning a multi-class, single-label classifier on a pre-trained ResNet model as described in the tutorial, i.e. using a single-label dataset, resetting the final layer, and using the CrossEntropyLoss function.

However, I’m not sure about all the changes I need to make to that code to produce a multi-label classification model. Obviously I need to provide a multi-label training set for fine-tuning, and change the loss function to something like MultiLabelMarginLoss, but is there anything else I need to do? I’ve searched for tutorials and code examples specifically for multi-label image classification, but haven’t found any.

You could use BCELoss for multi-label classification.
Just apply a sigmoid on your model’s output and use the BCELoss.
The target should have the same shape as the output in this case.

Hi @ptrblck ,
I have a similar kind of uses case as above to use the pre-trained model of a multi-label classifier.
Single Images has to be classified with two labels.

Used below code to modify the last layer for single-label classifier of 10 classes ,
in_features = resnet.fc.in_features
resnet.fc = nn.Linear(in_features, 10 )

How to modify the last layer for two-label classifier each of 10 classes? I’m a newbie to pytorch

in_features = resnet.fc.in_features
resnet.fc = nn.Linear(in_features, ? )

Does it mean you are working with 10 labels and for each sample two of these labels are active?
If so, your code looks fine:

in_features = resnet.fc.in_features
resnet.fc = nn.Linear(in_features, 10 )

Just make sure the target has the same shape as the model’s output ([batch_size, 10]) and contains the corresponding labels (1. for the active classes, 0 else).

PS: If you are not applying a sigmoid on the output, use nn.BCEWithLogitsLoss.

output tensor label looks as below ,

tensor([[0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],
[0., 0., 0., 0., 0., 0., 1., 0., 0., 0.]]))

The target looks like you are dealing with a multi-class classification, not a multi-label one, i.e. each sample corresponds to a single class.
If that’s the case, your target should only contain the current class index and should be a LongTensor.
In case you already have the one-hot encoded targets, just call:

target = torch.argmax(target, 1)

on them and use nn.CrossEntropyLoss (with logit outputs) as your criterion.

I have confused you by sharing the above target output. I’m dealing with multi-label one. In my case, each sample corresponds to two class.

Input_image (say A) which contains has two objects ( say obj1,obj2).

Example :
Input: image_a
output :[ cat, dog]
i.e., image_a pic has both cat and dog .

In that case the target should contain two active classes (e.g. assuming cat and dog are class0 and class4, respectively):

tensor([[1., 0., 0., 0., 1., 0., 0., 0., 0., 0.]])

If that’s the case, just ignore my last post and refer to the one before it. :wink: