詳解Softmax函數

  • 2020 年 11 月 3 日
  • AI

前言

提到二分類首先想到的可能就是邏輯回歸演算法。邏輯回歸演算法是在各個領域中應用比較廣泛的機器學習演算法。邏輯回歸演算法本身並不難,最關鍵的步驟就是將線性模型輸出的實數域映射到[0, 1]表示概率分布的有效實數空間,其中Sigmoid函數剛好具有這樣的功能。

▲Sigmoid函數

例如使用邏輯回歸演算法預測患者是否有惡性腫瘤的二分類問題中,輸出層可以只設置一個節點,表示某個事件A發生的概率為,其中x為輸入。對於患者是否有惡性腫瘤的二分類問題中,A事件可以表示為惡性腫瘤或表示為良性腫瘤(表示為良性腫瘤或惡性腫瘤),x為患者的一些特徵指標。

▲擁有單個輸出節點的二分類

對於二分類問題,除了可以使用單個輸出節點表示事件A發生的概率外,還可以分別預測,並滿足約束: 。其中表示事件A的對立事件。

▲擁有兩個輸出節點的二分類

兩個節點輸出的二分類相比於單節點輸出的二分類多了一個的約束條件,這個約束條件將輸出節點的輸出值變成一個概率分布,簡單來說各個輸出節點的輸出值範圍映射到[0, 1],並且約束各個輸出節點的輸出值的和為1。當然可以將輸出為兩個節點的二分類推廣成擁有n個輸出節點的n分類問題。

有沒有將各個輸出節點的輸出值範圍映射到[0, 1],並且約束各個輸出節點的輸出值的和為1的函數呢?

當然,這個函數就是Softmax函數。

a
   什 么 是 Softmax 函 數?

Softmax從字面上來說,可以分成soft和max兩個部分。max故名思議就是最大值的意思。Softmax的核心在於soft,而soft有軟的含義,與之相對的是hard硬。很多場景中需要我們找出數組所有元素中值最大的元素,實質上都是求的hardmax。下面使用Numpy模組以及TensorFlow深度學習框架實現hardmax。

使用Numpy模組實現hardmax:

使用TensorFlow深度學習框架實現hardmax:

通過上面的例子可以看出hardmax最大的特點就是只選出其中一個最大的值,即非黑即白。但是往往在實際中這種方式是不合情理的,比如對於文本分類來說,一篇文章或多或少包含著各種主題資訊,我們更期望得到文章對於每個可能的文本類別的概率值(置信度),可以簡單理解成屬於對應類別的可信度。所以此時用到了soft的概念,Softmax的含義就在於不再唯一的確定某一個最大值,而是為每個輸出分類的結果都賦予一個概率值,表示屬於每個類別的可能性。

下面給出Softmax函數的定義(以第i個節點輸出為例):

,其中為第i個節點的輸出值,C為輸出節點的個數,即分類的類別個數。通過Softmax函數就可以將多分類的輸出值轉換為範圍在[0, 1]和為1的概率分布。

引入指數函數對於Softmax函數是把雙刃劍,即得到了優點也暴露出了缺點:

  • 引入指數形式的優點

▲y=e^{x}函數影像

指數函數曲線呈現遞增趨勢,最重要的是斜率逐漸增大,也就是說在x軸上一個很小的變化,可以導致y軸上很大的變化。這種函數曲線能夠將輸出的數值拉開距離。假設擁有三個輸出節點的輸出值為  為[2, 3, 5]。首先嘗試不使用指數函數  ,接下來使用指數函數的Softmax函數計算。

tf.Tensor([0.2 0.3 0.5], shape=(3,), dtype=float32)tf.Tensor([0.04201007 0.11419519 0.8437947 ], shape=(3,), dtype=float32)

兩種計算方式的輸出結果分別是:

  • tf.Tensor([0.2 0.3 0.5], shape=(3,), dtype=float32)
  • tf.Tensor([0.04201007 0.11419519 0.8437947],shape=(3,), dtype=float32)
結果還是挺明顯的,經過使用指數形式的Softmax函數能夠將差距大的數值距離拉的更大。
在深度學習中通常使用反向傳播求解梯度進而使用梯度下降進行參數更新的過程,而指數函數在求導的時候比較方便。比如
  • 引入指數形式的缺點
指數函數的曲線斜率逐漸增大雖然能夠將輸出值拉開距離,但是也帶來了缺點,當  值非常大的話,計算得到的數值也會變的非常大,數值可能會溢出。

當然針對數值溢出有其對應的優化方法,將每一個輸出值減去輸出值中最大的值。
 

這裡需要注意一下,當使用Softmax函數作為輸出節點的激活函數的時候,一般使用交叉熵作為損失函數。由於Softmax函數的數值計算過程中,很容易因為輸出節點的輸出值比較大而發生數值溢出的現象,在計算交叉熵的時候也可能會出現數值溢出的問題。為了數值計算的穩定性,TensorFlow提供了一個統一的介面,將Softmax與交叉熵損失函數同時實現,同時也處理了數值不穩定的異常,使用TensorFlow深度學習框架的時候,一般推薦使用這個統一的介面,避免分開使用Softmax函數與交叉熵損失函數。

TensorFlow提供的統一函數式介面為:

其中y_true代表了One-hot編碼後的真實標籤,y_pred表示網路的實際預測值:

  • 當from_logits設置為True時,y_pred表示未經Softmax函數的輸出值;
  • 當from_logits設置為False時,y_pred表示為經過Softmax函數後的輸出值;

為了在計算Softmax函數時候數值的穩定,一般將from_logits設置為True,此時tf.keras.losses.categorical_crossentropy將在內部進行Softmax的計算,所以在不需要在輸出節點上添加Softmax激活函數。

雖然上面兩個過程結果差不多,但是當遇到一些不正常的數值時,將from_logits設置為True時TensorFlow會啟用一些優化機制。因此推薦使用將from_logits參數設置為True的統一介面。

b
   Softmax 函 數 求 導

單個輸出節點的二分類問題一般在輸出節點上使用Sigmoid函數,擁有兩個及其以上的輸出節點的二分類或者多分類問題一般在輸出節點上使用Softmax函數。其他層建議使用的激活函數可以參考深度學習中常用激活函數的詳細總結

現在可以構建比較複雜的神經網路模型,最重要的原因之一得益於反向傳播演算法。反向傳播演算法從輸出端也就是損失函數開始向輸入端基於鏈式法則計算梯度,然後通過計算得到的梯度,應用梯度下降演算法迭代更新待優化參數。

由於反向傳播計算梯度基於鏈式法則,因此下面為了更加清晰,首先推導一下Softmax函數的導數。作為最後一層的激活函數,求導本身並不複雜,但是需要注意需要分成兩種情況來考慮。

▲來源李宏毅老師PPT

為了方便說明,先來簡單看一個小例子。

▲簡單計算圖

可以將梯度看成是高維的導數,而導數簡單來說就是切線的斜率,也就是y軸的改變數與x軸的改變數的比值。通過上面的計算圖可以得知,的改變數都會影響的值,因此需要讓分別求導,很明顯此時計算出來的兩個偏導數結果不同,

繪製擁有三個輸出節點的Softmax函數的計算圖:

▲擁有三個輸出節點的Softmax函數的計算圖

回顧Softmax函數的表達式:
,其中i表示輸出節點的編號。
影響的有與之相連的,因此需要分別求出 。此時輸出值,很明顯結果不同,而只需換相應索引號即可。因此在對Softmax函數求導的時候,需要分兩種情況考慮。即對第i個輸出節點,分為對求導以及其它求導。

  • 時,類似前面介紹的 。Softmax函數的偏導數可以展開為:
上面使用了函數相除的導數運算,由於是對求導數,由於此時,因此 的導數還是本身,對求導結果只保留因此上面求導的結果為:
提取公共項  :
拆分成兩個部分:
為了方便,將Softmax函數表達式 表示為 ,結果為,由於此時,因此最終結果為 

  • 時,類似前面介紹的Softmax函數的偏導數 可以展開為:
上面使用了函數相除的導數運算,由於是對求導數,由於此時,因此 相當於常數,常數的導數為0,對求導同樣只保留因此上面求導的結果為:
分解兩項相乘:
為了方便,將Softmax函數表達式表示為 ,結果為,由於此時,因此最終結果為
對於Softmax函數的梯度推導依然使用的是導數的基本運算,並不複雜。最關鍵的是要對 以及  兩種情況分別討論。偏導數的最終表達式如下:

首發:

1. 觸摸壹縷陽光~知乎
參考:
1. 三分鐘帶你對 Softmax 劃重點
2. 《TensorFlow深度學習》
3. 觸摸壹縷陽光:[L4]使用LSTM實現語言模型-softmax與交叉熵