1. 程式人生 > >深度學習:欠擬合問題的幾種解決方案

深度學習:欠擬合問題的幾種解決方案

我最近做深度學習在連續中文語音識別方向的應用的時候,根據一些論文和網上一些公開程式碼和模型結構,設計了一個神經網路的模型。但是在訓練的時候,就首先遇到了很讓人頭疼的欠擬合問題。神經網路欠擬合的特徵是,訓練了很長時間,但是在訓練集上,loss值仍然很大甚至與初始值沒有太大區別,而且精確度也很低,幾乎接近於0,在測試集上亦如此。且先不管模型結構配置的優劣,就欠擬合問題來說,需要從如下方面來著手。

就我目前所遇到的來說,神經網路的欠擬合大致分為兩種情況,一種是神經網路的擬合能力不足,一種是網路配置的問題。先說說欠擬合的特徵吧,即如何判斷當前是不是欠擬合,以及到底是上述我說的哪一種情況。

我們先用兩張圖來說明一下吧:

如果我們訓練神經網路的時候,在訓練集上得到了這樣的loss:

以及這樣的Accurancy:

那麼,欠擬合基本上是沒得跑了。因為,一開始就有一個較大的loss,以及幾乎為0的精度,然後不論怎麼訓練,比如訓練了一整天,loss遲遲不下降,精度遲遲不上升,即神經網路總是不能很好地擬合訓練資料,那麼這就是欠擬合了。

判斷神經網路的擬合能力是否足夠

這時候,有一個小技巧,那就是,讓神經網路在每次訓練時,只迭代同樣的資料,甚至每一個batch裡面也是完全相同一模一樣的資料,再來看看loss值和accurancy值的變化。如果發現,這時候,神經網路的Loss開始下降,accurancy也開始上升了,並且在訓練了一段時間後神經網路能夠正確地計算出所訓練樣本經過神經網路的輸出值了,那麼這種情況屬於神經網路擬合能力不足

。對於大量的資料樣本,神經網路無法去擬合全部資料,只能擬合大量樣本的整體特徵,或者少數樣本的具體特徵。此時,需要做的很簡單,只需要增加深度,也就是增加神經網路的層數就可以了。也可以增加神經網路的寬度,將每一層的神經單元數量增加,但是同等情況下,效果明顯不如增加層數,而且要想達到較好的效果,需要增加的神經元數遠超過增加一層增加的神經元數。深度深比寬度寬的模型更優這一點,是大家普遍認同的。

那麼如果loss和accurancy仍然如此呢?不論怎麼增加神經網路的層數,用哪怕只有一條資料去訓練擬合,神經網路就是“巋然不動”,loss的值“屹立不倒”,那麼這就與神經網路的擬合能力無關了,就要考慮一下其他的因素了。這也是我遇到的那個問題的根源所在。

尋找最優的權重初始化方案

首先要說的就是權重的初始化方案。神經網路在訓練之前,我們需要給其賦予一個初值,但是如何選擇這個初始值,這是個問題。神經網路有大概如下的幾種初始化方案:

  • 全零初始化 Zeros
  • 全1初始化 Ones
  • 初始化為固定值value  Constant
  • 隨機正態分佈初始化 RandomNormal
  • 隨機均勻分佈初始化 RandomUniform
  • 截尾高斯分佈初始化 TruncatedNormal
  • VarianceScaling
  • 用隨機正交矩陣初始化Orthogonal
  • 使用單位矩陣初始化 Identiy
  • LeCun均勻分佈初始化方法 lecun_uniform
  • LeCun正態分佈初始化方法 lecun_normal
  • Glorot正態分佈初始化方法 glorot_normal
  • Glorot均勻分佈初始化 glorot_uniform
  • He正態分佈初始化 he_normal
  • LeCun均勻分佈初始化 he_uniform

參考資料:

https://keras-cn.readthedocs.io/en/latest/other/initializations/

https://keras.io/initializers/

具體的初始化方案的原理本文不再贅述,這麼多初始化方案,其實按照大類來分,主要就三種:均勻分佈、正太分佈和相同固定值。

全0的初始化,一般只會被用於邏輯斯蒂迴歸之類的這種二分類問題上,最多是淺層的神經網路上。全為1或者某個其他相同的值的方案則很少見。因為這種初始化方案,會使得網路處於對稱狀態,導致的結果就是,每個神經元都具有相同的輸出,然後在反向傳播計算梯度時,會得到一個同一個梯度值,並且進行著同樣的引數更新,這是我們不希望看到的。

在我用的基於tensorflow的神經網路框架keras中,神經網路預設初始化全部被初始化為了glorot_uniform,也就是一種均值為0,以0為中心的對稱區間均勻分佈的隨機數。在我的模型上,這種接近於0的均勻分佈會導致什麼問題呢?那就是梯度的消失,使得訓練時的loss難以收斂,就出現了上面那兩張圖的情況。這種初始化方案,訓練速度不僅僅慢,而且結果也不好。可以考慮一些其他的方案試一試,比如he_normal和xavier normal等。所以,初始化就跟黑科技一樣,用對了,超引數都不用調,沒用對,跑出來的結果跟模型有bug一樣,不忍直視。

使用適當的啟用函式

不僅僅是初始化,在神經網路的啟用函式方面的選取,也不是隨意的。比如,卷積神經網路中,卷積層的輸出,需要使用的啟用函式一般為ReLu,迴圈神經網路中的迴圈層使用的啟用函式一般為tanh,或者ReLu,全連線層一般也是多用ReLu來啟用,只有在神經網路的輸出層,使用全連線層來分類的情況下,才會使用softmax這種啟用函式。而在各種機器學習入門教程裡面最常講到的sigmoid函式,想都不要想它,它已經不適用於深度學習了,哪怕是作為其改進版的softmax函式,也僅僅是在輸出層才使用。

選擇合適的優化器和學習速率

神經網路訓練的優化器也是需要考慮的一大因素。神經網路的優化器其實有很多種,每種都有其不同的特點,我們最耳熟能詳的就是梯度下降法,對應著有批量梯度下降,隨機梯度下降。這種優化方法其實不賴,尤其是在神經網路即將最終收斂的時候,使用一個合適的學習速率使得其最終下降到儘可能低的點上。但是隨機梯度下降有著明顯的缺點,尤其是跟Momentum、Adagrad、Adadelta等其他優化器對比之後。

而且,這裡我最推薦Adadelta,在一開始的效果很顯著,只有在最終收斂之前可能不如SGD,可以選擇這時候再換成SGD就行了。而且Adadelta不需要太多關注學習率,因為其訓練的原理已經不怎麼跟學習率有關了。

不過,如果是SGD的話,在排除了以上情況之後,當神經網路仍欠擬合或者loss不再下降時,可以將學習率調小一些試試。

一般來說,經過以上的組合拳式的優化調參,欠擬合問題基本上都能夠得到解決,哪怕最後仍然準確率不高,但肯定是擬合了。欠擬合問題解決之後,接下來要解決的就是過擬合問題了。

我最近做深度學習在連續中文語音識別方向的應用的時候,根據一些論文和網上一些公開程式碼和模型結構,設計了一個神經網路的模型。但是在訓練的時候,就首先遇到了很讓人頭疼的欠擬合問題。神經網路欠擬合的特徵是,訓練了很長時間,但是在訓練集上,loss值仍然很大甚至與初始值沒有太大區別,而且精確度也很低,幾乎接近於0,在測試集上亦如此。且先不管模型結構配置的優劣,就欠擬合問題來說,需要從如下方面來著手。

就我目前所遇到的來說,神經網路的欠擬合大致分為兩種情況,一種是神經網路的擬合能力不足,一種是網路配置的問題。先說說欠擬合的特徵吧,即如何判斷當前是不是欠擬合,以及到底是上述我說的哪一種情況。

我們先用兩張圖來說明一下吧:

如果我們訓練神經網路的時候,在訓練集上得到了這樣的loss:

以及這樣的Accurancy:

那麼,欠擬合基本上是沒得跑了。因為,一開始就有一個較大的loss,以及幾乎為0的精度,然後不論怎麼訓練,比如訓練了一整天,loss遲遲不下降,精度遲遲不上升,即神經網路總是不能很好地擬合訓練資料,那麼這就是欠擬合了。

判斷神經網路的擬合能力是否足夠

這時候,有一個小技巧,那就是,讓神經網路在每次訓練時,只迭代同樣的資料,甚至每一個batch裡面也是完全相同一模一樣的資料,再來看看loss值和accurancy值的變化。如果發現,這時候,神經網路的Loss開始下降,accurancy也開始上升了,並且在訓練了一段時間後神經網路能夠正確地計算出所訓練樣本經過神經網路的輸出值了,那麼這種情況屬於神經網路擬合能力不足。對於大量的資料樣本,神經網路無法去擬合全部資料,只能擬合大量樣本的整體特徵,或者少數樣本的具體特徵。此時,需要做的很簡單,只需要增加深度,也就是增加神經網路的層數就可以了。也可以增加神經網路的寬度,將每一層的神經單元數量增加,但是同等情況下,效果明顯不如增加層數,而且要想達到較好的效果,需要增加的神經元數遠超過增加一層增加的神經元數。深度深比寬度寬的模型更優這一點,是大家普遍認同的。

那麼如果loss和accurancy仍然如此呢?不論怎麼增加神經網路的層數,用哪怕只有一條資料去訓練擬合,神經網路就是“巋然不動”,loss的值“屹立不倒”,那麼這就與神經網路的擬合能力無關了,就要考慮一下其他的因素了。這也是我遇到的那個問題的根源所在。

尋找最優的權重初始化方案

首先要說的就是權重的初始化方案。神經網路在訓練之前,我們需要給其賦予一個初值,但是如何選擇這個初始值,這是個問題。神經網路有大概如下的幾種初始化方案:

  • 全零初始化 Zeros
  • 全1初始化 Ones
  • 初始化為固定值value  Constant
  • 隨機正態分佈初始化 RandomNormal
  • 隨機均勻分佈初始化 RandomUniform
  • 截尾高斯分佈初始化 TruncatedNormal
  • VarianceScaling
  • 用隨機正交矩陣初始化Orthogonal
  • 使用單位矩陣初始化 Identiy
  • LeCun均勻分佈初始化方法 lecun_uniform
  • LeCun正態分佈初始化方法 lecun_normal
  • Glorot正態分佈初始化方法 glorot_normal
  • Glorot均勻分佈初始化 glorot_uniform
  • He正態分佈初始化 he_normal
  • LeCun均勻分佈初始化 he_uniform

參考資料:

https://keras-cn.readthedocs.io/en/latest/other/initializations/

https://keras.io/initializers/

具體的初始化方案的原理本文不再贅述,這麼多初始化方案,其實按照大類來分,主要就三種:均勻分佈、正太分佈和相同固定值。

全0的初始化,一般只會被用於邏輯斯蒂迴歸之類的這種二分類問題上,最多是淺層的神經網路上。全為1或者某個其他相同的值的方案則很少見。因為這種初始化方案,會使得網路處於對稱狀態,導致的結果就是,每個神經元都具有相同的輸出,然後在反向傳播計算梯度時,會得到一個同一個梯度值,並且進行著同樣的引數更新,這是我們不希望看到的。

在我用的基於tensorflow的神經網路框架keras中,神經網路預設初始化全部被初始化為了glorot_uniform,也就是一種均值為0,以0為中心的對稱區間均勻分佈的隨機數。在我的模型上,這種接近於0的均勻分佈會導致什麼問題呢?那就是梯度的消失,使得訓練時的loss難以收斂,就出現了上面那兩張圖的情況。這種初始化方案,訓練速度不僅僅慢,而且結果也不好。可以考慮一些其他的方案試一試,比如he_normal和xavier normal等。所以,初始化就跟黑科技一樣,用對了,超引數都不用調,沒用對,跑出來的結果跟模型有bug一樣,不忍直視。

使用適當的啟用函式

不僅僅是初始化,在神經網路的啟用函式方面的選取,也不是隨意的。比如,卷積神經網路中,卷積層的輸出,需要使用的啟用函式一般為ReLu,迴圈神經網路中的迴圈層使用的啟用函式一般為tanh,或者ReLu,全連線層一般也是多用ReLu來啟用,只有在神經網路的輸出層,使用全連線層來分類的情況下,才會使用softmax這種啟用函式。而在各種機器學習入門教程裡面最常講到的sigmoid函式,想都不要想它,它已經不適用於深度學習了,哪怕是作為其改進版的softmax函式,也僅僅是在輸出層才使用。

選擇合適的優化器和學習速率

神經網路訓練的優化器也是需要考慮的一大因素。神經網路的優化器其實有很多種,每種都有其不同的特點,我們最耳熟能詳的就是梯度下降法,對應著有批量梯度下降,隨機梯度下降。這種優化方法其實不賴,尤其是在神經網路即將最終收斂的時候,使用一個合適的學習速率使得其最終下降到儘可能低的點上。但是隨機梯度下降有著明顯的缺點,尤其是跟Momentum、Adagrad、Adadelta等其他優化器對比之後。

而且,這裡我最推薦Adadelta,在一開始的效果很顯著,只有在最終收斂之前可能不如SGD,可以選擇這時候再換成SGD就行了。而且Adadelta不需要太多關注學習率,因為其訓練的原理已經不怎麼跟學習率有關了。

不過,如果是SGD的話,在排除了以上情況之後,當神經網路仍欠擬合或者loss不再下降時,可以將學習率調小一些試試。

一般來說,經過以上的組合拳式的優化調參,欠擬合問題基本上都能夠得到解決,哪怕最後仍然準確率不高,但肯定是擬合了。欠擬合問題解決之後,接下來要解決的就是過擬合問題了。

更多參考: http://nooverfit.com/wp/%E5%90%B4%E6%81%A9%E8%BE%BE%E6%96%B0%E4%B9%A6%E3%80%8Amachine-learning-yearning%E3%80%8B%E8%AF%BB%E5%90%8E%E6%84%9F%EF%BC%8C%E9%AA%8C%E8%AF%81%E6%B5%8B%E8%AF%95%E9%9B%86%E6%80%8E%E4%B9%88%E9%80%89/