1. 程式人生 > >改善深層神經網路——深度學習的實用層面(5)

改善深層神經網路——深度學習的實用層面(5)

目錄

正則化

偏差大的解決辦法:在正則化引數合適的情況下增大網路(不影響方差)

方差大解決辦法:調整正則化引數或者準備更多資料增大資料集(不影響偏差)

正則化

邏輯迴歸正則化:

神經網路正則化:

6.Dropout正則化

除了L2 regularization之外,還有另外一種防止過擬合的有效方法:Dropout。

Dropout是指在深度學習網路的訓練過程中,對於每層的神經元,按照一定的概率將其暫時從網路中丟棄。也就是說,每次訓練時,每一層都有部分神經元不工作,起到簡化複雜網路模型的效果,從而避免發生過擬合。

Dropout有不同的實現方法,接下來介紹一種常用的方法:Inverted dropout

。假設對於第ll層神經元,設定保留神經元比例概率keep_prob=0.8,即該層有20%的神經元停止工作。dldl為dropout向量,設定dldl為隨機vector,其中80%的元素為1,20%的元素為0。在python中可以使用如下語句生成dropout vector:

dl = np.random.rand(al.shape[0],al.shape[1])<keep_prob

然後,第ll層經過dropout,隨機刪減20%的神經元,只保留80%的神經元,其輸出為:

al = np.multiply(al,dl)

最後,還要對alal進行scale up處理,即:

al /= keep_prob

以上就是Inverted dropout的方法。之所以要對al進行scale up是為了保證在經過dropout後,al作為下一層神經元的輸入值儘量保持不變。假設第l層有50個神經元,經過dropout後,有10個神經元停止工作,這樣只有40神經元有作用。那麼得到的al只相當於原來的80%。scale up後,能夠儘可能保持al的期望值相比之前沒有大的變化。

Inverted dropout的另外一個好處就是在對該dropout後的神經網路進行測試時能夠減少scaling問題。因為在訓練時,使用scale up保證al的期望值沒有大的變化,測試時就不需要再對樣本資料進行類似的尺度伸縮操作了。

對於m個樣本,單次迭代訓練時,隨機刪除掉隱藏層一定數量的神經元;然後,在刪除後的剩下的神經元上正向和反向更新權重w和常數項b;接著,下一次迭代中,再恢復之前刪除的神經元,重新隨機刪除一定數量的神經元,進行正向和反向更新w和b。不斷重複上述過程,直至迭代訓練完成。

值得注意的是,使用dropout訓練結束後,在測試和實際應用模型時,不需要進行dropout和隨機刪減神經元,所有的神經元都在工作。

7.理解Dropout

Dropout通過每次迭代訓練時,隨機選擇不同的神經元,相當於每次都在不同的神經網路上進行訓練,類似機器學習中Bagging的方法(三個臭皮匠,賽過諸葛亮),能夠防止過擬合。

除此之外,還可以從權重w的角度來解釋為什麼dropout能夠有效防止過擬合。對於某個神經元來說,某次訓練時,它的某些輸入在dropout的作用被過濾了。而在下一次訓練時,又有不同的某些輸入被過濾。經過多次訓練後,某些輸入被過濾,某些輸入被保留。這樣,該神經元就不會受某個輸入非常大的影響,影響被均勻化了。也就是說,對應的權重w不會很大。這從從效果上來說,與L2 regularization是類似的,都是對權重w進行“懲罰”,減小了w的值。

總結一下,對於同一組訓練資料,利用不同的神經網路訓練之後,求其輸出的平均值可以減少overfitting。Dropout就是利用這個原理,每次丟掉一定數量的隱藏層神經元,相當於在不同的神經網路上進行訓練,這樣就減少了神經元之間的依賴性,即每個神經元不能依賴於某幾個其他的神經元(指層與層之間相連線的神經元),使神經網路更加能學習到與其他神經元之間的更加健壯robust的特徵。

在使用dropout的時候,有幾點需要注意。首先,不同隱藏層的dropout係數keep_prob可以不同。一般來說,神經元越多的隱藏層,keep_out可以設定得小一些.,例如0.5;神經元越少的隱藏層,keep_out可以設定的大一些,例如0.8,設定是1。另外,實際應用中,不建議對輸入層進行dropout,如果輸入層維度很大,例如圖片,那麼可以設定dropout,但keep_out應設定的大一些接近1,例如0.8,0.9。總體來說,就是越容易出現過擬合的隱藏層,其keep_prob就設定的相對小一些。沒有準確固定的做法,通常可以根據validation進行選擇。

Dropout在電腦視覺CV領域應用比較廣泛,因為輸入層維度較大,而且沒有足夠多的樣本數量。值得注意的是dropout是一種regularization技巧,用來防止過擬合的,最好只在需要regularization的時候使用dropout。

使用dropout的時候,可以通過繪製cost function來進行debug,看看dropout是否正確執行。一般做法是,將所有層的keep_prob全設定為1,再繪製cost function,即涵蓋所有神經元,看J是否單調下降。下一次迭代訓練時,再將keep_prob設定為其它值。

8.其他正則化方法

除了L2 regularization和dropout regularization之外,還有其它減少過擬合的方法。

一種方法是增加訓練樣本數量。但是通常成本較高,難以獲得額外的訓練樣本。但是,我們可以對已有的訓練樣本進行一些處理來“製造”出更多的樣本,稱為data augmentation。例如圖片識別問題中,可以對已有的圖片進行水平翻轉、垂直翻轉、任意角度旋轉、縮放或擴大等等。如下圖所示,這些處理都能“製造”出新的訓練樣本。雖然這些是基於原有樣本的,但是對增大訓練樣本數量還是有很有幫助的,不需要增加額外成本,卻能起到防止過擬合的效果。

在數字識別中,也可以將原有的數字圖片進行任意旋轉或者扭曲,或者增加一些noise,如下圖所示:

還有另外一種防止過擬合的方法:early stopping。一個神經網路模型隨著迭代訓練次數增加,train set error一般是單調減小的,而dev set error 先減小,之後又增大。也就是說訓練次數過多時,模型會對訓練樣本擬合的越來越好,但是對驗證集擬合效果逐漸變差,即發生了過擬合。因此,迭代訓練次數不是越多越好,可以通過train set error和dev set error隨著迭代次數的變化趨勢,選擇合適的迭代次數,即early stopping。

然而,Early stopping有其自身缺點。通常來說,機器學習訓練模型有兩個目標:一是優化cost function,儘量減小J;二是防止過擬合。這兩個目標彼此對立的,即減小J的同時可能會造成過擬合,反之亦然。我們把這二者之間的關係稱為正交化orthogonalization。該節課開始部分就講過,在深度學習中,我們可以同時減小Bias和Variance,構建最佳神經網路模型。但是,Early stopping的做法通過減少迭代訓練次數來防止過擬合,這樣J就不會足夠小。也就是說,early stopping將上述兩個目標融合在一起,同時優化,但可能沒有“分而治之”的效果好。

與early stopping相比,L2 regularization可以實現“分而治之”的效果:迭代訓練足夠多,減小J,而且也能有效防止過擬合。而L2 regularization的缺點之一是最優的正則化引數λλ的選擇比較複雜。對這一點來說,early stopping比較簡單。總的來說,L2 regularization更加常用一些。

9.標準化輸入

在訓練神經網路時,標準化輸入可以提高訓練的速度。標準化輸入就是對訓練資料集進行歸一化的操作,即將原始資料減去其均值μ後,再除以其方差\sigma ^{2}

\mu =\frac{1}{m}\sum_{i=1}^{m}X^{(i)}

\sigma ^{2}=\frac{1}{m}\sum_{i=1}^{m}(X^{(i)})^{2}

X:=\frac{X-\mu }{\sigma ^{2}}

以二維平面為例,下圖展示了其歸一化過程:

值得注意的是,由於訓練集進行了標準化處理,那麼對於測試集或在實際應用時,應該使用同樣的μ和\sigma ^{2}對其進行標準化處理。這樣保證了訓練集合測試集的標準化操作一致。

之所以要對輸入進行標準化操作,主要是為了讓所有輸入歸一化同樣的尺度上,方便進行梯度下降演算法時能夠更快更準確地找到全域性最優解。假如輸入特徵是二維的,且x1的範圍是[1,1000],x2的範圍是[0,1]。如果不進行標準化處理,x1與x2之間分佈極不平衡,訓練得到的w1和w2也會在數量級上差別很大。這樣導致的結果是cost function與w和b的關係可能是一個非常細長的橢圓形碗。對其進行梯度下降演算法時,由於w1和w2數值差異很大,只能選擇很小的學習因子α,來避免J發生振盪。一旦α較大,必然發生振盪,J不再單調下降。如下左圖所示。

然而,如果進行了標準化操作,x1與x2分佈均勻,w1和w2數值差別不大,得到的cost function與w和b的關係是類似圓形碗。對其進行梯度下降演算法時,αα可以選擇相對大一些,且J一般不會發生振盪,保證了J是單調下降的。如下右圖所示。

另外一種情況,如果輸入特徵之間的範圍本來就比較接近,那麼不進行標準化操作也是沒有太大影響的。但是,標準化處理在大多數場合下還是值得推薦的。

10.梯度消失和梯度爆炸

在神經網路尤其是深度神經網路中存在可能存在這樣一個問題:梯度消失和梯度爆炸。意思是當訓練一個 層數非常多的神經網路時,計算得到的梯度可能非常小或非常大,甚至是指數級別的減小或增大。這樣會讓訓練過程變得非常困難。

舉個例子來說明,假設一個多層的每層只包含兩個神經元的深度神經網路模型,如下圖所示:

為了簡化複雜度,便於分析,我們令各層的啟用函式為線性函式,即g(Z)=Zg(Z)=Z。且忽略各層常數項b的影響,令b全部為零。那麼,該網路的預測輸出\hat{Y}為:

\hat{Y}=W^{[L]}W^{[L-1]}W^{[L-2]}...W^{[3]}W^{[2]}W^{[1]}X

如果各層權重W^{[l]}的元素都稍大於1,例如1.5,則預測輸出\hat{Y}將正比於1.5^{L}。L越大,\hat{Y}越大,且呈指數型增長。我們稱之為數值爆炸。相反,如果各層權重W[l]的元素都稍小於1,例如0.5,則預測輸出\hat{Y}將正比於0.5^{L}。網路層數L越多,\hat{Y}呈指數型減小。我們稱之為數值消失。

也就是說,如果各層權重W^{[l]}都大於1或者都小於1,那麼各層啟用函式的輸出將隨著層數l的增加,呈指數型增大或減小。當層數很大時,出現數值爆炸或消失。同樣,這種情況也會引起梯度呈現同樣的指數型增大或減小的變化。L非常大時,例如L=150,則梯度會非常大或非常小,引起每次更新的步進長度過大或者過小,這讓訓練過程十分困難。

深度神經網路的權重初始化

下面介紹如何改善Vanishing and Exploding gradients這類問題,方法是對權重w進行一些初始化處理,不能讓矩陣w比1大很多也不能比1小很多。

深度神經網路模型中,以單個神經元為例,該層(l)的輸入個數為n,其輸出為:

這裡忽略了常數項b。為了讓z不會過大或者過小,思路是讓w與n有關,且n越大,w應該越小才好。這樣能夠保證z不會過大。一種方法是在初始化w時,令Var(V):=\frac{1}{n}。相應的python虛擬碼為:

w[l] = np.random.randn(n[l],n[l-1])*np.sqrt(1/n[l-1]) 

如果啟用函式是tanh,一般選擇上面的初始化方法。

如果啟用函式是ReLU,權重w的初始化一般令其方差為\frac{2}{n}

w[l] = np.random.randn(n[l],n[l-1])*np.sqrt(2/n[l-1]) 

除此之外,Yoshua Bengio對啟用函式tanh提出了另外一種初始化w的方法,令其方差為\frac{2}{n^{[l]}n^{[l-1]}}

w[l] = np.random.randn(n[l],n[l-1])*np.sqrt(2/n[l-1]*n[l]) 

至於選擇哪種初始化方法因人而異,可以根據不同的啟用函式選擇不同方法。另外,我們可以對這些初始化方法中設定某些引數,作為超引數,通過驗證集進行驗證,得到最優引數,來優化神經網路。

11.梯度的數值逼近和梯度檢測

利用微積分的思想,函式f在點\sigma處的梯度可以表示為:

g(\theta )=\frac{f(\theta +\varepsilon) -f(\theta -\varepsilon)}{2\varepsilon }

其中\varepsilon > 0且足夠小。

介紹完如何近似求出梯度值後,我們將介紹如何進行梯度檢查,來驗證訓練過程中是否出現bugs。

梯度檢查首先要做的是分別將W^{[1]},b^{[1]},...,W^{[L]},b^{[L]}這些矩陣構造成一維向量,然後將這些一維向量組合起來構成一個更大的一維向量\theta。這樣cost functionJ(W^{[1]},b^{[1]},...,W^{[L]},b^{[L]})就可以表示成J(\theta )

然後將反向傳播過程通過梯度下降演算法得到的dW^{[1]},db^{[1]},...,dW^{[L]},db^{[L]}按照一樣的順序構造成一個一維向量dθ。dθ的維度與θ一致。

接著利用J(θ)對每個θi計算近似梯度,其值與反向傳播演算法得到的dθi相比較,檢查是否一致。例如,對於第i個元素,近似梯度為:

d\theta _{approx}[i]=\frac{J(\theta _{1},\theta _{2},...,\theta _{i}+\varepsilon,... )-J(\theta _{1},\theta _{2},...,\theta _{i}-\varepsilon ,...)}{2\varepsilon }

計算完所有θi的近似梯度後,可以計算d\theta _{approx}與dθ的歐氏(Euclidean)距離來比較二者的相似度。公式如下:

\frac{\left \| d\theta _{approx}-d\theta \right \|_{2}}{\left \| d\theta _{approx} \right \|_{2}-\left \| d\theta \right \|_{2}}                ——歐幾里得範數,求誤差平方之和然後求平方根

一般來說,如果歐氏距離越小,例如10^{-7},甚至更小,則表明dθapprox與dθ越接近,即反向梯度計算是正確的,沒有bugs。如果歐氏距離較大,例如10−5,則表明梯度計算可能出現問題,需要再次檢查是否有bugs存在。如果歐氏距離很大,例如10−3,甚至更大,則表明dθapprox與dθ差別很大,梯度下降計算過程有bugs,需要仔細檢查。

在進行梯度檢查的過程中有幾點需要注意的地方:

  • 不要在整個訓練過程中都進行梯度檢查,僅僅作為debug使用。

  • 如果梯度檢查出現錯誤,找到對應出錯的梯度,檢查其推導是否出現錯誤。

  • 注意不要忽略正則化項,計算近似梯度的時候要包括進去。

  • 梯度檢查時關閉dropout,檢查完畢後再開啟dropout。

  • 隨機初始化時執行梯度檢查,經過一些訓練後再進行梯度檢查(不常用)。