1. 程式人生 > >深度學習常用優化方法

深度學習常用優化方法

深度解讀最流行的優化演算法:梯度下降

【本文轉載自機器之心   翻譯:沈澤江 原文地址:http://www.jiqizhixin.com/article/1857】

梯度下降法,是當今最流行的優化(optimization)演算法,亦是至今最常用的優化神經網路的方法。本文旨在讓你對不同的優化梯度下降法的演算法有一個直觀認識,以幫助你使用這些演算法。我們首先會考察梯度下降法的各種變體,然後會簡要地總結在訓練(神經網路或是機器學習演算法)的過程中可能遇到的挑戰。(本文的中文版 PDF 下載地址

目錄

  • 梯度下降的各種變體

  1. 批量梯度下降(Batch gradient descent)

  2. 隨機梯度下降(Stochastic gradient descent)

  3. 小批量梯度下降(Mini-batch gradient descent)

  • 面臨的挑戰

  • 梯度下降的優化演算法

  1. Momentum法

  2. Nesterov加速梯度法

  3. Adagrad法

  4. Adadelta法

  5. RMSprop法

  6. 適應性動量估計法(Adam)

  7. 幾種演算法的視覺化

  8. 該選擇哪種優化器

  • 對SGD進行平行或分散式運算

  1. Hogwild!

  2. Downpour SGD

  3. 容忍延遲的SGD演算法

  4. TensorFlow

  5. 彈性平均梯度下降法(Elastic Averaging SGD)

  • 優化SGD的其他手段

  1. 重排(Shuffling )和遞進學習(Curriculum Learning)

  2. 批量標準化(Batch normalization)

  3. 早停(Early Stopping)

  4. 梯度噪聲(Gradient noise)

  • 結論

  • 參考資料

梯度下降法,是當今最流行的優化(optimization)演算法,亦是至今最常用的優化神經網路的方法。與此同時,最新的深度學習程式庫都包含了各種優化梯度下降的演算法(可以參見如 lasagne、caffe 及 Kera 等程式庫的說明文件)。但它們的演算法則不被公開,都作為黑箱優化器被使用,這也就是為什麼它們的優勢和劣勢往往難以被實際地解釋。


本文旨在讓你對不同的優化梯度下降法的演算法有一個直觀認識,以幫助你使用這些演算法。我們首先會考察梯度下降法的各種變體,然後會簡要地總結在訓練(神經網路或是機器學習演算法)的過程中可能遇到的挑戰。接著,我們將會討論一些最常見的優化演算法,研究它們的解決這些挑戰的動機及推匯出更新規律(update rules)的過程。我們還會簡要探討一下,在平行計算或是分散式處理情況下優化梯度下降法的演算法和架構。最後,我們會考慮一下其他有助於優化梯度下降法的策略。

梯度下降法的核心,是最小化目標函式 J(θ),其中θ是模型的引數,θ∈Rd。它的方法是,在每次迭代中,對每個變數,按照目標函式在該變數梯度的相反方向,更新對應的引數值。其中,學習率η決定了函式到達(區域性)最小值的迭代次數。換句話說,我們在目標函式的超平面上,沿著斜率下降的方向前進,直到我們遇到了超平面構成的「谷底」。如果你不熟悉梯度下降法的話,你可以在這裡找到一個很好的關於優化神經網路的介紹。

梯度下降法變體

本文討論了三種梯度下降法的變體——它們的不同之處在於,一次性使用多少資料來計算目標函式的梯度。對於不同的資料量,我們需要在引數更新準確性和引數更新花費時間兩方面做出權衡。

批量梯度下降法(Batch Gradient Descent)

Vanilla 梯度下降法(譯者注:Vanilla 是早期機器學習演算法相關的名詞,也是如今一個機器學習 python 程式庫的名字,在該處指的是後者,參見:https://github.com/vinhkhuc/VanillaML),也就是大家所熟知的批量梯度下降法,在整個資料集上(求出罰函式 J(θ 並)對每個引數 θ 求目標函式 J(θ) 的偏導數:

blob.png

在該方法中,每次更新我們都需要在整個資料集上求出所有的偏導數。因此批量梯度下降法的速度會比較慢,甚至對於較大的、記憶體無法容納的資料集,該方法都無法被使用。同時,梯度下降法不能以「線上」的形式更新我們的模型,也就是不能再執行中加入新的樣本進行運算。

批量梯度下降法的實現程式碼,如下所示:

for i in range(nb_epochs):
  params_grad = evaluate_gradient(loss_function, data, params)
  params = params - learning_rate * params_grad

對於給定的迭代次數,我們首先基於輸入的罰函式 loss_function 對輸入的引數向量 params 計算梯度向量 params_grad。注意,最新的深度學習程式庫中,提供了自動求導的功能,能夠高效、快速地求給定函式對於特定引數的導數。如果你希望自己寫程式碼求出梯度值,那麼「梯度檢查」會是一個不錯的注意。(你可以參考這裡,瞭解關於如何檢查梯度的相關建議。)

然後,我們對引數減去梯度值乘學習率的值,也就是在反梯度方向,更新我們引數。當目標函式 J(θ) 是一凸函式時,則批量梯度下降法必然會在全域性最小值處收斂;否則,目標函式則可能會區域性極小值處收斂。

隨機梯度下降法(Stochastic Gradient Descent)

相比批量梯度下降法,隨機梯度下降法的每次更新,是對資料集中的一個樣本(x,y)求出罰函式,然後對其求相應的偏導數:

blob.png

因為批量梯度下降法在每次更新前,會對相似的樣本求算梯度值,因而它在較大的資料集上的計算會有些冗餘(redundant)。而隨機梯度下降法通過每次更新僅對一個樣本求梯度,去除了這種冗餘的情況。因而,它的執行速度被大大加快,同時也能夠「線上」學習。

隨機梯度下降法更新值的方差很大,在頻繁的更新之下,它的目標函式有著如下圖所示的劇烈波動。

deep-learning-pic.png

SGD 函式波動,來源:Wikipedia

相比批量梯度下降法的收斂會使目標函式落入一個區域性極小值,SGD 收斂過程中的波動,會幫助目標函式跳入另一個可能的更小的極小值。另一方面,這最終會讓收斂到特定最小值的過程複雜化,因為該方法可能持續的波動而不停止。但是,當我們慢慢降低學習率的時候,SGD 表現出了與批量梯度下降法相似的收斂過程,也就是說,對非凸函式和凸函式,必然會分別收斂到它們的極小值和最小值。

相比批量梯度下降法的程式碼,在如下的程式碼中,我們僅僅加入了一個迴圈,用以遍歷所有的訓練樣本並求出相應的梯度值。注意,如這裡所說,在每次迭代中,我們會打亂訓練資料集。

for i in range(nb_epochs):
  np.random.shuffle(data)
  for example in data:
    params_grad = evaluate_gradient(loss_function, example, params)
    params = params - learning_rate * params_grad

小批量梯度下降法(Mini-Batch Gradient Descent)

小批量梯度下降法集合了上述兩種方法的優勢,在每次更新中,對 n 個樣本構成的一批資料,計算罰函式 J(θ),並對相應的引數求導:

blob.png

這種方法,(a) 降低了更新引數的方差(variance),使得收斂過程更為穩定;(b) 能夠利用最新的深度學習程式庫中高度優化的矩陣運算器,能夠高效地求出每小批資料的梯度。通常一小批資料含有的樣本數量在 50 至 256 之間,但對於不同的用途也會有所變化。小批量梯度下降法,通常是我們訓練神經網路的首選演算法。同時,有時候我們也會使用隨機梯度下降法,來稱呼小批量梯度下降法(譯者注:在下文中,我們就用 SGD 代替隨機梯度下降法)。注意:在下文對於隨機梯度法優化的介紹中,為方便起見,我們會省略式子中的引數 x(i:i+n),y(i:i+n)。

如下的程式碼所示,我們不再對每個樣本進行迴圈,而是對每批帶有 50 個樣本的小批資料進行迴圈:

for i in range(nb_epochs):
  np.random.shuffle(data)
  for batch in get_batches(data, batch_size=50):
    params_grad = evaluate_gradient(loss_function, batch, params)
    params = params - learning_rate * params_grad

面臨的挑戰

由於 Vanilla 小批量梯度下降法並不能保證良好地收斂,這給我們留下了如下待解決的挑戰:

  • 選擇適當的學習率是一個難題。太小的學習率會導致較慢的收斂速度,而太大的學習率則會阻礙收斂,並會引起罰函式在最小值處震盪,甚至有可能導致結果發散;

  • 我們可以設定一個關於學習率地列表,通過如退火的方法,在學習過程中調整學習率——按照一個預先定義的列表、或是當每次迭代中目標函式的變化小於一定閾值時來降低學習率。但這些列表或閾值,需要根據資料集地特性,被提前定義。

  • 此外,我們對所有的引數都採用了相同的學習率。但如果我們的資料比較稀疏,同時特徵有著不同的出現頻率,那麼我們不希望以相同的學習率來更新這些變數,我們希望對較少出現的特徵有更大的學習率。

在對神經網路最優化非凸的罰函式時,另一個通常面臨的挑戰,是如何避免目標函式被困在無數的區域性最小值中,以導致的未完全優化的情況。Dauphin 及其他人 [19] 認為,這個困難並不來自於區域性最小值,而是來自於「鞍點」,也就是在一個方向上斜率是正的、在一個方向上斜率是負的點。這些鞍點通常由一些函式值相同的面環繞,它們在各個方向的梯度值都為 0,所以 SGD 很難從這些鞍點中脫開。

梯度下降的優化演算法

在如下的討論中,我們將會列舉一些應對上述問題的演算法,它們被廣泛應用於深度學習社群。同時,我們不會討論那些不能應用於高維資料集的方法,例如牛頓法等針對二階問題的方法。

動量法

SGD 很難在陡谷——一種在一個方向的彎曲程度遠大於其他方向的表面彎曲情況——中找到正確更新方向。而這種陡谷,經常在區域性極值中出現。在這種情況下,如圖 2 所示,SGD 在陡谷的周圍震盪,向區域性極值處緩慢地前進。

blob.png

動量法 [2],如圖 3 所示,則幫助 SGD 在相關方向加速前進,並減少它的震盪。他通過修改公式中,在原有項前增加一個折損係數γ,來實現這樣的功能:

blob.png

注意:在其他的一些演算法實現中,公式中的符號也許有所不同。動量項 γ 往往被設定為 0.9 或為其他差不多的值。

從本質上說,動量法,就彷彿我們從高坡上推下一個球,小球在向下滾動的過程中積累了動量,在途中他變得越來越快(直到它達到了峰值速度,如果有空氣阻力的話,γ<1)。在我們的演算法中,相同的事情發生在我們的引數更新上:動量項在梯度指向方向相同的方向逐漸增大,對梯度指向改變的方向逐漸減小。由此,我們得到了更快的收斂速度以及減弱的震盪。

Nesterov 加速梯度法

但當一個小球從山谷上滾下的時候,盲目的沿著斜率方向前行,其效果並不令人滿意。我們需要有一個更「聰明」的小球,它能夠知道它再往哪裡前行,並在知道斜率再度上升的時候減速。

Nesterov 加速梯度法(NAG)是一種能給予梯度項上述「預測」功能的方法。我們知道,我們使用動量項γvt-1 來「移動」引數項θ。通過計算θ-γvt-1,我們能夠得到一個下次引數位置的近似值——也就是能告訴我們引數大致會變為多少。那麼,通過基於未來引數的近似值而非當前的引數值計算相得應罰函式 J(θ-γvt-1) 並求偏導數,我們能讓優化器高效地「前進」並收斂:

blob.png

在該情況下,我們依然設定動量係數γ 在 0.9 左右。如下圖 4 所示,動量法首先計算當前的梯度值(小藍色向量),然後在更新的積累向量(大藍色向量)方向前進一大步。但 NAG 法則首先(試探性地)在之前積累的梯度方向(棕色向量)前進一大步,再根據當前地情況修正,以得到最終的前進方向(綠色向量)。這種基於預測的更新方法,使我們避免過快地前進,並提高了演算法地響應能力(responsiveness),大大改進了 RNN 在一些任務上的表現 [8]。

jqzx (88).png

Nesterov Update 法,來源:G. Hinton’s lecture 6c

參考這裡,以檢視 Ilya Sutskever 在它博士論文中,對 NAG 機理的更為詳盡的解釋 [9]。

因為我們現在能根據我們罰函式的梯度值來調整我們的更新,並能相應地加速 SGD,我們也希望能夠對罰函式中的每個引數調整我們的更新值,基於它們的重要性以進行或大或小的更新。

Adagrad 法

Adagrad[3] 是一個基於梯度的優化演算法,它的主要功能是:它對不同的引數調整學習率,具體而言,對低頻出現的引數進行大的更新,對高頻出現的引數進行小的更新。因此,他很適合於處理稀疏資料。Dean 等人 [14] 發現,Adagrad 法大大提升了 SGD 的魯棒性,並在谷歌使用它訓練大規模的神經網路,其諸多功能包括識別 Youtube 視訊中的貓。此外,Pennington 等人 [5] 使用它訓練 GloVe 單詞向量對映(Word Embedding),在其中不頻繁出現的詞語需要比頻繁出現的更大的更新值。

在這之前,我們對於所有的引數使用相同的學習率進行更新。但 Adagrad 則不然,對不同的訓練迭代次數 t,adagrad 對每個引數都有一個不同的學習率。我們首先考察 adagrad 每個引數的的更新過程,然後我們再使之向量化。為簡潔起見,我們記在迭代次數 t 下,對引數θi 求目標函式梯度的結果為 gt,i:

blob.png

那麼普通 SGD 的更新規則為:

blob.png

而 adagrad 將學習率η進行了修正,對迭代次數 t,基於每個引數之前計算的梯度值,將每個引數的學習率η按如下方式修正:

blob.png

其中 是一個對角陣,其中對角線上的元素是從一開始到 時刻目標函式對於引數 梯度的平方和。是一個平滑項,以避免分母為 0 的情況,它的數量級通常在。有趣的是,如果不開方的話,這個演算法的表現會變得很糟。

因為 在其對角線上,含有過去目標函式對於引數 梯度的平方和,我們可以利用一個元素對元素的向量乘法,將我們的表示式向量化:

blob.png

Adagrad 主要優勢之一,是它不需要對每個學習率手工地調節。而大多數演算法,只是簡單地使用一個相同地預設值如 0.1,來避免這樣地情況。

Adagrad 地主要劣勢,是他在分母上的項中積累了平方梯度和。因為每次加入的項總是一個正值,所以累積的和將會隨著訓練過程而增大。因而,這會導致學習率不斷縮小,並最終變為一個無限小值——此時,這個演算法已經不能從資料中學到額外的資訊。而下面的演算法,則旨在解決這個問題。

Adadelta 法

Adadelta 法 [6] 是 Adagrad 法的一個延伸,它旨在解決它學習率不斷單調下降的問題。相比計算之前所有梯度值的平方和,Adadelta 法僅計算在一個大小為 的時間區間內梯度值的累積和。

但該方法並不會儲存之前 個梯度的平方值,而是將梯度值累積值按如下的方式遞迴地定義:它被定義為關於過去梯度值的衰減均值(decade average),當前時間的梯度均值是基於過去梯度均值和當前梯度值平方的加權平均,其中是類似上述動量項的權值。

blob.png

與動量項的設定類似,我們設定 為以 0.9 左右的值。為明確起見,我們將我們的 SGD 更新規則寫為關於引數更新向量 的形式:

blob.png

由此,我們剛剛在 Adagrad 法中推導的的引數更新規則的向量表示,變為如下形式:

blob.png

我們現在將其中的對角矩陣 用上述定義的基於過去梯度平方和的衰減均值 替換:

blob.png

因為分母表示式的形式與梯度值的方均根(root mean squared,RMS)形式類似,因而我們使用相應的簡寫來替換:

blob.png

作者還注意到,在該更新中(在 SGD、動量法或者 Adagrad 也類似)的單位並不一致,也就是說,更新值的量綱與引數值的假設量綱並不一致。為改進這個問題,他們定義了另外一種指數衰減的衰減均值,他是基於引數更新的平方而非梯度的平方來定義的:

blob.png

因此,對該問題的方均根為:

blob.png

因為 值未知,所以我們使用 時刻的方均根來近似。將前述規則中的學習率 替換為,我們最終得到了 Adadelta 法的更新規則:

blob.png

藉助 Adadelta 法,我們甚至不需要預設一個預設學習率,因為它已經從我們的更新規則中被刪除了。

RMSprop 法

RMSprop 是由 Geoff Hinton 在他 Coursera 課程中提出的一種適應性學習率方法,至今仍未被公開發表。

RMSprop 法和 Adadelta 法幾乎同時被髮展出來。他們 解決 Adagrad 激進的學習率縮減問題。實際上,RMSprop 和我們推匯出的 Adadelta 法第一個更規則相同:

blob.png

RMSprop 也將學習率除以了一個指數衰減的衰減均值。Hinton 建議設定 為 0.9,對 而言,0.001 是一個較好的預設值。

Adam

適應性動量估計法(Adam)[15] 是另一種能對不同引數計算適應性學習率的方法。除了儲存類似 Adadelta 法或 RMSprop 中指數衰減的過去梯度平方均值 外,Adam 法也儲存像動量法中的指數衰減的過去梯度值均值 :

blob.png

和 分別是梯度的一階矩(均值)和二階矩(表示不確定度的方差),這也就是該方法名字的來源。因為當 和 一開始被初始化為 0 向量時,Adam 的作者觀察到,該方法會有趨向 0 的偏差,尤其是在最初的幾步或是在衰減率很小(即 和 接近 1)的情況下。

他們使用偏差糾正係數,來修正一階矩和二階矩的偏差:

blob.png

他們使用這些來更新引數,更新規則很我們在 Adadelta 和 RMSprop 法中看到的一樣,服從 Adam 的更新規則:blob.png

作者認為引數的預設值應設為:0.9 for 

β1, 0.999 for β2, and 108 for ϵ.    。他們的經驗表明,Adam 在實踐中表現很好,和其他適應性學習演算法相比也比較不錯。

演算法視覺化

如下的兩個動畫(影象版權:Alec Radford)給了我們關於特定優化演算法在優化過程中行為的直觀感受。你可以參見這裡,以獲取 Karpathy 對相同影象的一些描述,及另關於一些相關演算法的細緻討論。

在圖 5 中,我們可以看到,在罰函式的等高線圖中,優化器的位置隨時間的變化情況。注意到,Adagrad、 Adadelta 及 RMSprop 法幾乎立刻就找到了正確前進方向並以相似的速度很快收斂。而動量法和 NAG 法,則找錯了方向,如圖所示,讓小球沿著梯度下降的方向前進。但 NAG 法能夠很快改正它的方向向最小指出前進,因為他能夠往前看並對前面的情況做出響應。

圖 6 展現了各演算法在鞍點附近的表現。如上面所說,這對對於 SGD 法、動量法及 NAG 法制造了一個難題。他們很難打破」對稱性「帶來的壁壘,儘管最後兩者設法逃脫了鞍點。而 Adagrad 法、RMSprop 法及 Adadelta 法都能快速的沿著負斜率的方向前進。

Black_box_AI_nature.gif

圖5:SGD optimization on loss surface contours

Synced (5).gif

圖6:SGD optimization on saddle point108

如我們所見,適應性學習率方法,也就是 Adagrad 法、Adadelta 法 、RMSprop 法及 Adam 法最適合處理上述情況,並有最好的收斂效果。

如何選擇優化器?

那麼,我們該如何選擇優化器呢?如果你的輸入資料較為稀疏(sparse),那麼使用適應性學習率型別的演算法會有助於你得到好的結果。此外,使用該方法的另一好處是,你在不調參、直接使用預設值的情況下,就能得到最好的結果。

總的來說,RMSprop 法是一種基於 Adagrad 法的拓展,他從根本上解決學習率驟縮的問題。Adadelta 法於 RMSprop 法大致相同,除了前者使用了。而 Adam 法,則基於 RMSprop 法添加了偏差修正項和動量項。在我們地討論範圍中,RMSprop、Adadelta 及 Adam 法都是非常相似地演算法,在相似地情況下都能做的很好。Kingma 及其他人 [15] 展示了他們的偏差修正項幫助 Adam 法,在最優化過程快要結束、梯度變得越發稀疏的時候,表現略微優於 RMSprop 法。總的來說,Adam 也許是總體來說最好的選擇。

有趣的是,很多最新的論文,都直接使用了(不帶動量項的)Vanilla SGD 法,配合一個簡單的學習率(退火)列表。如論文所示,這些 SGD 最終都能幫助他們找到一個最小值,但會花費遠多於上述方法的時間。並且這些方法非常依賴於魯棒的初始化值及退火列表。因此,如果你非常在你的模型能快速收斂,或是你需要訓練一個深度或複雜模型,你可能需要選擇上述的適應性模型。

對 SGD 進行平行計算或分散式計算

現如今,大規模資料集隨處可見、小型計算機叢集也易於獲得。因而,使用分散式方法進一步加速 SGD 是一個慣常的選擇。

SGD 它本事是序列化的:通過一步一步的迭代,我們最終求到了最小值。執行它能夠得到不錯的收斂結果,但是特別是對於大規模的資料集,它的執行速度很慢。相比而言,非同步 SGD 的執行速度相對較快,但在不同的工作機之間的關於非完全優化的溝通可能會導致較差的收斂結果。此外,我們能夠對 SGD 進行平行運算而不需要一個計算機叢集。下文討論了相關的演算法或架構,它們或關於平行計算或者對其進行了分散式優化。

Hogwild!

Niu 等人提出了一種叫做 Hogwild! 的更新規則,它允許在平行 GPU 上進行 SGD 更新。處理器。這僅能在輸入資料集是稀疏的時起效,在每次更新過程中僅會修正一部分的引數值。他們展示了,在這種情況下,這個更新規則達到了最優化的收斂速度,因為處理器不太會覆蓋有用的資訊。

Downpour SGD

Downpour SGD 是一個非同步的 SGD 法變體,它被 Dean 等人 [4] 用在了谷歌的 DistBelief 架構中(它是 TensorFlow 的前身)。他對訓練集地子集同步地執行模型的多個副本。這些模型將它們的更新值傳送到引數伺服器,伺服器被分為了許多臺主機。每一臺主機都負責儲存和上載模型的一部分引數。但是,副本之間卻沒有相互的通訊——例如,共享權重值或者更新值——其引數面臨著發散的風險,會阻止收斂。

容忍延遲的 SGD 演算法

McMahan 和 Streeter [12] 改良了 AdaGrad 法使之能夠用於平行運算的場景。通過實現延遲容忍的演算法,它不僅能能夠適應於過去的梯度,還能夠適應於更新的延遲。在實踐中,它的表現很好。

TensorFlow

TensorFlow[13] 是谷歌最近開源的一個實現和部署大規模機器學習模型的架構。它基於他們之前對於使用 DistBelief 的經驗,並已在內部被部署在一系列的移動裝置及大規模的分散式系統上進行計算。為了分散式執行,一個計算圖被分為了許多子圖給不同的裝置,裝置之間的通訊使用了傳送和接受節點對。2016 年 4 月 13 日更新:一個分散式 TensorFlow 的版本已經被髮布。

彈性平均梯度下降法(Elastic Averaging SGD)

張等人 [14] 提出了彈性平均梯度下降法(EASGD),他使不同工作機之間不同的 SGD 以一個「彈性力」連線,也就是一個儲存於引數伺服器的中心變數。這允許區域性變數比中心變數更大地波動,理論上允許了對引數空間更多的探索。他們的經驗表明,提高的探索能力有助於在尋找新的區域性極值中提升(優化器的)表現。

優化 SGD 的其他手段

最後,我們將討論一些其他手段,他們可以與前述的方法搭配使用,並能進一步提升 SGD 的效果。你可以參考 [22],以瞭解一些其他常用策略。

重排法(Shuffling)和遞進學習(Curriculum Learning)

總體而言,我們希望避免訓練樣本以某種特定順序傳入到我們的學習模型中,因為這會向我們的演算法引入偏差。因此,在每次迭代後,對訓練資料集中的樣本進行重排(shuffling),會是一個不錯的注意。

另一方面,在某些情況下,我們會需要解決難度逐步提升的問題。那麼,按照一定的順序遍歷訓練樣本,會有助於改進學習效果及加快收斂速度。這種構建特定遍歷順序的方法,叫做遞進學習(Curriculum Learning)[16]。*這個詞目前沒有標準翻譯,我根據表意和意義翻譯成這個。

Zaremba 和 Sutskever [17] 僅使用了遞進學習法訓練 LSTMs 來學習簡單的專案,但結果表明,遞進學習法使用的混合策略的表現好於樸素策略——後者不斷地重排資料,反而增加了學習過程的難度。

批量標準化(Batch Normalization)

我們通常設定我們引數初值的均值和方差分別為 0 和單位值,以幫助模型進行學習。隨著學習過程的進行,每個引數被不同程度地更新,相應地,引數的正則化特徵也隨之失去了。因此,隨著訓練網路的越來越深,訓練的速度會越來越慢,變化值也會被放大。

批量標準化 [18] 對每小批資料都重新進行標準化,並也會在操作中逆傳播(back-propgate)變化量。在模型中加入批量標準化後,我們能使用更高的學習率且不要那麼在意初始化引數。此外,批量正則化還可以看作是一種正則化手段,能夠減少(甚至去除)留出法的使用。

早停(Early Stopping)

誠如 Geoff Hinton 所言:「Early stopping (is) beautiful free lunch(早停是美妙的免費午餐,又簡單效果又好)」(NIPS 2015 Tutorial Sildes, Slide 63)。在訓練過程中,你應該時刻關注模型在驗證集上的誤差情況,並且在改誤差沒有明顯改進的時候停止訓練。

梯度噪聲(Gradient Noise)

Neelakentan 等人 [21] 在每次梯度的更新中,向其中加入一個服從合高斯分佈 N(0,σ^2) 的噪聲值:

blob.png

並按照如下的方式修正方差:

blob.png

他們指出,這種方式能夠提升神經網路在不良初始化前提下的魯棒性,並能幫助訓練特別是深層、複雜的神經網路。他們發現,加入噪聲項之後,模型更有可能發現並跳出在深度網路中頻繁出現的區域性最小值。

結論

在本文中,我們首先分析了梯度下降法的三個變體,在其中小批量梯度下降法最受歡迎。接著,我們研究了常用的優化 SGD 的演算法,包括:動量法、Nesterov accelerated gradient 法、Adagrad 法、Adadelta 法、RMSprop 法、Adam 法及其他優化非同步 SGD 的演算法。最終,我們討論了另外一些改進 SGD 的策略,包括樣本重排法(shuffling)、遞進學習(curriculum learning)、批量標準化(Batch Normali·zation)及早停(early stopping)等。

我希望本文能增進讀者關於這些優化演算法的認識,能對這些演算法的行為與動機有一個瞭解。也許我遺漏了一些常用的優化 SGD 的演算法,或是你有一些自己使用 SGD 訓練的技巧。如果有的話,請在下方留言區留言讓我知道。