深度神經網絡(DNN)損失函數和激活函數的選擇

    在深度神經網絡(DNN)反向傳播算法(BP)中,咱們對DNN的前向反向傳播算法的使用作了總結。裏面使用的損失函數是均方差,而激活函數是Sigmoid。實際上DNN可使用的損失函數和激活函數很多。這些損失函數和激活函數如何選擇呢?下面咱們就對DNN損失函數和激活函數的選擇作一個總結。html

1. 均方差損失函數+Sigmoid激活函數的問題

    在講反向傳播算法時,咱們用均方差損失函數和Sigmoid激活函數作了實例,首先咱們就來看看均方差+Sigmoid的組合有什麼問題。算法

    首先咱們回顧下Sigmoid激活函數的表達式爲:$$\sigma(z) = \frac{1}{1+e^{-z}}$$網絡

    $\sigma(z)$的函數圖像以下:函數

    從圖上能夠看出,對於Sigmoid,當$z$的取值愈來愈大後,函數曲線變得愈來愈平緩,意味着此時的導數$\sigma ^{'}(z)$也愈來愈小。一樣的,當$z$的取值愈來愈小時,也有這個問題。僅僅在$z$取值爲0附近時,導數$\sigma ^{'}(z)$的取值較大。post

    在上篇講的均方差+Sigmoid的反向傳播算法中,每一層向前遞推都要乘以$\sigma ^{'}(z)$,獲得梯度變化值。Sigmoid的這個曲線意味着在大多數時候,咱們的梯度變化值很小,致使咱們的$W,b$更新到極值的速度較慢,也就是咱們的算法收斂速度較慢。那麼有什麼什麼辦法能夠改進呢?學習

2. 使用交叉熵損失函數+Sigmoid激活函數改進DNN算法收斂速度

    上一節咱們講到Sigmoid的函數特性致使反向傳播算法收斂速度慢的問題,那麼如何改進呢?換掉Sigmoid?這固然是一種選擇。另外一種常見的選擇是用交叉熵損失函數來代替均方差損失函數。3d

    咱們來看看二分類時每一個樣本的交叉熵損失函數的形式:$$J(W,b,a,y) = - [y lna + (1-y) ln(1 -a)]$$htm

    這個形式其實很熟悉,在邏輯迴歸原理小結中其實咱們就用到了相似的形式,只是當時咱們是用最大似然估計推導出來的,而這個損失函數的學名叫交叉熵。blog

    使用了交叉熵損失函數,就能解決Sigmoid函數導數變化大多數時候反向傳播算法慢的問題嗎?咱們來看看當使用交叉熵時,咱們輸出層$\delta^L$的梯度狀況。get

$$ \begin{align} \delta^L  & = \frac{\partial J(W,b,a^L,y)}{\partial z^L} \\& = -y\frac{1}{a^L}(a^L)(1-a^L) + (1-y) \frac{1}{1-a^L}(a^L)(1-a^L) \\& = -y(1-a^L) + (1-y)a^L \\& = a^L-y \end{align}$$

    可見此時咱們的$\delta^l$梯度表達式裏面已經沒有了$\sigma ^{'}(z)$,做爲一個特例,回顧一下咱們上一節均方差損失函數時在$\delta^L$梯度,$$\frac{\partial J(W,b,x,y)}{\partial z^L} = (a^L-y) \odot \sigma^{'}(z)$$

    對比二者在第L層的$\delta^L$梯度表達式,就能夠看出,使用交叉熵,獲得的的$\delta^l$梯度表達式沒有了$\sigma^{'}(z)$,梯度爲預測值和真實值的差距,這樣求得的$W^l,b^l$的地圖也不包含$\sigma^{'}(z)$,所以避免了反向傳播收斂速度慢的問題。

    一般狀況下,若是咱們使用了sigmoid激活函數,交叉熵損失函數確定比均方差損失函數好用。

3. 使用對數似然損失函數和softmax激活函數進行DNN分類輸出

    在前面咱們講的全部DNN相關知識中,咱們都假設輸出是連續可導的值。可是若是是分類問題,那麼輸出是一個個的類別,那咱們怎麼用DNN來解決這個問題呢?

    好比假設咱們有一個三個類別的分類問題,這樣咱們的DNN輸出層應該有三個神經元,假設第一個神經元對應類別一,第二個對應類別二,第三個對應類別三,這樣咱們指望的輸出應該是(1,0,0),(0,1,0)和(0,0,1)這三種。即樣本真實類別對應的神經元輸出應該無限接近或者等於1,而非改樣本真實輸出對應的神經元的輸出應該無限接近或者等於0。或者說,咱們但願輸出層的神經元對應的輸出是若干個機率值,這若干個機率值即咱們DNN模型對於輸入值對於各種別的輸出預測,同時爲知足機率模型,這若干個機率值之和應該等於1。

    DNN分類模型要求是輸出層神經元輸出的值在0到1之間,同時全部輸出值之和爲1。很明顯,現有的普通DNN是沒法知足這個要求的。可是咱們只須要對現有的全鏈接DNN稍做改良,便可用於解決分類問題。在現有的DNN模型中,咱們能夠將輸出層第i個神經元的激活函數定義爲以下形式:$$a_i^L = \frac{e^{z_i^L}}{\sum\limits_{j=1}^{n_L}e^{z_j^L}}$$

    其中,$n_L$是輸出層第L層的神經元個數,或者說咱們的分類問題的類別數。

    很容易看出,全部的$a_i^L$都是在(0,1) 之間的數字,而$\sum\limits_{j=1}^{n_L}e^{z_j^L}$做爲歸一化因子保證了全部的$a_i^L$之和爲1。

    這個方法很簡潔漂亮,僅僅只須要將輸出層的激活函數從Sigmoid之類的函數轉變爲上式的激活函數便可。上式這個激活函數就是咱們的softmax激活函數。它在分類問題中有普遍的應用。將DNN用於分類問題,在輸出層用softmax激活函數也是最多見的了。

    下面這個例子清晰的描述了softmax激活函數在前向傳播算法時的使用。假設咱們的輸出層爲三個神經元,而未激活的輸出爲3,1和-3,咱們求出各自的指數表達式爲:20,2.7和0.05,咱們的歸一化因子即爲22.75,這樣咱們就求出了三個類別的機率輸出分佈爲0.88,0.12和0。

    從上面能夠看出,將softmax用於前向傳播算法是也很簡單的。那麼在反向傳播算法時還簡單嗎?反向傳播的梯度好計算嗎?答案是Yes!

    對於用於分類的softmax激活函數,對應的損失函數通常都是用對數似然函數,即:$$J(W,b,a^L,y) = - \sum\limits_ky_klna_k^L$$

    其中$y_k$的取值爲0或者1,若是某一訓練樣本的輸出爲第i類。則$y_i=1$,其他的$j \neq i$都有$y_j=0$。因爲每一個樣本只屬於一個類別,因此這個對數似然函數能夠簡化爲:$$J(W,b,a^L,y) = -lna_i^L$$

    其中$i$即爲訓練樣本真實的類別序號。

    可見損失函數只和真實類別對應的輸出有關,這樣假設真實類別是第i類,則其餘不屬於第i類序號對應的神經元的梯度導數直接爲0。對於真實類別第i類,他對應的第j個w連接$w_{ij}^L$對應的梯度計算爲:$$ \begin{align} \frac{\partial J(W,b,a^L,y)}{\partial w_{ij}^L}& = \frac{\partial J(W,b,a^L,y)}{\partial a_i^L}\frac{\partial a_i^L}{\partial z_i^L}\frac{\partial z_i^L}{\partial w_{ij}^L} \\& = -\frac{1}{a_i^L}\frac{(e^{z_i^L})\sum\limits_{j=1}^{n_L}e^{z_j^L}-e^{z_i^L}e^{z_i^L}}{(\sum\limits_{j=1}^{n_L}e^{z_j^L)^2}} a_j^{L-1} \\& = -\frac{1}{a_i^L} (\frac{e^{z_i^L}}{\sum\limits_{j=1}^{n_L}e^{z_j^L}}-\frac{e^{z_i^L}}{\sum\limits_{j=1}^{n_L}e^{z_j^L}}\frac{e^{z_i^L}}{\sum\limits_{j=1}^{n_L}e^{z_j^L}}) a_j^{L-1} \\& = -\frac{1}{a_i^L} a_i^L(1- a_i^L) a_j^{L-1} \\& = (a_i^L -1)  a_j^{L-1} \end{align}$$

    一樣的能夠獲得$b_i^L$的梯度表達式爲:$$\frac{\partial J(W,b,a^L,y)}{\partial b_i^L} = a_i^L -1$$

    可見,梯度計算也很簡潔,也沒有第一節說的訓練速度慢的問題。舉個例子,假如咱們對於第2類的訓練樣本,經過前向算法計算的未激活輸出爲(1,5,3),則咱們獲得softmax激活後的機率輸出爲:(0.015,0.866,0.117)。因爲咱們的類別是第二類,則反向傳播的梯度應該爲:(0.015,0.866-1,0.117)。是否是很簡單呢?

    當softmax輸出層的反向傳播計算完之後,後面的普通DNN層的反向傳播計算和以前講的普通DNN沒有區別。 

4. 梯度爆炸梯度消失與ReLU激活函數

    學習DNN,你們必定據說過梯度爆炸和梯度消失兩個詞。尤爲是梯度消失,是限制DNN與深度學習的一個關鍵障礙,目前也沒有徹底攻克。

    什麼是梯度爆炸和梯度消失呢?從理論上說均可以寫一篇論文出來。不過簡單理解,就是在反向傳播的算法過程當中,因爲咱們使用了是矩陣求導的鏈式法則,有一大串連乘,若是連乘的數字在每層都是小於1的,則梯度越往前乘越小,致使梯度消失,而若是連乘的數字在每層都是大於1的,則梯度越往前乘越大,致使梯度爆炸。

    好比咱們在前一篇反向傳播算法裏面講到了$\delta$的計算,能夠表示爲:$$\delta^l =\frac{\partial J(W,b,x,y)}{\partial z^l} = (\frac{\partial z^L}{\partial z^{L-1}}\frac{\partial z^{L-1}}{\partial z^{L-2}}...\frac{\partial z^{l+1}}{\partial z^{l}})^T\frac{\partial J(W,b,x,y)}{\partial z^L}$$

    若是不巧咱們的樣本致使每一層$\frac{\partial z^{l+1}}{\partial z^{l}}$的都小於1,則隨着反向傳播算法的進行,咱們的$\delta^l$會隨着層數愈來愈小,甚至接近越0,致使梯度幾乎消失,進而致使前面的隱藏層的$W,b$參數隨着迭代的進行,幾乎沒有大的改變,更談不上收斂了。這個問題目前沒有完美的解決辦法。

    而對於梯度爆炸,則通常能夠經過調整咱們DNN模型中的初始化參數得以解決。

    對於沒法完美解決的梯度消失問題,目前有不少研究,一個可能部分解決梯度消失問題的辦法是使用ReLU(Rectified Linear Unit)激活函數,ReLU在卷積神經網絡CNN中獲得了普遍的應用,在CNN中梯度消失彷佛再也不是問題。那麼它是什麼樣子呢?其實很簡單,比咱們前面提到的全部激活函數都簡單,表達式爲:$$\sigma(z) = max(0,z)$$

    也就是說大於等於0則不變,小於0則激活後爲0。就這麼一玩意就能夠解決梯度消失?至少部分是的。具體的緣由如今其實也沒有從理論上得以證實。這裏我也就很少說了。

5. DNN其餘激活函數

    除了上面提到了激活函數,DNN經常使用的激活函數還有:

    1) tanh:這個是sigmoid的變種,表達式爲:$$tanh(z) = \frac{e^z-e^{-z}}{e^z+e^{-z}}$$

    tanh激活函數和sigmoid激活函數的關係爲:$$tanh(z) = 2sigmoid(2z)-1$$

    tanh和sigmoid對比主要的特色是它的輸出落在了[-1,1],這樣輸出能夠進行標準化。同時tanh的曲線在較大時變得平坦的幅度沒有sigmoid那麼大,這樣求梯度變化值有一些優點。固然,要說tanh必定比sigmoid好倒不必定,仍是要具體問題具體分析。

    2) softplus:這個其實就是sigmoid函數的原函數,表達式爲:$$softplus(z) = log(1+e^z)$$

    它的導數就是sigmoid函數。softplus的函數圖像和ReLU有些相似。它出現的比ReLU早,能夠視爲ReLU的鼻祖。

    3)PReLU:從名字就能夠看出它是ReLU的變種,特色是若是未激活值小於0,不是簡單粗暴的直接變爲0,而是進行必定幅度的縮小。以下圖。固然,因爲ReLU的成功,有不少的跟風者,有其餘各類變種ReLU,這裏就很少提了。

6. DNN損失函數和激活函數小結

    上面咱們對DNN損失函數和激活函數作了詳細的討論,重要的點有:1)若是使用sigmoid激活函數,則交叉熵損失函數通常確定比均方差損失函數好。2)若是是DNN用於分類,則通常在輸出層使用softmax激活函數和對數似然損失函數。3)ReLU激活函數對梯度消失問題有必定程度的解決,尤爲是在CNN模型中。

    下一篇咱們討論下DNN模型的正則化問題。

 

(歡迎轉載,轉載請註明出處。歡迎溝通交流: liujianping-ok@163.com) 

參考資料:

1) Neural Networks and Deep Learning by By Michael Nielsen

2) Deep Learning, book by Ian Goodfellow, Yoshua Bengio, and Aaron Courville

3) UFLDL Tutorial

相關文章
相關標籤/搜索