pytorch 實現二分類交叉熵逆樣本頻率權重
通常,由於類別不均衡,需要使用weighted cross entropy loss平衡。
def inverse_freq(label): """ 輸入label [N,1,H,W],1是channel數目 """ den = label.sum() # 0 _,_,h,w= label.shape num = h*w alpha = den/num # 0 return torch.tensor([alpha, 1-alpha]).cuda() # train ... loss1 = F.cross_entropy(out1, label.squeeze(1).long(), weight=inverse_freq(label))
補充:Pytorch踩坑記之交叉熵(nn.CrossEntropy,nn.NLLLoss,nn.BCELoss的區別和使用)
在Pytorch中的交叉熵函數的血淚史要從nn.CrossEntropyLoss()這個損失函數開始講起。
從表面意義上看,這個函數好像是普通的交叉熵函數,但是如果你看過一些Pytorch的資料,會告訴你這個函數其實是softmax()和交叉熵的結合體。
然而如果去官方看這個函數的定義你會發現是這樣子的:
哇,竟然是nn.LogSoftmax()和nn.NLLLoss()的結合體,這倆都是什麼玩意兒啊。再看看你會發現甚至還有一個損失叫nn.Softmax()以及一個叫nn.nn.BCELoss()。
我們來探究下這幾個損失到底有何種關系。
nn.Softmax和nn.LogSoftmax
首先nn.Softmax()官網的定義是這樣的:
嗯…就是我們認識的那個softmax。那nn.LogSoftmax()的定義也很直觀瞭:
果不其然就是Softmax取瞭個log。可以寫個代碼測試一下:
import torch import torch.nn as nn a = torch.Tensor([1,2,3]) #定義Softmax softmax = nn.Softmax() sm_a = softmax=nn.Softmax() print(sm) #輸出:tensor([0.0900, 0.2447, 0.6652]) #定義LogSoftmax logsoftmax = nn.LogSoftmax() lsm_a = logsoftmax(a) print(lsm_a) #輸出tensor([-2.4076, -1.4076, -0.4076]),其中ln(0.0900)=-2.4076
nn.NLLLoss
上面說過nn.CrossEntropy()是nn.LogSoftmax()和nn.NLLLoss的結合,nn.NLLLoss官網給的定義是這樣的:
The negative log likelihood loss. It is useful to train a classification problem with C classes
負對數似然損失 ,看起來好像有點晦澀難懂,寫個代碼測試一下:
import torch import torch.nn a = torch.Tensor([[1,2,3]]) nll = nn.NLLLoss() target1 = torch.Tensor([0]).long() target2 = torch.Tensor([1]).long() target3 = torch.Tensor([2]).long() #測試 n1 = nll(a,target1) #輸出:tensor(-1.) n2 = nll(a,target2) #輸出:tensor(-2.) n3 = nll(a,target3) #輸出:tensor(-3.)
看起來nn.NLLLoss做的事情是取出a中對應target位置的值並取負號,比如target1=0,就取a中index=0位置上的值再取負號為-1,那這樣做有什麼意義呢,要結合nn.CrossEntropy往下看。
nn.CrossEntropy
看下官網給的nn.CrossEntropy()的表達式:
看起來應該是softmax之後取瞭個對數,寫個簡單代碼測試一下:
import torch import torch.nn as nn a = torch.Tensor([[1,2,3]]) target = torch.Tensor([2]).long() logsoftmax = nn.LogSoftmax() ce = nn.CrossEntropyLoss() nll = nn.NLLLoss() #測試CrossEntropyLoss cel = ce(a,target) print(cel) #輸出:tensor(0.4076) #測試LogSoftmax+NLLLoss lsm_a = logsoftmax(a) nll_lsm_a = nll(lsm_a,target) #輸出tensor(0.4076)
看來直接用nn.CrossEntropy和nn.LogSoftmax+nn.NLLLoss是一樣的結果。為什麼這樣呢,回想下交叉熵的表達式:
其中y是label,x是prediction的結果,所以其實交叉熵損失就是負的target對應位置的輸出結果x再取-log。這個計算過程剛好就是先LogSoftmax()再NLLLoss()。
所以我認為nn.CrossEntropyLoss其實應該叫做softmaxloss更為合理一些,這樣就不會誤解瞭。
nn.BCELoss
你以為這就完瞭嗎,其實並沒有。還有一類損失叫做BCELoss,寫全瞭的話就是Binary Cross Entropy Loss,就是交叉熵應用於二分類時候的特殊形式,一般都和sigmoid一起用,表達式就是二分類交叉熵:
直覺上和多酚類交叉熵的區別在於,不僅考慮瞭的樣本,也考慮瞭的樣本的損失。
總結
nn.LogSoftmax是在softmax的基礎上取自然對數
nn.NLLLoss是負的似然對數損失,但Pytorch的實現就是把對應target上的數取出來再加個負號,要在CrossEntropy中結合LogSoftmax來用
BCELoss是二分類的交叉熵損失,Pytorch實現中和多分類有區別
Pytorch是個深坑,讓我們一起紮根使用手冊,結合實踐踏平這些坑吧暴風哭泣。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- Pytorch BCELoss和BCEWithLogitsLoss的使用
- Pytorch中Softmax與LogSigmoid的對比分析
- pytorch 實現L2和L1正則化regularization的操作
- pyTorch深度學習softmax實現解析
- Pytorch中Softmax和LogSoftmax的使用詳解