【小知識】Softmax函數與交叉熵

2021-02-20 程式設計師大白

點擊上方「程式設計師大白」,選擇「星標」公眾號

重磅乾貨,第一時間送達

來自 | 知乎

地址 | https://zhuanlan.zhihu.com/p/27223959

作者 | 殺手XIII

編輯 | 程式設計師大白公眾號

本文僅作學術分享,若侵權,請聯繫後臺刪文處理

Softmax函數

背景與定義

在Logistic regression二分類問題中,我們可以使用sigmoid函數將輸入映射到區間中,從而得到屬於某個類別的概率。將這個問題進行泛化,推廣到多分類問題中,我們可以使用softmax函數,對輸出的值歸一化為概率值。

這裡假設在進入softmax函數之前,已經有模型輸出值,其中是要預測的類別數,模型可以是全連接網絡的輸出,其輸出個數為,即輸出為

所以對每個樣本,它屬於類別的概率為:

通過上式可以保證,即屬於各個類別的概率和為1。

導數

對softmax函數進行求導,即求



項的輸出對第項輸入的偏導。
代入softmax函數表達式,可以得到:

用我們高中就知道的求導規則:對於



它的導數為



所以在我們這個例子中,



上面兩個式子只是代表直接進行替換,而非真的等式。

(即)對進行求導,要分情況討論:

如果,則求導結果為

如果,則求導結果為

再來看求導,結果為

所以,當時:



時:

其中,為了方便,令

對softmax函數的求導,我在兩年前微信校招面試基礎研究崗位一面的時候,就遇到過,這個屬於比較基礎的問題。

softmax的計算與數值穩定性

在Python中,softmax函數為:

def softmax(x):
exp_x = np.exp(x)
return exp_x / np.sum(exp_x)

傳入[1, 2, 3, 4, 5]的向量

>>> softmax([1, 2, 3, 4, 5])
array([ 0.01165623, 0.03168492, 0.08612854, 0.23412166, 0.63640865])

但如果輸入值較大時:

>>> softmax([1000, 2000, 3000, 4000, 5000])
array([ nan, nan, nan, nan, nan])

這是因為在求exp(x)時候溢出了:

import math
math.exp(1000)
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# OverflowError: math range error

一種簡單有效避免該問題的方法就是讓exp(x)中的x值不要那麼大或那麼小,在softmax函數的分式上下分別乘以一個非零常數:



這裡是個常數,所以可以令它等於。加上常數之後,等式與原來還是相等的,所以我們可以考慮怎麼選取常數。我們的想法是讓所有的輸入在0附近,這樣的值不會太大,所以可以讓的值為:



這樣子將所有的輸入平移到0附近(當然需要假設所有輸入之間的數值上較為接近),同時,除了最大值,其他輸入值都被平移成負數,為底的指數函數,越小越接近0,這種方式比得到nan的結果更好。

def softmax(x):
shift_x = x - np.max(x)
exp_x = np.exp(shift_x)
return exp_x / np.sum(exp_x)

>>> softmax([1000, 2000, 3000, 4000, 5000])
array([ 0., 0., 0., 0., 1.])

當然這種做法也不是最完美的,因為softmax函數不可能產生0值,但這總比出現nan的結果好,並且真實的結果也是非常接近0的。

UPDATE(2017-07-07):

有同學問這種近似會不會影響計算結果,為了看原來的softmax函數計算結果怎麼樣,嘗試計算`softmax([1000, 2000, 3000, 4000, 5000])`的值。由於numpy是會溢出的,所以使用Python中的bigfloat庫。

import bigfloat

def softmax_bf(x):
exp_x = [bigfloat.exp(y) for y in x]
sum_x = sum(exp_x)
return [y / sum_x for y in exp_x]

res = softmax_bf([1000, 2000, 3000, 4000, 5000])
print('[%s]' % ', '.join([str(x) for x in res]))

結果:

[6.6385371046556741e-1738, 1.3078390189212505e-1303, 2.5765358729611501e-869, 5.0759588975494576e-435, 1.0000000000000000]

可以看出,雖然前四項結果的量級不一樣,但都是無限接近於0,所以加了一個常數的softmax對原來的結果影響很小。

Loss function對數似然函數

機器學習裡面,對模型的訓練都是對Loss function進行優化,在分類問題中,我們一般使用最大似然估計(Maximum likelihood estimation)來構造損失函數。對於輸入的,其對應的類標籤為,我們的目標是找到這樣的使得最大。在二分類的問題中,我們有:



其中,是模型預測的概率值,是樣本對應的類標籤。

將問題泛化為更一般的情況,多分類問題:



由於連乘可能導致最終結果接近0的問題,一般對似然函數取對數的負數,變成最小化對數似然函數。

交叉熵

說交叉熵之前先介紹相對熵,相對熵又稱為KL散度(Kullback-Leibler Divergence),用來衡量兩個分布之間的距離,記為



這裡的熵。

假設有兩個分布,它們在給定樣本集上的交叉熵定義為:



從這裡可以看出,交叉熵和相對熵相差了,而當已知的時候,是個常數,所以交叉熵和相對熵在這裡是等價的,反映了分布之間的相似程度。關於熵與交叉熵等概念,可以參考該博客再做了解。

回到我們多分類的問題上,真實的類標籤可以看作是分布,對某個樣本屬於哪個類別可以用One-hot的編碼方式,是一個維度為的向量,比如在5個類別的分類中,[0, 1, 0, 0, 0]表示該樣本屬於第二個類,其概率值為1。我們把真實的類標籤分布記為,該分布中,屬於它的真實類別。同時,分類模型經過softmax函數之後,也是一個概率分布,因為,所以我們把模型的輸出的分布記為,它也是一個維度為的向量,如[0.1, 0.8, 0.05, 0.05, 0]。
對一個樣本來說,真實類標籤分布與模型預測的類標籤分布可以用交叉熵來表示:



可以看出,該等式於上面對數似然函數的形式一樣!

最終,對所有的樣本,我們有以下loss function:



其中是樣本屬於類別的概率,是模型對樣本預測為屬於類別的概率。

Loss function求導

對單個樣本來說,loss function對輸入的導數為:



上面對求導結果已經算出:

時:

時:

所以,將求導結果代入上式:

TensorFlow方法1:手動實現(不建議使用)

在TensorFlow中,已經有實現好softmax函數,所以我們可以自己構造交叉熵損失函數:

import tensorflow as tf
import input_data

x = tf.placeholder("float", shape=[None, 784])
label = tf.placeholder("float", shape=[None, 10])

w_fc1 = tf.Variable(tf.truncated_normal([784, 1024], stddev=0.1))
b_fc1 = tf.Variable(tf.constant(0.1, shape=[1024]))
h_fc1 = tf.matmul(x, w_fc1) + b_fc1

w_fc2 = tf.Variable(tf.truncated_normal([1024, 10], stddev=0.1))
b_fc2 = tf.Variable(tf.constant(0.1, shape=[10]))
y = tf.nn.softmax(tf.matmul(h_fc1, w_fc2) + b_fc2)

cross_entropy = -tf.reduce_sum(label * tf.log(y))

cross_entropy = -tf.reduce_sum(label * tf.log(y))是交叉熵的實現。先對所有的輸出用softmax進行轉換為概率值,再套用交叉熵的公式。

方法2:使用tf.nn.softmax_cross_entropy_with_logits(推薦使用)

import tensorflow as tf
import input_data

x = tf.placeholder("float", shape=[None, 784])
label = tf.placeholder("float", shape=[None, 10])

w_fc1 = tf.Variable(tf.truncated_normal([784, 1024], stddev=0.1))
b_fc1 = tf.Variable(tf.constant(0.1, shape=[1024]))
h_fc1 = tf.matmul(x, w_fc1) + b_fc1

w_fc2 = tf.Variable(tf.truncated_normal([1024, 10], stddev=0.1))
b_fc2 = tf.Variable(tf.constant(0.1, shape=[10]))
y = tf.matmul(h_fc1, w_fc2) + b_fc2

cross_entropy = -tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(labels=label, logits=y))

TensorFlow已經實現好函數,用來計算label和logits的softmax交叉熵。注意,該函數的參數logits在函數內會用softmax進行處理,所以傳進來時不能是softmax的輸出了。

區別

既然我們可以自己實現交叉熵的損失函數,為什麼TensorFlow還要再實現tf.nn.softmax_cross_entropy_with_logits函數呢?

這個問題在Stack overflow上已經有Google的人出來回答(傳送門),原話是:

If you want to do optimization to minimize the cross entropy, AND you’re softmaxing after your last layer, you should use tf.nn.softmax_cross_entropy_with_logits instead of doing it yourself, because it covers numerically unstable corner cases in the mathematically right way. Otherwise, you』ll end up hacking it by adding little epsilons here and there.

也就是說,方法1自己實現的方法會有在前文說的數值不穩定的問題,需要自己在softmax函數裡面加些trick。所以官方推薦如果使用的loss function是最小化交叉熵,並且,最後一層是要經過softmax函數處理,則最好使用tf.nn.softmax_cross_entropy_with_logits函數,因為它會幫你處理數值不穩定的問題。

總結

全文到此就要結束了,可以看到,前面介紹這麼多概念,其實只是為了解釋在具體實現時候要做什麼樣的選擇。可能會覺得有些小題大做,但對於NN這個黑盒子來說,我們現暫不能從理論上證明其有效性,那在工程實現上,我們不能再將它當作黑盒子來使用。

Reference

The Softmax function and its derivative Peter’s Notes CS231n Convolutional Neural Networks for Visual Recognition cs229.stanford.edu/note 交叉熵(Cross-Entropy) - rtygbwwwerr的專欄 - 博客頻道 - CSDN.NET difference between tensorflow tf.nn.softmax and tf.nn.softmax_cross_entropy_with_logits

文章同時發在CSDN上:blog.csdn.net/behamcheu#

重磅!程式設計師大白交流群-學術微信交流群已成立

額外贈送福利資源!邱錫鵬深度學習與神經網絡,pytorch官方中文教程,利用Python進行數據分析,機器學習學習筆記,pandas官方文檔中文版,effective java(中文版)等20項福利資源

獲取方式:進入群後點開群公告即可領取下載連結

昨晚拉人小助手出了問題,最近不能使用,請大家加入微信2群

注意:請大家添加時修改備註為 [學校/公司 + 姓名 + 方向]

例如 —— 哈工大+張三+對話系統。

號主,微商請自覺繞道。謝謝!


推薦閱讀

機器學習中需要了解的 5 種採樣方法

阿里中臺搞了3年,搞砸了?

如何畫出優秀的架構圖?

一次Linux系統被攻擊的分析過程

史上最爛的項目

關於程式設計師大白

程式設計師大白是一群哈工大,東北大學,西湖大學和上海交通大學的碩士博士運營維護的號,大家樂於分享高質量文章,喜歡總結知識,歡迎關注[程式設計師大白],大家一起學習進步!

相關焦點

  • Softmax函數與交叉熵
    TensorFlow方法1:手動實現(不建議使用)在TensorFlow中,已經有實現好softmax函數,所以我們可以自己構造交叉熵損失函數:import tensorflow as tfimport
  • Softmax和交叉熵的深度解析和Python實現
    當中,老師一定會告訴你在全連接層後面應該加上 Softmax 函數,如果正常情況下(不正常情況指的是類別超級多的時候)用交叉熵函數作為損失函數,你就一定可以得到一個讓你基本滿意的結果。▌交叉熵損失函數下面我們來看一下對模型優化真正起到作用的損失函數——交叉熵損失函數。交叉熵函數體現了模型輸出的概率分布和真實樣本的概率分布的相似程度。
  • 關於交叉熵損失
    這樣兩個分布的交叉熵H(p,q)也就等價於最小化這兩個分布的相對熵DKL(p∥q)。設p(x)是目標分布(訓練數據的分布),我們的目標的就讓訓練得到的分布q(x)儘可能的接近p(x),這時就可以最小化DKL(p∥q),等價於最小化交叉熵H(p,q) 。
  • 【softmax】詳解softmax函數以及相關求導過程
    一、softmax函數softmax用於多分類過程中,它將多個神經元的輸出,映射到(0,1)區間內,可以看成概率來理解,從而來進行多分類!假設我們有一個數組,V,Vi表示V中的第i個元素,那麼這個元素的softmax值就是
  • 【Softmax】乾貨 | 淺談Softmax函數
    引言Softmax函數幾乎是深度學習中的標配了,在人工神經網絡中,幾乎無處不可見softmax函數的身影。可以認為softmax是arg max操作的一種平滑近似。我將softmax的用途總結為兩種:分類:給定一系列類別,softmax可以給出某輸入被劃分到各個類別的概率分布。
  • 通俗詳解softmax函數及其求導過程
    1、softmax函數講解2、softmax函數求導過程詳解3、softmax函數求導為什麼如此方便softmax用於多分類過程中,它將多個神經元的輸出,映射到(0,1)區間內,可以看成概率來理解,從而來進行多分類!
  • 乾貨 | 淺談Softmax函數
    引言Softmax函數幾乎是深度學習中的標配了,在人工神經網絡中,幾乎無處不可見softmax函數的身影。可以認為softmax是arg max操作的一種平滑近似。我將softmax的用途總結為兩種:分類:給定一系列類別,softmax可以給出某輸入被劃分到各個類別的概率分布。
  • 乾貨 | 淺談 Softmax 函數
    引言Softmax函數幾乎是深度學習中的標配了,在人工神經網絡中,幾乎無處不可見softmax函數的身影。可以認為softmax是arg max操作的一種平滑近似。我將softmax的用途總結為兩種:分類:給定一系列類別,softmax可以給出某輸入被劃分到各個類別的概率分布。
  • Pytorch 中交叉熵 Loss 趣解
    什麼是交叉熵信息量引用百度百科中信息量的例子來看,在日常生活中,極少發生的事件一旦發生是容易引起人們關注的,而司空見慣的事不會引起注意,也就是說,極少見的事件所帶來的信息量多。如果用統計學的術語來描述,就是出現概率小的事件信息量多。因此,事件出現得概率越小,信息量愈大。即信息量的多少是與事件發生頻繁(即概率大小)成反比。
  • 從最優化的角度看待Softmax損失函數
    Softmax交叉熵損失函數應該是目前最常用的分類損失函數了,在大部分文章都是從概率角度來解釋的(請讀者自行搜索),本文將嘗試從最優化的角度來推導出Softmax交叉熵損失函數,希望能夠啟發出更多的研究思路。
  • 透徹講解~交叉熵代價函數
    交叉熵代價函數(Cross-entropy cost function)是用來衡量人工神經網絡(ANN)的預測值與實際值的一種方式。與二次代價函數相比,它能更有效地促進ANN的訓練。在介紹交叉熵代價函數之前,本文先簡要介紹二次代價函數,以及其存在的不足。
  • 從最優化的角度看待 Softmax 損失函數
    Softmax交叉熵損失函數應該是目前最常用的分類損失函數了,在大部分文章中,Softmax交叉熵損失函數都是從概率角度來解釋的,本周二極市就推送了一篇Softmax相關文章:一文道盡softmax loss及其變種。本文將嘗試從最優化的角度來推導出Softmax交叉熵損失函數,希望能夠啟發出更多的研究思路。
  • 機器學習小知識: 圖解熵、交叉熵和 KL-散度
    交叉熵是分類問題中最常用的損失函數之一。但是由於如今有大量容易上手的現成庫和框架,我們大多數人常常在沒有真正了解熵的核心概念的情況下,就可以熟練地解決問題。在本文中,讓我們研究一下熵這個概念背後的基本直覺,並將其與交叉熵、KL-散度相關聯。我們還將使用交叉熵作為損失函數,結合一個實例來看看它在分類問題中的應用。1什麼是熵?
  • 熵、交叉熵和KL散度的基本概念和交叉熵損失函數的通俗介紹
    但是,由於當今龐大的庫和框架的存在以及它們的易用性,我們中的大多數人常常在不了解熵的核心概念的情況下著手解決問題。所以,在這篇文章中,讓我們看看熵背後的基本概念,把它與交叉熵和KL散度聯繫起來。我們還將查看一個使用損失函數作為交叉熵的分類問題的示例。什麼是熵?
  • 簡單的交叉熵,你真的懂了嗎?
    引言        我們都知道損失函數有很多種:均方誤差(MSE)、SVM的合頁損失(hinge loss)、交叉熵(cross entropy)。這幾天看論文的時候產生了疑問:為啥損失函數很多用的都是交叉熵(cross entropy)?其背後深層的含義是什麼?如果換做均方誤差(MSE)會怎麼樣?下面我們一步步來揭開交叉熵的神秘面紗。2.
  • 你是否有過疑問:為啥損失函數很多用的都是交叉熵(cross entropy)?
    引言我們都知道損失函數有很多種:均方誤差(MSE)、SVM的合頁損失(hinge loss)、交叉熵(cross entropy)。這幾天看論文的時候產生了疑問:為啥損失函數很多用的都是交叉熵(cross entropy)?其背後深層的含義是什麼?如果換做均方誤差(MSE)會怎麼樣?下面我們一步步來揭開交叉熵的神秘面紗。2.
  • 簡單的交叉熵損失函數,你真的懂了嗎?
    說起交叉熵損失函數「Cross Entropy Loss」,腦海中立馬浮現出它的公式:我們已經對這個交叉熵函數非常熟悉,大多數情況下都是直接拿來使用就好。但是它是怎麼來的?為什麼它能表徵真實樣本標籤和預測概率之間的差值?上面的交叉熵函數是否有其它變種?也許很多朋友還不是很清楚!
  • Logistic和Softmax回歸實戰(附代碼)
    本文主要實戰Logistic回歸和softmax回歸在iris數據集上的應用,通過該文章,希望我們能一起掌握該方面的知識。歡迎文末查看下載關鍵字,公眾號回復即可免費下載實戰代碼。很遺憾,要使得上面的損失函數值最小並沒有一個閉式解能進行優化θ,但是由於該函數是凸的,所以我們可以很方便的用之前線性模型中所介紹的三種梯度下降法來進行尋優。
  • 機器學習最常用的損失函數之交叉熵
    假設X是一個離散型隨機變量,其取值集合為X,概率分布函數為p(x)=Pr(X=x),x∈X,我們定義事件X=x0的信息量為: I(x0)=−log(p(x0)),可以理解為,一個事件發生的概率越大,則它所攜帶的信息量就越小,而當p(x0)=1時,熵將等於0,也就是說該事件的發生不會導致任何信息量的增加。
  • 乾貨 | 對數線性模型之 Logistic 回歸、SoftMax 回歸和最大熵模型
    (sigmoid,softmax,entropy )將其映射到概率區間,使用對數損失構建目標函數。首先以概率的方式解釋了logistic回歸為什麼使用sigmoid函數和對數損失,然後將二分類擴展到多分類,導出sigmoid函數的高維形式softmax函數對應softmax回歸,最後最大熵模型可以看作是softmax回歸的離散型版本,logistic回歸和softmax回歸處理數值型分類問題,最大熵模型對應處理離散型分類問題。