Unexpected behaviour on using class weights in loss

Saswat: <p>I’m working on a classification problem (500 classes). My NN has 3 fully connected layers, followed by an LSTM layer. I use <code>nn.CrossEntropyLoss()</code> as my loss function. To tackle the problem of class imbalance, I use sklearn’s class_weight while initializing the loss</p>
<pre><code class="lang-auto">from sklearn.utils import class_weight

class_weights = class_weight.compute_class_weight(class_weight='balanced', classes=np.unique(y_org), y=y_org)
</code></pre>
<p>The below plots show the number of predictions made per class<br>
<div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/d/a/da70b18c09d8632b9747cb06ed92259eaa56fe19.png" data-download-href="https://discuss.pytorch.org/uploads/default/da70b18c09d8632b9747cb06ed92259eaa56fe19" title="image"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/d/a/da70b18c09d8632b9747cb06ed92259eaa56fe19_2_690x460.png" alt="image" data-base62-sha1="vapx4eIeOmb5gES6Z2hp9hI6uXD" width="690" height="460" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/d/a/da70b18c09d8632b9747cb06ed92259eaa56fe19_2_690x460.png, https://discuss.pytorch.org/uploads/default/optimized/3X/d/a/da70b18c09d8632b9747cb06ed92259eaa56fe19_2_1035x690.png 1.5x, https://discuss.pytorch.org/uploads/default/optimized/3X/d/a/da70b18c09d8632b9747cb06ed92259eaa56fe19_2_1380x920.png 2x" data-dominant-color="F7F8F9"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">image</span><span class="informations">1500×1000 134 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div></p>
<p>Here, x-axis represents the class and y-axis is the number of times it occurred (as prediction and as ground truth).</p>
<p>The pattern observed here is that the ground truth and predicted class almost always complement each other. i.e., a class is predicted more times when it’s available less number of times in the ground truth and vice versa (every peak of the blue curve has a dip in orange curve and vice versa). What could be going wrong here?</p>

Saswat: <p>In principle, nothing looks wrong here. When using weighted cross-entropy, the loss is adjusted based on the frequency with a weight between 0 and 1. Now normally this works just fine, but since you have 500 classes I suspect your minority classes are boosted a lot.<br>
You can actually test it pretty easily.</p>
<pre><code class="lang-auto">from sklearn.utils import class_weight
test = []
for i in range(500):
        if i&lt;10:
            test = test + [i] * 50
        else:
            test = test + [i] * 1000
class_weights=class_weight.compute_class_weight(class_weight='balanced',classes=np.unique(test), y=test)
print(class_weights[0], class_weights[-1])
</code></pre>
<p>And you’ll get 19.62 , 0.981. So 10 minority classes have a loss weight of 20, which is enough of a reason for the model to learn to over-predict them. Keep in mind though that in principle there’s nothing wrong with weighting the loss, in the long run, the other classes should be learned as well. If the model really struggles you could try using the focal loss, based on cross-entropy but with a different weighting approach.</p>