Pytorch 之損失函數


1. torch.nn.MSELoss

   均方損失函數,一般損失函數都是計算一個 batch 數據總的損失,而不是計算單個樣本的損失。

$$L = (x - y)^{2}$$

   這里 $L, x, y$ 的維度是一樣的,可以是向量或者矩陣(有多個樣本組合),這里的平方是針對 Tensor 的每個元素,即 $(x-y)**2$ 或 $torch.pow(x-y, 2)$。

   函數原型如下:

"""
該函數返回的是一個 python 類對象
reduce = False,損失函數返回的是向量形式的 loss,這種情況下參數 size_average 失效。
reduce = True, 損失函數返回的是標量形式的 loss,這種情況下:
    1)當 size_average = True 時,返回 loss.mean(),即所有向量元素求和后再除以向量長度
    2)當 size_average = False 時,返回 loss.sum(),即所有向量元素只求和
默認情況下:兩個參數都為 True。
"""
CLASS torch.nn.MSELoss(size_average=True, reduce=True)

   舉個例子:

import torch

loss = torch.nn.MSELoss()   # 默認輸出標量並求均值
input = torch.randn(3, 5, requires_grad=True)
target = torch.randn(3, 5)
output = loss(input, target)
output.backward()
print(output)

"""
tensor(2.4015, grad_fn=<MseLossBackward>)
"""

 

2. torch.nn.BCELoss

   它適用於二分類問題,且神經網絡的輸出是一個概率分布,一般輸出層的激活函數是 $Sigmod$ 函數,因為只有兩類,所以輸出沒

   必要歸一化,直接就是一個概率分布。那么這個損失函數可以用來計算目標值和預測值之間的二進制交叉熵損失函數,一般損失函

   數都是計算一個 batch 數據總的損失,而不是計算單個樣本的損失。一個 batch 數據的損失為

$$L_{batch} = -w \cdot \big [\; y \ln \hat{y} + (1 - y)\ln (1 - \hat{y}) \;\big]$$

   這里 $L, y, \hat{y}$ 的維度是一樣的,可以是向量或者矩陣(由多個樣本組合),這里的 $\ln$ 是針對 Tensor 的每個元素。

   既然是計算兩個分布(一個分布是我們用來近似的模型,另一個是真實分布)之間的交叉熵,那么每個樣本對應的分布是什么?

   只考慮一個樣本,那么它其實就是一個 $0-1$ 分布,即每一個 $x$,都會對應一個類別 $y$,$y$ 要么等於 $0$,要么等於 $1$。

       1)如果 $y = 0$,那么這個樣本 $x$ 對應的 $0-1$ 分布(真實分布)為

             

       2)如果 $y = 1$,那么這個樣本 $x$ 對應的 $0-1$ 分布(真實分布)為

             

 

   如果上面的內容不理解,可先去閱讀下博客:KL 散度和交叉熵

 

   注意輸出標簽不一定是 $0$ 和 $1$,但概率一定是 $0,1$ 且只有一項,其它項都是 $0$,如果標簽比如是 $3,4$,是不能直接代入 BCELoss 的,

   因為這里標簽為 $0,1$ 正好等於概率,所以才直接代入的。當輸出標簽為 $0,1$ 時,無論哪種情況,每個樣本對應的交叉熵為:

$$L_{one} = - \big [\; y \ln \hat{y} + (1 - y)\ln (1 - \hat{y}) \;\big]$$

   函數原型如下:

"""
weight 必須和 target 的 shape 一致
reduce = False,損失函數返回的是向量形式的 loss,這種情況下參數 size_average 失效。
reduce = True, 損失函數返回的是標量形式的 loss,這種情況下:
    1)當 size_average = True 時,返回 loss.mean(),即所有向量元素求和后再除以向量長度,這種情況就是交叉熵
    2)當 size_average = False 時,返回 loss.sum(),即所有向量元素只求和,這種情況就是極大似然估計
默認情況下:weight 為 None, size_average 和 reduce 為 True。
"""
CLASS torch.nn.BCELoss(weight = None, size_average=True, reduce=True)

   舉個例子:

import torch
 
S = torch.nn.Sigmoid()
loss = torch.nn.BCELoss()
input = torch.randn(3, requires_grad=True)
target = torch.empty(3).random_(2)
output = loss(S(input), target)
print(output)

"""
tensor(0.7957, grad_fn=<BinaryCrossEntropyBackward>)
"""

 

3. torch.nn.CrossEntropyLoss

   這個和 BCELoss 其實是一樣的,只不過 BCELoss 算的是二類,而 CrossEntropyLoss 算的是多類,比如輸出類別 $0,1,2,3,4,5,6,7,8,9$ 共 $10$

   個類別,每個樣本喂給神經網絡,一定只會輸出一個類別。舉個例子,一個輸入對應的輸出類別為 $3$,那么它對應的分布長成這樣:

      

   這個樣本輸出類別為 $3$,意味着 $P(y = 3) = 1$,其它概率都是 $0$,那么可以計算這個樣本的交叉熵損失為:

$$L_{one} = - \big [ \; 0 \cdot \ln \hat{y}_{0} + 0 \cdot \ln \hat{y}_{1} + 0 \cdot \ln \hat{y}_{2} + 
1 \cdot \ln \hat{y}_{3} + 0 \cdot \ln \hat{y}_{4} \\
+ 0 \cdot \ln \hat{y}_{5} + 0 \cdot \ln \hat{y}_{6} + 0 \cdot \ln \hat{y}_{7} + 0 \cdot \ln \hat{y}_{8} + 0 \cdot \ln \hat{y}_{9}\; \big]$$

   當使用 CrossEntropyLoss 損失函數的時候,神經網絡的輸出就不用再接 $softmax$ 層了,因為這個損失函數內部會做這個歸一化,同時它還會根據

   對應的輸出標簽 $y$ 生成 $one-hot$ 向量。如下圖所示:

      

   左邊輸入的是不帶激活函數的神經網絡的輸出,右邊輸入的是該樣本的標簽,比如標簽 $3$,那么會生成 $one-hot$ 向量 $(0,0,0,1,0,0,0,0,0,0)$。

   上面只是個示意圖,並不對應。生成的 $one-hot$ 向量其實就是該樣本分布的真實概率。

"""
weight(Tensor, optional) - 每個類別對應的權重,默認是值為 1 的 Tensor
size_average(bool, optional) - 默認為 True, reduce = True 時忽略該參數。
   size_average = True: 則 losses 在 minibatch 結合 weight 求平均
   size_average = False: 則 losses 在 minibatch 只求相加和
ignore_index: 不知道干啥用
reduce: 默認為 True, 為 False 則返回 loss 向量,不求和
"""
class torch.nn.CrossEntropyLoss(weight=None, size_average=True, ignore_index=-100, reduce=True)

   舉個例子:

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM