How to create label in custom dataset for multi-label classification?

I have 3 separate image folders for train, test and validation set.
Both train and validation set have multiple labels of varying number.
The labels are provided in a .csv file where 1st column is filename of images in training set and second column has varying number of labels.

import torch
import pandas as pd
df= pd.read_csv(’/home/nis/Downloads/trialdata/Training-Concepts.csv’,sep=’;’,header=None)
print(df.head())

             0                                             1

0 ROCO_CLEF_07350 C0203126,C0203051
1 ROCO_CLEF_19073 C0772294,C0023884,C0221198,C0412555,C0041618
2 ROCO_CLEF_60501 C0233492,C2985494,C0262950,C1306232
3 ROCO_CLEF_05564 C0521530,C0817096
4 ROCO_CLEF_55020 C0935598,C1184743

I created a custom dataset named myCustomDataset reading pytorch tutorials.
Is this approach right?

class myCustomDataset(Dataset):
“”“my dataset.”""

def __init__(self, csv_file, root_dir, transform=None):
    """
    Args:
        csv_file (string): Path to the csv file with annotations.
        root_dir (string): Directory with all the images.
        transform (callable, optional): Optional transform to be applied
            on a sample.
    """
    self.conceptframe = pd.read_csv(csv_file,sep=';',header=None)
    self.root_dir = root_dir
    self.transform = transform

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

def __getitem__(self, index):
    img_name = os.path.join(self.root_dir,
                            self.conceptframe.iloc[index, 0])
    image = io.imread(img_name)
    label = self.conceptframe.iloc[index, 1]
    sample = {'image': image, 'label': label}

    if self.transform:
        sample = self.transform(sample)

    return sample

Now,I need to use transfer learning Resnet 50.
If, i am not wrong, I need to use nn.BCEloss
and i need to use sigmoid Function.
But I could not know how to use it.I was doubtful about it.
The maximum number of labels is 100 per image.
If i am not wrong, I should replace 2 with 100, in nn.linear() and logSoftmax with sigmoid.

Please let me know how to solve it.

If your target is a multi-hot encoded tensor, then your changes should work.
I’m currently unsure, if label is a tensor or if it contains the class names as given in the data frame.
Anyway, for a multi-label classification, your target should have the same output shape as the model’s output, containing ones for each active class.

Also, as you already explained, nn.BCELoss expects a sigmoid input.

1 Like

I think i have problem on how to create label in case of dataset. I followed the link https://www.kaggle.com/mratsim/starting-kit-for-pytorch-deep-learning .

I have 5529 labels(string concepts) in total. Just to check , i converted them to numpy array.
Each of my image contains variable number of labels as you can see my training concepts.


I used multi binarizer to convert my labels into my multi hot encoded tensor.
One of the link mentioned used the total number of classes within the multilabel binarizer , to convert the labels, whereas, most of the links don’t do so.
When I run the following code,

class myCustomDataset(Dataset):
“”“my dataset.”""

def __init__(self, csv_file, root_dir,img_ext,transform=None):
    """
    Args:
        csv_file (string): Path to the csv file with annotations.
        root_dir (string): Directory with all the images.
        transform (callable, optional): Optional transform to be applied
            on a sample.
    """
    #.iloc[:,0]=[[0]]
     #
    tmp_df = pd.read_csv(csv_file,sep=';',header=None)
    assert tmp_df.iloc[:,0].apply(lambda x: os.path.isfile(root_dir + x + img_ext)).all(), \

“Some images referenced in the CSV file were not found”
#global r

    self.mlb = MultiLabelBinarizer()
    
    self.root_dir = root_dir
    self.img_ext = img_ext
    self.transform = transform

    self.X_train = tmp_df.iloc[:,0]
    self.y_train = self.mlb.fit_transform(tmp_df.iloc[:,1].str.split(',')).astype(np.float32)
    
    #'float'
    
def __len__(self):
    return len(self.X_train.index)

def __getitem__(self, index):
    
    img = Image.open(self.root_dir + self.X_train[index] + self.img_ext)
    img = img.convert('RGB')
    if self.transform is not None:
        img = self.transform(img)
    
    label =torch.from_numpy(self.y_train[index])
    #from_numpy(self.y[index])
    return img, label

After this i print the following code,I made a custom dataset and then dataloader accordingly:


I would like to ask If i should provide my numpy array ‘r’ while writing
self.mlb = MultiLabelBinarizer()
inside the braces or not.
I don’t know if i am going good or not.
My other question is, why is torch size 3233 in the later case.
When i put ‘r’ inside multilabel binarizer, my label size in case of trainloader and validloader changes from 5216 and 3233 to 5528 for both and my torch size changes from 3323 to 5528.
I am unable to understand which one is correct and how should i proceed ahead.
Please provide me your suggestions.