I have a dataset that contains email texts and their corresponding labels. Each email can have multiple labels, making it a multilabel problem. I used multi-hot encoding for labels, so they look like [1, 0, 1, 0, 0], where 1 indicates that an email belongs to that class. However, my data is imbalanced, and some label combinations barely occur in the dataset, which makes my LSTM biased towards the majority classes. I tried specifying pos_weight for BCEWithLogitsLoss, but that doesn’t seem to help. What are some balancing techniques that I could use?
I’m not sure how to measure their dependency, but for context, I’m classifying emails based on what architectural (software) design decisions they contain. Here is the distribution of labels in my training dataset (not-ak refers to emails that don’t contain any architectural decisions):
Well, I would indeed consider 5 binary classifiers here, as Yes/No classifier for each of for 5 class labels.
For example if a item item1 is labeled “process, property, technology”, and an item item2 is labeled as “process, technology” it can be views as multiclass data as follow:
(item1, process)
(item1, property)
(item1, technology)
(item2, process)
(item3, technology)
If you now train the, say, “property” classifier, you put item1 in the positive class and item2 in the negative class. For training the “process” and “technology” classifiers, of course both item1 and item2 are in the positive class
For inferencing, you pump a new item through all 5 classifiers. If the “property” classifier and the “technology” classifier say but not the others, you label the new item with “property, technology”.
Suppose we have all of your targets(all_targets) in a tensor of size [num_targets, num_classes].
First, sum along the num_targets:
total_by_class = all_targets.sum(0)
Second, use this to generate a weights vector:
weights = total_by_class.mean()/total_by_class
Third, set empty classes back to 0.
cond = torch.isinf(weights)
weights[cond] = 0
Finally, pass that into your loss function:
criterion = nn.CrossEntropyLoss(weight=weights)
What that will do is cause the loss function to scale each class by a multiplier, by the inverse of their representation. I.e. classes with less examples get scaled more.