深度神經網路(DNN)損失函式和啟用函式的選擇

劉建平Pinard發表於2017-02-24

    在深度神經網路(DNN)反向傳播演算法(BP)中,我們對DNN的前向反向傳播演算法的使用做了總結。裡面使用的損失函式是均方差,而啟用函式是Sigmoid。實際上DNN可以使用的損失函式和啟用函式不少。這些損失函式和啟用函式如何選擇呢?下面我們就對DNN損失函式和啟用函式的選擇做一個總結。

1. 均方差損失函式+Sigmoid啟用函式的問題

    在講反向傳播演算法時,我們用均方差損失函式和Sigmoid啟用函式做了例項,首先我們就來看看均方差+Sigmoid的組合有什麼問題。

    首先我們回顧下Sigmoid啟用函式的表示式為:$$\sigma(z) = \frac{1}{1+e^{-z}}$$

    $\sigma(z)$的函式影象如下:

    從圖上可以看出,對於Sigmoid,當$z$的取值越來越大後,函式曲線變得越來越平緩,意味著此時的導數$\sigma ^{'}(z)$也越來越小。同樣的,當$z$的取值越來越小時,也有這個問題。僅僅在$z$取值為0附近時,導數$\sigma ^{'}(z)$的取值較大。

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

2. 使用交叉熵損失函式+Sigmoid啟用函式改進DNN演算法收斂速度

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

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

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

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

$$ \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 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}}$$

    如果不巧我們的樣本導致每一層$\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

 

相關文章