背景:例如2分类中,类别极度不均衡,ok样本10万张,ng样本3张,就算模型把所有的样本都预测成ok样本,也能达到99.997%的状态,但是可能实际情况是宁可过杀也不放过。对ng样本添加惩罚项可以缓解这个问题:如果标签为ng,预测成了ng,把这个损失拉满。
- Demo:用mmcls框架,求带权重的交叉熵。
import mmcls.models
import torch
#输入和标签
inputs = torch.FloatTensor([0,1,0,0,0,1])
outputs = torch.LongTensor([0,1])
inputs = inputs.view((1,3,2))
outputs = outputs.view((1,2))
# 定义两种交叉熵,前面为正常交叉熵,后面为带权重的交叉熵
CE = mmcls.models.losses.CrossEntropyLoss()
CE2 = mmcls.models.losses.CrossEntropyLoss(class_weight=[1,10,100])
loss1 = CE(inputs,outputs) #tensor(1.4803)
loss2 = CE2(inputs,outputs) #tensor(9.8593)
Demo2:手动求交叉熵和带权重的交叉熵
# step1:先求softmax,axis=1
inputs2 = inputs.softmax(inputs,1)
print(inputs2)
'''
tensor([[[0.3333, 0.4223],
[0.3333, 0.1554],
[0.3333, 0.4223]]])
'''
# step2:再求log
inputs3 = inputs2.log()
print(inputs3)
'''
tensor([[[-1.0986, -0.8620],
[-1.0986, -1.8620],
[-1.0986, -0.8620]]])
'''
# 上述过程等价于:
inputs3 = inputs.log_softmax(1)
# step3:再根据标签,求损失。
'''
inputs3的shape为(1,3,2),1是批次大小,3是总共包含的类别,2是最终需要计算的交叉熵的向量长度。
除去批次后,inputs3的shape为(3,2)。标签为0,1。表示从第0列需要找第0个元素,
表示从第1列需要找第1个元素.这样组合成交叉熵的向量。最终取到-1.0986和-1.8620
最后取反相加就是最终交叉熵;加上权重就是带权重的交叉熵
'''
1:loss1 = (1.0986+1.862)/2=1.4803
2:loss2 = (1.0986*1+1.862*10)/2=9.8593
可以看出:同样的网络输出,带权重的损失是9.85,不带权重的是1.48。
如果只用交叉熵,损失比较小,如果加上带权重的交叉熵,那么可以把想要关注的类别加入更大权重。
反向推导:如果想要loss2减小,则input3中[-0.8620,-1.8620,-0.8620],需要越逼近[a,-0.0000,b],则inputs2需要越逼近[0,1.,0],inputs1需要越逼近[小,大,小]。
inputs[0][1][1] = 1000000
'''
tensor([[[0., 0],
[0., 1000000],
[0., 1.]]])
'''
CE2(inputs,outputs)#tensor(0.5493)