PyTorch學習筆記:nn.CrossEntropyLoss——交叉熵損失
功能:建立一個交叉熵損失函數:
l ( x , y ) = L = { l 1 , … , l N } T , l n = − ∑ c = 1 C w c log e x n , c ∑ i = 1 C e x n , i ⋅ y n , c l(x,y)=L=\{l_1,\dots,l_N\}^T,l_n=-\sum^C_{c=1}w_c\log\frac{e^{x_{n,c}}}{\sum^C_{i=1}e^{x_{n,i}}}· y_{n,c} l(x,y)=L={l1,…,lN}T,ln=−c=1∑Cwclog∑i=1Cexn,iexn,c⋅yn,c
其中 x x x是輸入, y n , c y_{n,c} yn,c是标簽向量元素(來自經過獨熱編碼後的标簽向量), w w w是類别權重, C C C是類别總數, N N N表示batch size。
輸入:
-
與size_average
已被棄用,具體功能由參數reduce
代替reduction
-
:賦予每個類的權重,指定的權重必須是一維并且長度為 C C C的數組,資料類型必須為weight
格式tensor
-
:指定一個被忽略,并且不影響網絡參數更新的目标類别,資料類型必須是整數,即隻能指定一個類别ignore_index
-
:指定損失輸出的形式,有三種選擇:reduction
|none
|mean
。sum
:損失不做任何處理,直接輸出一個數組;none
:将得到的損失求平均值再輸出,會輸出一個數;mean
sum
:将得到的損失求和再輸出,會輸出一個數
注意:如果指定了ignore_index,則首先将ignore_index代表的類别損失删去,在剩下的損失資料裡求均值,是以ignore_index所代表的的類别完全不會影響網絡參數的更新
-
:指定計算損失時的平滑量,其中0.0表示不平滑,關于平滑量可參考論文《Rethinking the Inception Architecture for Computer Vision》label_smoothing
注意:
- 輸入應該包含原始、未經過标準化的預測值,
函數已經内置CrossEntropyLoss
處理softmax
- 對于輸入張量 x x x,尺寸必須為 ( m i n i b a t c h , C ) (minibatch,C) (minibatch,C)或者 ( m i n i b a t c h , C , d 1 , … , d K ) (minibatch,C,d_1,\dots,d_K) (minibatch,C,d1,…,dK),後者對于計算高維輸入時很有用,如計算二維圖像中每個像素點的交叉熵損失,注意: K ≥ 1 K≥1 K≥1
- 輸入的張量 y y y,尺寸必須為 ( m i n i b a t c h ) (minibatch) (minibatch)或者 ( m i n i b a t c h , d 1 , … , d K ) (minibatch,d_1,\dots,d_K) (minibatch,d1,…,dK),與 x x x的尺寸相對應,後者也是用于高維資料的計算
- 注意 x x x的第二次元尺寸與類别數量一一對應,并且 y y y隻需要輸入物體類别序号即可,無需輸入獨熱編碼(該函數會自動對 y y y做獨熱編碼), y y y裡面資料的大小不能超過 x x x第二次元尺寸的大小減一(減一是因為标簽 y y y是從 0 0 0開始計算)
代碼案例
一般用法
import torch.nn as nn
import torch
x = torch.randn((2, 8))
# 在0-7範圍内,随機生成兩個數,當做标簽
y = torch.randint(0, 8, [2])
ce = nn.CrossEntropyLoss()
out = ce(x, y)
print(x)
print(y)
print(out)
輸出
# x
tensor([[ 1.3712, 0.4903, -1.3202, 0.1297, -1.6004, -0.1809, -2.8812, -0.3088],
[ 0.5855, -0.4926, 0.7647, -0.1717, -1.0418, -0.0381, -0.1307, -0.6390]])
# y
tensor([5, 0])
# 得到的交叉熵損失,預設傳回損失的平均值
tensor(1.9324)
參數weight的用法
import torch.nn as nn
import torch
x = torch.randn((2, 2))
y = torch.tensor([0, 1])
# 不添加weight
ce = nn.CrossEntropyLoss(reduction='none')
# 添加weight
ce_w = nn.CrossEntropyLoss(weight=torch.tensor([0.5, 1.5]), reduction='none')
out = ce(x, y)
out_w = ce_w(x, y)
print(x)
print(y)
print(out)
print(out_w)
輸出
# x
tensor([[-1.1011, 0.6231],
[ 0.2384, -0.3223]])
# y
tensor([0, 1])
# 不添加weight時的損失輸出
tensor([1.8883, 1.0123])
# weight定義為[0.5, 1.5]時的損失
# 第一個資料(batch中第一個元素)由于标簽為0
# 是以對應的損失乘以weight中第一個權重
# 第二個資料類似
tensor([0.9441, 1.5184])
參數ignore_index的用法
import torch.nn as nn
import torch
x = torch.randn((2, 2))
y = torch.tensor([0, 1])
# 不添加ignore_index
ce = nn.CrossEntropyLoss(reduction='none')
# 添加ignore_index
ce_i = nn.CrossEntropyLoss(ignore_index = 0, reduction='none')
out = ce(x, y)
out_i = ce_i(x, y)
print(x)
print(y)
print(out)
print(out_i)
輸出
# x
tensor([[-0.9390, -0.6169],
[-0.7700, 0.3602]])
# y
tensor([0, 1])
# 不添加ignore_index時的損失輸出
tensor([0.8671, 0.2799])
# ignore_index設定為0,表示忽略類别序号為0的損失
# 這裡第一個資料标簽設定為0,是以第一個損失清零
tensor([0.0000, 0.2799])
輸入高維資料時
這裡以對二維的預測圖做損失為例
import torch.nn as nn
import torch
# 這裡表示随機生成batch為1,圖檔尺寸為3*3
# 并且每個點有兩個類别的預測圖
x = torch.randn((1, 2, 3, 3))
# 這裡表示預測圖x對應的标簽y
# 預測圖x每個位置都會對應一個标簽值
# x删去第二次元後的尺寸,就是标簽y的尺寸
y = torch.randint(0, 2, [1, 3, 3])
ce = nn.CrossEntropyLoss(reduction='none')
out = ce(x, y)
print(x)
print(y)
print(out)
輸出
# 輸入的高維資料x
tensor([[[[ 0.8859, -2.0889, -0.6026],
[-1.6448, 0.7807, 0.9609],
[-0.0646, 0.2204, -0.7471]],
[[ 0.7075, -0.7013, -0.9280],
[-0.6913, 2.1507, -0.0758],
[ 0.2139, 0.8387, 0.3743]]]])
# 對應的标簽,預測圖x長寬為多少,标簽y的長寬就為多少
tensor([[[0, 0, 1],
[0, 0, 0],
[1, 0, 1]]])
# 輸出的損失
# 函數會為預測圖x上每個位置都生成一個損失,這裡一共生成3*3個損失(對應長乘寬)
tensor([[[0.6079, 1.6105, 0.8690],
[1.2794, 1.5964, 0.3035],
[0.5635, 1.0493, 0.2820]]])
官方文檔
nn.CrossEntropyLoss:https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html#torch.nn.CrossEntropyLoss
初步完稿于:2022年1月29日