深度學習中softmax交叉熵損失函數的理解


1. softmax層的作用
通過神經網絡解決多分類問題時,最常用的一種方式就是在最后一層設置n個輸出節點,無論在淺層神經網絡還是在CNN中都是如此,比如,在AlexNet中最后的輸出層有1000個節點,即便是ResNet取消了全連接層,但1000個節點的輸出層還在。
一般情況下,最后一個輸出層的節點個數與分類任務的目標數相等。
假設最后的節點數為N,那么對於每一個樣例,神經網絡可以得到一個N維的數組作為輸出結果,數組中每一個維度會對應一個類別。在最理想的情況下,如果一個樣本屬於k,那么這個類別所對應的的輸出節點的輸出值應該為1,而其他節點的輸出都為0,即 [0,0,1,0,….0,0][0,0,1,0,….0,0],這個數組也就是樣本的Label,是神經網絡最期望的輸出結果,但實際是這樣的輸出[0.01,0.01,0.6,....0.02,0.01][0.01,0.01,0.6,....0.02,0.01],這其實是在原始輸出的基礎上加入了softmax的結果,原始的輸出是輸入的數值做了復雜的加權和與非線性處理之后的一個值而已,這個值可以是任意的值,但是經過softmax層后就成了一個概率值,而且概率和為1。
假設神經網絡的原始輸出為y_1,y_2,….,y_n,那么經過Softmax回歸處理之后的輸出為 :
y′=softmax(yi)=eyi∑nj=1eyj
y′=softmax(yi)=eyi∑j=1neyj
以上可以看出:∑y′=1∑y′=1
這也是為什么softmax層的每個節點的輸出值成為了概率和為1的概率分布。
2. 交叉熵損失函數的數學原理
上面說過實際的期望輸出,也就是標簽是[0,0,1,0,….0,0][0,0,1,0,….0,0]這種形式,而實際的輸出是[0.01,0.01,0.6,....0.02,0.01][0.01,0.01,0.6,....0.02,0.01]這種形式,這時按照常理就需要有一個損失函數來判定實際輸出和期望輸出的差距,交叉熵就是用來判定實際的輸出與期望的輸出的接近程度!下面就簡單介紹下交叉熵的原理。
交叉熵刻畫的是實際輸出(概率)與期望輸出(概率)的距離,也就是交叉熵的值越小,兩個概率分布就越接近。假設概率分布p為期望輸出(標簽),概率分布q為實際輸出,H(p,q)為交叉熵。
第一種交叉熵損失函數的形式:
H(p,q)=−∑xp(x)logq(x)
H(p,q)=−∑xp(x)logq(x)
舉個例子:
假設N=3,期望輸出為p=(1,0,0),實際輸出q1=(0.5,0.2,0.3),q2=(0.8,0.1,0.1)q1=(0.5,0.2,0.3),q2=(0.8,0.1,0.1),這里的q1,q2兩個輸出分別代表在不同的神經網絡參數下的實際輸出,通過計算其對應的交叉熵來優化神經網絡參數,計算過程:
H(p,q1)=−1(1×log0.5+0×log0.2+0×log0.3)H(p,q1)=−1(1×log0.5+0×log0.2+0×log0.3)
假設結果:H(p,q1)=0.3H(p,q1)=0.3
H(p,q2)=−1(1×log0.8+0×log0.1+0×log0.1)H(p,q2)=−1(1×log0.8+0×log0.1+0×log0.1)
假設結果:H(p,q2)=0.1H(p,q2)=0.1
這時得到了q2q2是相對正確的分類結果。
第二種交叉熵損失函數形式:
H(p,q)=−∑x(p(x)logq(x)+(1−p(x))log(1−q(x)))
H(p,q)=−∑x(p(x)logq(x)+(1−p(x))log(1−q(x)))
下面簡單推到其過程:
我們知道,在二分類問題模型:例如邏輯回歸「Logistic Regression」、神經網絡「Neural Network」等,真實樣本的標簽為 [0,1],分別表示負類和正類。模型的最后通常會經過一個 Sigmoid 函數,輸出一個概率值,這個概率值反映了預測為正類的可能性:概率越大,可能性越大。
Sigmoid 函數的表達式和圖形如下所示:g(s)=11+e−sg(s)=11+e−s
其中 s 是模型上一層的輸出,Sigmoid 函數有這樣的特點:s = 0 時,g(s) = 0.5;s >> 0 時, g ≈ 1,s << 0 時,g ≈ 0。顯然,g(s) 將前一級的線性輸出映射到 [0,1] 之間的數值概率上。
其中預測輸出即 Sigmoid 函數的輸出g(s)表征了當前樣本標簽為 1 的概率:
P(y=1|x)=y^P(y=1|x)=y^
p(y=0|x)=1−y^p(y=0|x)=1−y^
這個時候從極大似然性的角度出發,把上面兩種情況整合到一起:
p(y|x)=y^y(1−y^)(1−y)p(y|x)=y^y(1−y^)(1−y)
這個函數式表征的是:
當真實樣本標簽 y = 1 時,上面式子第二項就為 1,概率等式轉化為:
P(y=1|x)=y^P(y=1|x)=y^
當真實樣本標簽 y = 0 時,上面式子第一項就為 1,概率等式轉化為:
P(y=0|x)=1−y^P(y=0|x)=1−y^
兩種情況下概率表達式跟之前的完全一致,只不過我們把兩種情況整合在一起了。那這個時候應用極大似然估計應該得到的是所有的概率值乘積應該最大,即:
L=∑Ni=1y^yii(1−y^i)(1−yi)L=∑i=1Ny^iyi(1−y^i)(1−yi)
引入log函數后得到:
L′=log(L)=∑Ni=1yilogy^i+(1−yi)log(1−y^i)L′=log(L)=∑i=1Nyilogy^i+(1−yi)log(1−y^i)
這時令loss=-log(L)=-L',也就是損失函數越小越好,而此時也就是 L'越大越好。
而在實際的使用訓練過程中,數據往往是組合成為一個batch來使用,所以對用的神經網絡的輸出應該是一個m*n的二維矩陣,其中m為batch的個數,n為分類數目,而對應的Label也是一個二維矩陣,還是拿上面的數據,組合成一個batch=2的矩陣
q=[0.50.80.20.10.30.1]
q=[0.50.20.30.80.10.1]
p=[110000]
p=[100100]
根據第一種交叉熵的形式得到:
H(p,q)=[0.30.1]
H(p,q)=[0.30.1]
而對於一個batch,最后取平均為0.2。
3. 在TensorFlow中實現交叉熵
在TensorFlow可以采用這種形式:
cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0)))
1
其中y_表示期望的輸出,y表示實際的輸出(概率值),*為矩陣元素間相乘,而不是矩陣乘。
並且通過tf.clip_by_value函數可以將一個張量中的數值限制在一個范圍之內,這樣可以避免一些運算錯誤(比如log0是無效的),tf.clip_by_value函數是為了限制輸出的大小,為了避免log0為負無窮的情況,將輸出的值限定在(1e-10, 1.0)之間,其實1.0的限制是沒有意義的,因為概率怎么會超過1呢。比如:
import tensorflow as tf
v=tf.constant([[1.0,2.0,3.0],[4.0,5.0,6.0]])
with tf.Session() as sess:
    print(tf.clip_by_value(v,2.5,4.5).eval(session=sess))
1
2
3
4
5
結果:
[[2.5 2.5 3. ]
 [4.  4.5 4.5]]
1
2
上述代碼實現了第一種形式的交叉熵計算,需要說明的是,計算的過程其實和上面提到的公式有些區別,按照上面的步驟,平均交叉熵應該是先計算batch中每一個樣本的交叉熵后取平均計算得到的,而利用tf.reduce_mean函數其實計算的是整個矩陣的平均值,這樣做的結果會有差異,但是並不改變實際意義。
import tensorflow as tf
v=tf.constant([[1.0,2.0,3.0],[4.0,5.0,6.0]])
with tf.Session() as sess:
    # 輸出3.5
    print(tf.reduce_mean(v).eval())
1
2
3
4
5
6
由於在神經網絡中,交叉熵常常與Sorfmax函數組合使用,所以TensorFlow對其進行了封裝,即:
cross_entropy = tf.nn.sorfmax_cross_entropy_with_logits(y_ ,y)
1
與第一個代碼的區別在於,這里的y用神經網絡最后一層的原始輸出就好了,而不是經過softmax層的概率值。
————————————————
版權聲明:本文為CSDN博主「lilong117194」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/lilong117194/article/details/81542667


免責聲明!

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



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