【Deep Learning】Softmax和交叉熵損失函數

前言

​ SoftMax和Sigmoid是搭建神經網絡時常見的兩種激活函數。由於最近在做一個多分類的任務,使用到了Softmax函數,這裏僅簡單提一下Sigmoid,詳細介紹Softmax函數。

Sigmoid

Sigmoid函數由下列公式定義
在這裏插入圖片描述
Sigmoid函數的圖形如S曲線
在這裏插入圖片描述

SoftMax

Sigmoid函數由下列公式定義
在這裏插入圖片描述
softmax 的作用是把 一個序列,變成概率
在這裏插入圖片描述
softmax用於多分類過程中,它將多個神經元的輸出,映射到(0,1)區間內,所有概率的和將等於1。

LogSoftMax

​ 在介紹完Softmax函數後,這裏又出現了LogSoftMax函數,那麼這個函數與Softmax函數有什麼區別?它又有什麼作用呢?

LogSoftmax函數由下列公式定義
在這裏插入圖片描述
​ 由於使用SoftMax函數計算數值的穩定性不高,而且還有可能報 NaN的錯誤[2],因此一種可能的替代的方案是使用LogSoftMax(然後再求 exp)數值穩定定性比 softmax 好一些。
在這裏插入圖片描述
​ 可以看到,LogSoftMax省了一個指數計算,省了一個除法,數值上相對穩定一些。

交叉熵損失函數

​ 交叉熵(cross entropy)是深度學習中常用的一個概念,一般用來求目標與預測值之間的差距。在介紹交叉熵損失函數之前,首先需要了解幾個概念。

信息量

“太陽從東邊升起”,這條信息陳述了一個事實,因爲太陽肯定是從東邊升起的,這是一句廢話,信息量爲0。

”2018年中國隊成功進入世界盃“,從直覺上來看,這句話具有很大的信息量。因爲中國隊進入世界盃的不確定性因素很大,而這句話消除了進入世界盃的不確定性,所以按照定義,這句話的信息量很大。

根據上述可總結如下:信息量的大小與信息發生的概率成反比。概率越大,信息量越小。概率越小,信息量越大。

設某一事件發生的概率爲P(x),其信息量表示爲:

信息熵

信息熵也被稱爲熵,用來表示所有信息量的期望。

期望是試驗中每次可能結果的概率乘以其結果的總和。

所以信息量的熵可表示爲:
在這裏插入圖片描述
使用明天的天氣概率來計算其信息熵:
在這裏插入圖片描述
H(X)=−(0.5∗log(0.5)+0.2∗log(0.2)+0.3∗log(0.3))*

相對熵(KL散度)

​ 如果對於同一個隨機變量XXX有兩個單獨的概率分佈P(x)和Q(x),則我們可以使用KL散度來衡量這兩個概率分佈之間的差異。公式如下:
在這裏插入圖片描述
​ 在機器學習中,常常使用P(x)來表示樣本的真實分佈,Q(x)來表示模型所預測的分佈,比如在一個三分類任務中(例如,貓狗馬分類器),X1,X2,X3 分別代表貓,狗,馬,例如一張貓的圖片真實分佈P(X)=[1,0,0],預測分佈Q(X)=[0.7,0.2,0.1],計算KL散度:
在這裏插入圖片描述
​ KL散度越小,表示P(x)的分佈更加接近,可以通過反覆訓練Q(x)來使Q(x)的分佈逼近P(x)。

交叉熵

首先將KL散度公式拆開:

H(p(x))表示信息熵,後者即爲交叉熵,KL散度 = 交叉熵 - 信息熵

在這裏插入圖片描述
交叉熵公式
在這裏插入圖片描述
(上述公式中 q(xi) 即爲SoftMax函數求出的值)

​ 在機器學習訓練網絡時,輸入數據與標籤常常已經確定,那麼真實概率分佈P(x)也就確定下來了,所以信息熵在這裏就是一個常量。由於KL散度的值表示真實概率分佈P(x)與預測概率分佈Q(x)之間的差異,值越小表示預測的結果越好,所以需要最小化KL散度,而交叉熵等於KL散度加上一個常量(信息熵),且公式相比KL散度更加容易計算,所以在機器學習中常常使用交叉熵損失函數來計算loss就行了[3]

NLLLoss函數

​ 最近在使用神經網絡做圖像的分類,使用到了pytorch框架,NLLLoss和CrossEntropyLoss兩個函數設計到了交叉熵損失函數,而且這兩個函數易爲混淆,故這裏特地記錄下來,方便日後查閱。

吐槽一下,pytorch的官方文檔寫的極其簡陋!

NLLLoss函數表達式:f(x,class)=−x[class]

​ 例如:假設 x = [1,2,3],真實類別class = 2,那麼f(x,class)=−x[2]=−3

NLLLoss函數的輸入

​ 1. 是一個對數概率向量(先進行了SoftMax操作,對其進行-log操作,也就是LogSoftmax操作);

​ 2. 一個目標標籤;

NLLLoss函數的輸出:

​ 把上面的對數概率向量與Label對應的那個值拿出來,再去掉負號,再求均值。

import torch
import torch.nn as nn
# 使用NLLLoss損失函數
output = torch.randn(3, 3) # 模擬預測輸出
logsm = nn.LogSoftmax(dim=1)  # LogSoftmax
NLLLloss = nn.NLLLoss()  # 負對數似然損失函數
target = torch.tensor([0, 2, 1])  # 目標標籤
result1 = NLLLloss(logsm(output), target)
print(output)  # 打印模擬的預測張量元素
print(result1)  # 打印使用NLLLoss損失函數結果
tensor([[ 0.1721, -0.8006, -0.8058],
        [-0.0211, -0.7485,  0.3632],
        [ 1.3830,  0.2733,  0.3185]]) # 模擬的張量元素
tensor(0.9618) # 使用NLLLoss損失函數計算的結果

我們可以驗證一下NLLLoss函數的輸出結果:

###驗證NLLLoss損失的結果
print(logsm(output))  # 打印模擬的張量元素經過LogSoftmax後的結果

下面是對模擬的張量元素進行LogSoftmax後的結果

tensor([[-0.5620, -1.5347, -1.5399],
        [-1.0824, -1.8098, -0.6981],
        [-0.5155, -1.6253, -1.5801]]) # 經過LogSoftmax後的結果

經過計算:-(-0.562-0.6981-1.6253) / 3 = 0.9681 與使用NLLLoss損失函數計算的結果相同。

注: NLLLoss函數不會爲我們計算對數概率,適合最後一層是LogSoftmax函數的網絡

CrossEntropyLoss函數

​ 在上面我已經介紹了交叉熵損失函數的表達式,這裏再給出:
在這裏插入圖片描述
​ 其中 Pk 表示真實值,在這個公式中是one-hot形式; qk 是預測值,在這裏假設已經是經過softmax後的結果了。仔細觀察可以知道,因爲Pk 的元素不是0就是1,而且又是乘法,所以很自然地我們如果知道1所對應的index,那麼就不用做其他無意義的運算了。所以在pytorch代碼中target不是以one-hot形式表示的,而是直接用scalar表示。所以交叉熵的公式(m表示真實類別)可變形爲:
在這裏插入圖片描述
​ 仔細觀察,其實CrossEntropyLoss就等同於LogsoftmaxNLLLoss兩個步驟(把Softmax–Log–NLLLoss合併成一步)。其計算方式即爲:
在這裏插入圖片描述

# 使用交叉熵損失函數
crossEntropyLoss = nn.CrossEntropyLoss()  # 交叉熵損失函數
result2 = crossEntropyLoss(output, target)
print(result2)
tensor(0.9618) # 使用交叉熵損失函數計算的結果

可以發現,對模擬張量元素,經過LogSoftmax後輸入到NLLLoss函數得到的結果與將模擬的張量元素直接輸入到CrossEntropyLoss函數中的結果相同。

參考鏈接

[1] https://blog.csdn.net/uncle_ll/article/details/82778750

[2] https://www.zhihu.com/search?type=content&q=logsoftmax

[3] https://blog.csdn.net/b1055077005/article/details/100152102

[4] https://zhuanlan.zhihu.com/p/2572311

[5] https://www.cnblogs.com/marsggbo/p/10401215.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章