1. 程式人生 > >TensorFlow學習筆記(二十三)四種Cross Entropy交叉熵演算法實現和應用

TensorFlow學習筆記(二十三)四種Cross Entropy交叉熵演算法實現和應用

交叉熵(Cross-Entropy)

交叉熵是一個在ML領域經常會被提到的名詞。在這篇文章裡將對這個概念進行詳細的分析。

1.什麼是資訊量?

假設是一個離散型隨機變數,其取值集合為,概率分佈函式為

p ( x ) = r ( = x ) , x ∈ 
,我們定義事件

= x 0 
的資訊量為: 

( x 0 ) = − l o ( p ( x 0 ) ) 
,可以理解為,一個事件發生的概率越大,則它所攜帶的資訊量就越小,而當

p ( x 0 ) = 1 
時,熵將等於0,也就是說該事件的發生不會導致任何資訊量的增加。舉個例子,小明平時不愛學習,考試經常不及格,而小王是個勤奮學習的好學生,經常得滿分,所以我們可以做如下假設: 
事件A:小明考試及格,對應的概率

( x A ) = 0.1 
,資訊量為

( x A ) = − log ( 0.1 ) = 3.3219 

事件B:小王考試及格,對應的概率

( x B ) = 0.999 
,資訊量為

( x B ) = − log ( 0.999 ) = 0.0014 

可以看出,結果非常符合直觀:小明及格的可能性很低(十次考試只有一次及格),因此如果某次考試及格了(大家都會說:XXX竟然及格了!),必然會引入較大的資訊量,對應的值也較高。而對於小王而言,考試及格是大概率事件,在事件B發生前,大家普遍認為事件B的發生幾乎是確定的,因此當某次考試小王及格這個事件發生時並不會引入太多的資訊量,相應的值也非常的低。

2.什麼是熵?

那麼什麼又是熵呢?還是通過上邊的例子來說明,假設小明的考試結果是一個0-1分佈


只有兩個取值{0:不及格,1:及格},在某次考試結果公佈前,小明的考試結果有多大的不確定度呢?你肯定會說:十有八九不及格!因為根據先驗知識,小明及格的概率僅有0.1,90%的可能都是不及格的。怎麼來度量這個不確定度?求期望!不錯,我們對所有可能結果帶來的額外資訊量求取均值(期望),其結果不就能夠衡量出小明考試成績的不確定度了嗎。

即:

 

A ( x ) = − [ p ( x A ) log ( p ( x A ) ) + ( 1 − p ( x A ) ) log ( 1 − p ( x A ) ) ] = 0.4690 

對應小王的熵:

 

B ( x ) = − [ p ( x B ) log ( p ( x B ) ) + ( 1 − p ( x B ) ) log ( 1 − p ( x B ) ) ] = 0.0114 

雖然小明考試結果的不確定性較低,畢竟十次有9次都不及格,但是也比不上小王(1000次考試只有一次才可能不及格,結果相當的確定)

我們再假設一個成績相對普通的學生小東,他及格的概率是

( x ) = 0.5 
,即及格與否的概率是一樣的,對應的熵:

 

( x ) = − [ p ( x ) log ( p ( x ) ) + ( 1 − p ( x ) ) log ( 1 − p ( x ) ) ] = 1 

其熵為1,他的不確定性比前邊兩位同學要高很多,在成績公佈之前,很難準確猜測出他的考試結果。

可以看出,熵其實是資訊量的期望值,它是一個隨機變數的確定性的度量。熵越大,變數的取值越不確定,反之就越確定。

對於一個隨機變數X而言,它的所有可能取值的資訊量的期望(

[ ( x ) ] 
)就稱為熵。

的熵定義為:

 

( ) = p log 1 p ( x ) = − ∑ x ∈ p ( x ) log p ( x ) 

如果

p ( x ) 
是連續型隨機變數的pdf,則熵定義為:

 

( ) = − x ∈ p ( x ) log p ( x ) x 

為了保證有效性,這裡約定當

p ( x ) → 0 時 , 有 p ( x ) log p ( x ) → 0 

當X為0-1分佈時,熵與概率p的關係如下圖: 

可以看出,當兩種取值的可能性相等時,不確定度最大(此時沒有任何先驗知識),這個結論可以推廣到多種取值的情況。在圖中也可以看出,當p=0或1時,熵為0,即此時X完全確定。 
熵的單位隨著公式中log運算的底數而變化,當底數為2時,單位為“位元”(bit),底數為e時,單位為“奈特”。

3.什麼是相對熵?

相對熵(relative entropy)又稱為KL散度(Kullback-Leibler divergence),KL距離,是兩個隨機分佈間距離的度量。記為

D L ( p | | ) 
。它度量當真實分佈為p時,假設分佈q的無效性。 

D L ( p | | ) = p [ log p ( x ) ( x ) ] = ∑ x ∈ p ( x ) log p ( x ) ( x ) 
 

= ∑ x ∈ [ p ( x ) log p ( x ) − p ( x ) log ( x ) ] 
 

= ∑ x ∈ p ( x ) log p ( x ) − ∑ x ∈ p ( x ) log ( x ) 
 

= − ( p ) − ∑ x ∈ p ( x ) log ( x ) 
 

= − ( p ) + p [ − log ( x ) ] 
 

= p ( ) − ( p ) 

並且為了保證連續性,做如下約定: 

0 log 0 0 = 0 , 0 log = 0 , p log p 0 = ∞ 

顯然,當

p = 
時,兩者之間的相對熵

D L ( p | | ) = 0 

上式最後的

p ( ) 
表示在p分佈下,使用q進行編碼需要的bit數,而H(p)表示對真實分佈


所需要的最小編碼bit數。基於此,相對熵的意義就很明確了:

D L ( p | | ) 
表示在真實分佈為p的前提下,使用q分佈進行編碼相對於使用真實分佈p進行編碼(即最優編碼)所多出來的bit數。

4. 什麼是交叉熵?

交叉熵容易跟相對熵搞混,二者聯絡緊密,但又有所區別。假設有兩個分佈

p , 
,則它們在給定樣本集上的交叉熵定義如下: 

( p , ) = p [ − log ] = − ∑ x ∈ p ( x ) log ( x ) = ( p ) + D L ( p | | ) 

可以看出,交叉熵與上一節定義的相對熵僅相差了

( p ) 
,當


已知時,可以把

( p ) 
看做一個常數,此時交叉熵與KL距離在行為上是等價的,都反映了分佈p,q的相似程度。最小化交叉熵等於最小化KL距離。它們都將在

p = 
時取得最小值

( p ) 
(p=q時KL距離為0),因此有的工文獻中將最小化KL距離的方法稱為Principle of Minimum Cross-Entropy (MCE)或Minxent方法。 
特別的,在logistic regression中, 
p:真實樣本分佈,服從引數為p的0-1分佈,即

∼ B ( 1 , p ) 

q:待估計的模型,服從引數為q的0-1分佈,即

∼ B ( 1 , ) 

兩者的交叉熵為: 

( p , ) 
 

= − ∑ x ∈ p(x) log q(x) 
 

= − [ p ( x = 1 ) log ( x = 1 ) + p ( x = 0 ) log ( x = 0 ) ] 
 

= − [ p log + ( 1 − p ) log ( 1 − ) ] 
 

= − [ y log h θ ( x ) + ( 1 − y ) log ( 1 − h θ ( x ) ) ] 

對所有訓練樣本取均值得: 

− 1 m ∑ i = 1 m [ ( i ) log h θ ( x ( i ) ) + ( 1 − ( i ) ) log ( 1 − h θ ( x ( i ) ) ) ] 

這個結果與通過最大似然估計方法求出來的結果一致。

在ML或者DL中,交叉熵(Cross Entropy)是Loss函式的一種(也稱為損失函式或代價函式),用於描述模型預測值與真實值的差距大小,常見的Loss函式就是均方平方差(Mean Squared Error),定義如下。

​平方差很好理解,預測值與真實值直接相減,為了避免得到負數取絕對值或者平方,再做平均就是均方平方差。注意這裡預測值需要經過sigmoid啟用函式,得到取值範圍在0到1之間的預測值。

平方差可以表達預測值與真實值的差異,但在分類問題種效果並不如交叉熵好,原因可以參考 這篇博文。交叉熵的定義如下,截圖來自 https://hit-scir.gitbooks.io/neural-networks-and-deep-learning-zh_cn/content/chap3/c3s1.html 。

上面的文章也介紹了交叉熵可以作為Loss函式的原因,首先是交叉熵得到的值一定是正數,其次是預測結果越準確值越小,注意這裡用於計算的“a”也是經過sigmoid啟用的,取值範圍在0到1。如果label是1,預測值也是1的話,前面一項y * ln(a)就是1 * ln(1)等於0,後一項(1 – y) * ln(1 – a)也就是0 * ln(0)等於0,Loss函式為0,反之Loss函式為無限大非常符合我們對Loss函式的定義。

這裡多次強調sigmoid啟用函式,是因為在多目標或者多分類的問題下有些函式是不可用的,而TensorFlow本身也提供了多種交叉熵演算法的實現。

TensorFlow針對分類問題,實現了四個交叉熵函式,分別是

tf.nn.sigmoid_cross_entropy_with_logits 、 tf.nn.softmax_cross_entropy_with_logits 、 tf.nn.sparse_softmax_cross_entropy_with_logits 和 tf.nn.weighted_cross_entropy_with_logits ,詳細內容參考API文件 https://www.tensorflow.org/versions/master/api_docs/python/nn.html#sparse_softmax_cross_entropy_with_logits

sigmoid_cross_entropy_with_logits詳解

我們先看sigmoid_cross_entropy_with_logits,為什麼呢,因為它的實現和前面的交叉熵演算法定義是一樣的,也是TensorFlow最早實現的交叉熵演算法。 這個函式的輸入是logits和targets,logits就是神經網路模型中的 W * X矩陣,注意不需要經過sigmoid,而targets的shape和logits相同, 就是正確的label值,例如這個模型一次要判斷100張圖是否包含10種動物,這兩個輸入的shape都是[100, 10]。註釋中還提到這10個分類之間是獨立的、不要求是互斥,這種問題我們成為多目標,例如判斷圖片中是否包含10種動物,label值可以包含多個1或0個1,還有一種問題是多分類問題,例如我們對年齡特徵分為5段,只允許5個值有且只有1個值為1,這種問題可以直接用這個函式嗎?答案是不可以,我們先來看看sigmoid_cross_entropy_with_logits的程式碼實現吧。

可以看到這就是標準的Cross Entropy演算法實現,對W * X得到的值進行sigmoid啟用,保證取值在0到1之間,然後放在交叉熵的函式中計算Loss。對於二分類問題這樣做沒問題,但對於前面提到的多分類,例如年輕取值範圍在0~4,目標值也在0~4,這裡如果經過sigmoid後預測值就限制在0到1之間,而且公式中的1 – z就會出現負數,仔細想一下0到4之間還不存線上性關係,如果直接把label值帶入計算肯定會有非常大的誤差。因此對於多分類問題是不能直接代入的,那其實我們可以靈活變通,把5個年齡段的預測用onehot encoding變成5維的label,訓練時當做5個不同的目標來訓練即可,但不保證只有一個為1,對於這類問題TensorFlow又提供了基於Softmax的交叉熵函式。

softmax_cross_entropy_with_logits詳解

Softmax本身的演算法很簡單,就是把所有值用e的n次方計算出來,求和後算每個值佔的比率,保證總和為1,一般我們可以認為Softmax出來的就是confidence也就是概率,演算法實現如下。

​softmax_cross_entropy_with_logits和sigmoid_cross_entropy_with_logits很不一樣,輸入是類似的logits和lables的shape一樣,但這裡要求分類的結果是互斥的,保證只有一個欄位有值,例如CIFAR-10中圖片只能分一類而不像前面判斷是否包含多類動物。想一下問什麼會有這樣的限制?在函式頭的註釋中我們看到,這個函式傳入的logits是unscaled的,既不做sigmoid也不做softmax,因為函式實現會在內部更高效得使用softmax,對於任意的輸入經過softmax都會變成和為1的概率預測值,這個值就可以代入變形的Cross Entroy演算法- y * ln(a) – (1 – y) * ln(1 – a)演算法中,得到有意義的Loss值了。如果是多目標問題,經過softmax就不會得到多個和為1的概率,而且label有多個1也無法計算交叉熵,因此這個函式只適合單目標的二分類或者多分類問題,TensorFlow函式定義如下。

再補充一點,對於多分類問題,例如我們的年齡分為5類,並且人工編碼為0、1、2、3、4,因為輸出值是5維的特徵,因此我們需要人工做onehot encoding分別編碼為00001、00010、00100、01000、10000,才可以作為這個函式的輸入。理論上我們不做onehot encoding也可以,做成和為1的概率分佈也可以,但需要保證是和為1,和不為1的實際含義不明確,TensorFlow的C++程式碼實現計劃檢查這些引數,可以提前提醒使用者避免誤用。

sparse_softmax_cross_entropy_with_logits詳解

sparse_softmax_cross_entropy_with_logits是softmax_cross_entropy_with_logits的易用版本,除了輸入引數不同,作用和演算法實現都是一樣的。前面提到softmax_cross_entropy_with_logits的輸入必須是類似onehot encoding的多維特徵,但CIFAR-10、ImageNet和大部分分類場景都只有一個分類目標,label值都是從0編碼的整數,每次轉成onehot encoding比較麻煩,有沒有更好的方法呢?答案就是用sparse_softmax_cross_entropy_with_logits,它的第一個引數logits和前面一樣,shape是[batch_size, num_classes],而第二個引數labels以前也必須是[batch_size, num_classes]否則無法做Cross Entropy,這個函式改為限制更強的[batch_size],而值必須是從0開始編碼的int32或int64,而且值範圍是[0, num_class),如果我們從1開始編碼或者步長大於1,會導致某些label值超過這個範圍,程式碼會直接報錯退出。這也很好理解,TensorFlow通過這樣的限制才能知道使用者傳入的3、6或者9對應是哪個class,最後可以在內部高效實現類似的onehot encoding,這只是簡化使用者的輸入而已,如果使用者已經做了onehot encoding那可以直接使用不帶“sparse”的softmax_cross_entropy_with_logits函式。

weighted_sigmoid_cross_entropy_with_logits詳解

weighted_sigmoid_cross_entropy_with_logits是sigmoid_cross_entropy_with_logits的拓展版,輸入引數和實現和後者差不多,可以多支援一個pos_weight引數,目的是可以增加或者減小正樣本在算Cross Entropy時的Loss。實現原理很簡單,在傳統基於sigmoid的交叉熵演算法上,正樣本算出的值乘以某個係數介面,演算法實現如下。

​總結

這就是TensorFlow目前提供的有關Cross Entropy的函式實現,使用者需要理解多目標和多分類的場景, 根據業務需求(分類目標是否獨立和互斥)來選擇基於sigmoid或者softmax的實現, 如果使用sigmoid目前還支援加權的實現,如果使用softmax我們可以自己做onehot coding或者使用更易用的sparse_softmax_cross_entropy_with_logits函式。

TensorFlow提供的Cross Entropy函式基本cover了多目標和多分類的問題,但如果同時是多目標多分類的場景,肯定是無法使用softmax_cross_entropy_with_logits,如果使用sigmoid_cross_entropy_with_logits我們就把多分類的特徵都認為是獨立的特徵,而實際上他們有且只有一個為1的非獨立特徵,計算Loss時不如Softmax有效。這裡可以預測下,未來TensorFlow社群將會實現更多的op解決類似的問題,我們也期待更多人蔘與TensorFlow貢獻演算法和程式碼

參考:http://dataunion.org/26447.html