吳恩達《優化深度神經網路》課程筆記(1)– 深度學習的實用層面

紅色石頭發表於2018-07-31

Andrew Ng的深度學習專項課程的第一門課《Neural Networks and Deep Learning》的5份筆記我已經整理完畢。在接下來的幾次筆記中,我們將對第二門課《Improving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimization》進行筆記總結和整理。我們在第一門課中已經學習瞭如何建立一個神經網路,或者淺層的,或者深度的。而這第二門課,我們將著重討論和研究如何優化神經網路模型,例如調整超引數,提高演算法執行速度等等。開始吧~

1. Train/Dev/Test sets

選擇最佳的訓練集(Training sets)、驗證集(Development sets)、測試集(Test sets)對神經網路的效能影響非常重要。除此之外,在構建一個神經網路的時候,我們需要設定許多引數,例如神經網路的層數、每個隱藏層包含的神經元個數、學習因子(學習速率)、啟用函式的選擇等等。實際上很難在第一次設定的時候就選擇到這些最佳的引數,而是需要通過不斷地迭代更新來獲得。這個迴圈迭代的過程是這樣的:我們先有個想法Idea,先選擇初始的引數值,構建神經網路模型結構;然後通過程式碼Code的形式,實現這個神經網路;最後,通過實驗Experiment驗證這些引數對應的神經網路的表現效能。根據驗證結果,我們對引數進行適當的調整優化,再進行下一次的Idea->Code->Experiment迴圈。通過很多次的迴圈,不斷調整引數,選定最佳的引數值,從而讓神經網路效能最優化。

深度學習已經應用於許多領域中,比如NLP,CV,Speech Recognition等等。通常來說,最適合某個領域的深度學習網路往往不能直接應用在其它問題上。解決不同問題的最佳選擇是根據樣本數量、輸入特徵數量和電腦配置資訊(GPU或者CPU)等,來選擇最合適的模型。即使是最有經驗的深度學習專家也很難第一次就找到最合適的引數。因此,應用深度學習是一個反覆迭代的過程,需要通過反覆多次的迴圈訓練得到最優化引數。決定整個訓練過程快慢的關鍵在於單次迴圈所花費的時間,單次迴圈越快,訓練過程越快。而設定合適的Train/Dev/Test sets數量,能有效提高訓練效率。

一般地,我們將所有的樣本資料分成三個部分:Train/Dev/Test sets。Train sets用來訓練你的演算法模型;Dev sets用來驗證不同演算法的表現情況,從中選擇最好的演算法模型;Test sets用來測試最好演算法的實際表現,作為該演算法的無偏估計。

之前人們通常設定Train sets和Test sets的數量比例為70%和30%。如果有Dev sets,則設定比例為60%、20%、20%,分別對應Train/Dev/Test sets。這種比例分配在樣本數量不是很大的情況下,例如100,1000,10000,是比較科學的。但是如果資料量很大的時候,例如100萬,這種比例分配就不太合適了。科學的做法是要將Dev sets和Test sets的比例設定得很低。因為Dev sets的目標是用來比較驗證不同演算法的優劣,從而選擇更好的演算法模型就行了。因此,通常不需要所有樣本的20%這麼多的資料來進行驗證。對於100萬的樣本,往往只需要10000個樣本來做驗證就夠了。Test sets也是一樣,目標是測試已選演算法的實際表現,無偏估計。對於100萬的樣本,往往也只需要10000個樣本就夠了。因此,對於大資料樣本,Train/Dev/Test sets的比例通常可以設定為98%/1%/1%,或者99%/0.5%/0.5%。樣本資料量越大,相應的Dev/Test sets的比例可以設定的越低一些。

現代深度學習還有個重要的問題就是訓練樣本和測試樣本分佈上不匹配,意思是訓練樣本和測試樣本來自於不同的分佈。舉個例子,假設你開發一個手機app,可以讓使用者上傳圖片,然後app識別出貓的圖片。在app識別演算法中,你的訓練樣本可能來自網路下載,而你的驗證和測試樣本可能來自不同使用者的上傳。從網路下載的圖片一般畫素較高而且比較正規,而使用者上傳的圖片往往畫素不穩定,且圖片質量不一。因此,訓練樣本和驗證/測試樣本可能來自不同的分佈。解決這一問題的比較科學的辦法是儘量保證Dev sets和Test sets來自於同一分佈。值得一提的是,訓練樣本非常重要,通常我們可以將現有的訓練樣本做一些處理,例如圖片的翻轉、假如隨機噪聲等,來擴大訓練樣本的數量,從而讓該模型更加強大。即使Train sets和Dev/Test sets不來自同一分佈,使用這些技巧也能提高模型效能。

最後提一點的是如果沒有Test sets也是沒有問題的。Test sets的目標主要是進行無偏估計。我們可以通過Train sets訓練不同的演算法模型,然後分別在Dev sets上進行驗證,根據結果選擇最好的演算法模型。這樣也是可以的,不需要再進行無偏估計了。如果只有Train sets和Dev sets,通常也有人把這裡的Dev sets稱為Test sets,我們要注意加以區別。

2. Bias/Variance

偏差(Bias)和方差(Variance)是機器學習領域非常重要的兩個概念和需要解決的問題。在傳統的機器學習演算法中,Bias和Variance是對立的,分別對應著欠擬合和過擬合,我們常常需要在Bias和Variance之間進行權衡。而在深度學習中,我們可以同時減小Bias和Variance,構建最佳神經網路模型。

如下圖所示,顯示了二維平面上,high bias,just right,high variance的例子。可見,high bias對應著欠擬合,而high variance對應著過擬合。

上圖這個例子中輸入特徵是二維的,high bias和high variance可以直接從圖中分類線看出來。而對於輸入特徵是高維的情況,如何來判斷是否出現了high bias或者high variance呢?

例如貓識別問題,輸入是一幅影象,其特徵維度很大。這種情況下,我們可以通過兩個數值Train set error和Dev set error來理解bias和variance。假設Train set error為1%,而Dev set error為11%,即該演算法模型對訓練樣本的識別很好,但是對驗證集的識別卻不太好。這說明了該模型對訓練樣本可能存在過擬合,模型泛化能力不強,導致驗證集識別率低。這恰恰是high variance的表現。假設Train set error為15%,而Dev set error為16%,雖然二者error接近,即該演算法模型對訓練樣本和驗證集的識別都不是太好。這說明了該模型對訓練樣本存在欠擬合。這恰恰是high bias的表現。假設Train set error為15%,而Dev set error為30%,說明了該模型既存在high bias也存在high variance(深度學習中最壞的情況)。再假設Train set error為0.5%,而Dev set error為1%,即low bias和low variance,是最好的情況。值得一提的是,以上的這些假設都是建立在base error是0的基礎上,即人類都能正確識別所有貓類圖片。base error不同,相應的Train set error和Dev set error會有所變化,但沒有相對變化。

一般來說,Train set error體現了是否出現bias,Dev set error體現了是否出現variance(正確地說,應該是Dev set error與Train set error的相對差值)。

我們已經通過二維平面展示了high bias或者high variance的模型,下圖展示了high bias and high variance的模型:

模型既存在high bias也存在high variance,可以理解成某段區域是欠擬合的,某段區域是過擬合的。

3. Basic Recipe for Machine Learning

機器學習中基本的一個訣竅就是避免出現high bias和high variance。首先,減少high bias的方法通常是增加神經網路的隱藏層個數、神經元個數,訓練時間延長,選擇其它更復雜的NN模型等。在base error不高的情況下,一般都能通過這些方式有效降低和避免high bias,至少在訓練集上表現良好。其次,減少high variance的方法通常是增加訓練樣本資料,進行正則化Regularization,選擇其他更復雜的NN模型等。

這裡有幾點需要注意的。第一,解決high bias和high variance的方法是不同的。實際應用中通過Train set error和Dev set error判斷是否出現了high bias或者high variance,然後再選擇針對性的方法解決問題。

第二,Bias和Variance的折中tradeoff。傳統機器學習演算法中,Bias和Variance通常是對立的,減小Bias會增加Variance,減小Variance會增加Bias。而在現在的深度學習中,通過使用更復雜的神經網路和海量的訓練樣本,一般能夠同時有效減小Bias和Variance。這也是深度學習之所以如此強大的原因之一。

4. Regularization

如果出現了過擬合,即high variance,則需要採用正則化regularization來解決。雖然擴大訓練樣本數量也是減小high variance的一種方法,但是通常獲得更多訓練樣本的成本太高,比較困難。所以,更可行有效的辦法就是使用regularization。

我們先來回顧一下之前介紹的Logistic regression。採用L2 regularization,其表示式為:

J(w,b)=\frac1m\sum_{i=1}^mL(\hat y^{(i)},y^{(i)})+\frac{\lambda}{2m}||w||_2^2

||w||_2^2=\sum_{j=1}^{n_x}w_j^2=w^Tw

這裡有個問題:為什麼只對w進行正則化而不對b進行正則化呢?其實也可以對b進行正則化。但是一般w的維度很大,而b只是一個常數。相比較來說,引數很大程度上由w決定,改變b值對整體模型影響較小。所以,一般為了簡便,就忽略對b的正則化了。

除了L2 regularization之外,還有另外一隻正則化方法:L1 regularization。其表示式為:

J(w,b)=\frac1m\sum_{i=1}^mL(\hat y^{(i)},y^{(i)})+\frac{\lambda}{2m}||w||_1

||w||_1=\sum_{j=1}^{n_x}|w_j|

與L2 regularization相比,L1 regularization得到的w更加稀疏,即很多w為零值。其優點是節約儲存空間,因為大部分w為0。然而,實際上L1 regularization在解決high variance方面比L2 regularization並不更具優勢。而且,L1的在微分求導方面比較複雜。所以,一般L2 regularization更加常用。

L1、L2 regularization中的\lambda就是正則化引數(超引數的一種)。可以設定\lambda為不同的值,在Dev set中進行驗證,選擇最佳的\lambda。順便提一下,在python中,由於lambda是保留字,所以為了避免衝突,我們使用lambd來表示\lambda

在深度學習模型中,L2 regularization的表示式為:

J(w^{[1]},b^{[1]},\cdots,w^{[L]},b^{[L]})=\frac1m\sum_{i=1}^mL(\hat y^{(i)},y^{(i)})+\frac{\lambda}{2m}\sum_{l=1}^L||w^{[l]}||^2

||w^{[l]}||^2=\sum_{i=1}^{n^{[l]}}\sum_{j=1}^{n^{[l-1]}}(w_{ij}^{[l]})^2

通常,我們把||w^{[l]}||^2稱為Frobenius範數,記為||w^{[l]}||_F^2。一個矩陣的Frobenius範數就是計算所有元素平方和再開方,如下所示:

||A||_F=\sqrt {\sum_{i=1}^m\sum_{j=1}^n|a_{ij}|^2}

值得注意的是,由於加入了正則化項,梯度下降演算法中的dw^{[l]}計算表示式需要做如下修改:

dw^{[l]}=dw^{[l]}_{before}+\frac{\lambda}{m}w^{[l]}

w^{[l]}:=w^{[l]}-\alpha\cdot dw^{[l]}

L2 regularization也被稱做weight decay。這是因為,由於加上了正則項,dw^{[l]}有個增量,在更新w^{[l]}的時候,會多減去這個增量,使得w^{[l]}比沒有正則項的值要小一些。不斷迭代更新,不斷地減小。

其中,(1-\alpha\frac{\lambda}{m})<1

5. Why regularization reduces overfitting

為什麼正則化能夠有效避免high variance,防止過擬合呢?下面我們通過幾個例子說明。

還是之前那張圖,從左到右,分別表示了欠擬合,剛好擬合,過擬合三種情況。

假如我們選擇了非常複雜的神經網路模型,如上圖左上角所示。在未使用正則化的情況下,我們得到的分類超平面可能是類似上圖右側的過擬合。但是,如果使用L2 regularization,當\lambda很大時,w^{[l]}\approx0w^{[l]}近似為零,意味著該神經網路模型中的某些神經元實際的作用很小,可以忽略。從效果上來看,其實是將某些神經元給忽略掉了。這樣原本過於複雜的神經網路模型就變得不那麼複雜了,而變得非常簡單化了。如下圖所示,整個簡化的神經網路模型變成了一個邏輯迴歸模型。問題就從high variance變成了high bias了。

因此,選擇合適大小的\lambda值,就能夠同時避免high bias和high variance,得到最佳模型。

還有另外一個直觀的例子來解釋為什麼正則化能夠避免發生過擬合。假設啟用函式是tanh函式。tanh函式的特點是在z接近零的區域,函式近似是線性的,而當|z|很大的時候,函式非線性且變化緩慢。當使用正則化,\lambda較大,即對權重w^{[l]}的懲罰較大,w^{[l]}減小。因為z^{[l]}=w^{[l]}a^{[l]}+b^{[l]}。當w^{[l]}減小的時候,z^{[l]}也會減小。則此時的z^{[l]}分佈在tanh函式的近似線性區域。那麼這個神經元起的作用就相當於是linear regression。如果每個神經元對應的權重w^{[l]}都比較小,那麼整個神經網路模型相當於是多個linear regression的組合,即可看成一個linear network。得到的分類超平面就會比較簡單,不會出現過擬合現象。

6. Dropout Regularization

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

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

Dropout有不同的實現方法,接下來介紹一種常用的方法:Inverted dropout。假設對於第l層神經元,設定保留神經元比例概率keep_prob=0.8,即該層有20%的神經元停止工作。dl為dropout向量,設定dl為隨機vector,其中80%的元素為1,20%的元素為0。在python中可以使用如下語句生成dropout vector:

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

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

al = np.multiply(al,dl)

最後,還要對al進行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. Understanding 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應設定的大一些,例如0.8,0.9。總體來說,就是越容易出現overfitting的隱藏層,其keep_prob就設定的相對小一些。沒有準確固定的做法,通常可以根據validation進行選擇。

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

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

8. Other regularization methods

除了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的缺點之一是最優的正則化引數\lambda的選擇比較複雜。對這一點來說,early stopping比較簡單。總的來說,L2 regularization更加常用一些。

9. Normalizing inputs

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

\mu=\frac1m\sum_{i=1}^mX^{(i)}

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

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

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

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

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

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

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

10. Vanishing and Exploding gradients

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

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

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

\hat Y=W^{[L]}W^{[L-1]}W^{[L-2]}\cdots 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,則梯度會非常大或非常小,引起每次更新的步進長度過大或者過小,這讓訓練過程十分困難。

11. Weight Initialization for Deep Networks

下面介紹如何改善Vanishing and Exploding gradients這類問題,方法是對權重w進行一些初始化處理。

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

z=w_1x_1+w_2x_2+\cdots+w_nx_n

a=g(z)

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

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

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

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

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

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

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

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

12. Numerical approximation of gradients

Back Propagation神經網路有一項重要的測試是梯度檢查(gradient checking)。其目的是檢查驗證反向傳播過程中梯度下降演算法是否正確。該小節將先介紹如何近似求出梯度值。

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

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

其中,\varepsilon>0,且足夠小。

13. Gradient checking

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

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

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

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

d\theta_{approx}[i]=\frac{J(\theta_1,\theta_2,\cdots,\theta_i+\varepsilon,\cdots)-J(\theta_1,\theta_2,\cdots,\theta_i-\varepsilon,\cdots)}{2\varepsilon}

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

\frac{||d\theta_{approx}-d\theta||_2}{||d\theta_{approx}||_2+||d\theta||_2}

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

14. Gradient Checking Implementation Notes

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

  • 不要在整個訓練過程中都進行梯度檢查,僅僅作為debug使用。
  • 如果梯度檢查出現錯誤,找到對應出錯的梯度,檢查其推導是否出現錯誤。

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

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

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


更多AI資源請關注公眾號:AI有道(ID:redstonewill)

相關文章