1. 程式人生 > >深度學習與計算機視覺(PB-07)-優化演算法

深度學習與計算機視覺(PB-07)-優化演算法

在之前的章節中,我們只研究和使用了隨機梯度下降法(SGD)來優化網路模型,但是,在深度學習中還有其他高階的優化演算法,這些高階方法可以加速訓練過程或者提高準確度:

  • 在可接受的準確度下,高階演算法可以減少訓練時間(比如更少的迭代次數epochs)。
  • 模型可以更好的適應其他超引數,而不僅僅是學習率。
  • 理想情況下,可以獲得比SGD更高的分類準確度。

隨著深度學習的不斷髮展,新的優化技術層出不窮,每一種新的優化技術都試圖改進SGD演算法,並且可以自適應學習速率。正如我們所知道的,在給定學習率情況下,SGD演算法對網路中的所有引數進行同等的優化。但是,考慮到學習率既是優化網路過程中最重要的引數之一,又很難把握學習率的大小。因此,相關學者提出了,隨著網路訓練的進行,可以自適應地調整學習速率(某些情況下,可能是每一個超引數)的演算法。

在本章中,我們將回顧自適應學習率相關演算法。

自適應學習率

為了理解本節中的每一種優化演算法,我們將用虛擬碼——特別是更新步驟,來表示。本章的大部分內容來自於Karpathy[26]和Ruder[27]對優化方法的概述文章。在此基礎上,對原文描述內容做一定的修改,使內容更易於理解。

Vanilla SGD

首先,讓我們看一看我們已經熟悉的演算法—— Vanilla SGD(就是我們常見的批量梯度下降法)的更新階段:

W += -lr * dW

其中:

  • W:模型權重矩陣
  • lr::學習率
  • dW:W的梯度

學習率lr是固定的。當然只要學習率足夠小,模型的loss會在訓練中減少[太大可能出現loss增大情況]。在之前訓練模型過程中,我們也使用了SGD的擴充套件,如momentum和Nesterov。

具體的隨機梯度下降法流程,可以檢視圖7.1:

圖7.1 SGD演算法流程

Adagrad

我們將要學習的第一個自適應學習速率方法是Adagrad,由Duchi[28]等人提出。Adagrad是解決不同引數應該使用不同的更新速率的問題。Adagrad自適應地為各個引數分配不同學習率的演算法。對於某些變數,可能已經優化到了極小值附近,但是,有的變數仍然處在梯度很大的地方,這時候一個統一的全域性學習率是可能出現問題的。如果學習率太小,則梯度很大的變數會收斂很慢,如果梯度太大,已經優化差不多的變數可能會不穩定。AdaGrad的基本思想是對每個變數用不同的學習率,這個學習率在一開始比較大,用於快速梯度下降。隨著優化過程的進行,對於已經下降很多的變數,則減緩學習率,對於還沒怎麼下降的變數,則保持一個較大的學習率。

下面我們可以看到Adagrad更新的偽程式碼表示:

cache += (dW ** 2)
w += -lr * dW / (np.sqrt(cache) + eps)

你會發現第一個引數是cache——這個變數主要是在mini-batch更新過程中,計算每個引數的梯度的平方和[累加和]。通過cache變數,我們可以看到哪些引數經常更新,哪些引數不經常更新。第2行程式碼,我們將lr * dW除以cache的平方根(eps一般是一個很小的值,作用是防止分母為0)。不同的引數,其cache值是不同的,因此通過cache,我們可以自適應地更新網路中的引數。從上虛擬碼中可以看到,隨著優化過程的進行,對於已經下降很多的變數,則減緩學習率,對於還沒怎麼下降的變數,則保持一個較大的學習率。Adagrad的主要好處是,我們不再需要手動調優學習率——大多數實踐中,Adagrad演算法的初始學速率一般設定為0.01,並允許演算法在每個引數的調優學習速率。

在機器學習的應用中,Adagrad非常適合樣本稀疏的問題,因為稀疏的樣本下,每次梯度下降的方向,以及涉及的變數都可能有很大的差異。Adagrad的缺點是雖然不同變數有了各自的學習率,但是初始的全域性學習率還是需要手工指定。如果全域性學習率過大,優化同樣不穩定;而如果全域性學習率過小,我們知道的,將一個小數字(梯度)除以一個很大的數字(cache)將會得到一個非常小的值,因為Adagrad的特性,隨著優化的進行,學習率會越來越小,很可能還沒有到極值就停滯不前了,網路的更新能力會越來越弱,能學到的更多知識的能力也越來越弱。

總的來說,我們發現Adagrad存在問題,即隨著優化的進行,分母中的平方梯度累加和cache不斷變大,整個訓練過程中的學習率將繼續下降,最終降至零,完全停止訓練,這就是為什麼現在我們很少看到Adagrad用於訓練深度神經網路。但是,有必要回顧一下,以便我們能夠理解Adagrad演算法的擴充套件。

具體的Adagrad演算法流程,可以檢視圖7.2:

圖7.2 Adagrad演算法流程

Adadelta

Adadelta演算法是由Zeiler在2012年的論文《ADADELTA: An Adaptive Learning Rate Method 》[29]提出。Adadelta是對Adagrad的擴充套件,以處理Adagrad學習率一直單調遞減的問題。

在Adagrad演算法中,Adagrad會累加之前所有的梯度平方,即cache會不斷的增加。但是,Adadelta只累加固定大小的項,並且也不直接儲存這些項。僅僅是近似計算對應的平均值——實際實現時,梯度和是遞迴的定義成歷史梯度平方的衰減平均值。即:

n t = v n t 1 + ( 1 v ) g t 2 n_{t} = v * n_{t-1} + (1- v) * g^2_{t}

Δ θ t = η n t + ϵ g t \Delta \theta_{t} = - \frac{\eta}{\sqrt{n_{t} + \epsilon}} * g_{t}

因此,Adadelta可以被視為Adagrad的改進,然而,與之密切相關的RMSprop演算法(它也執行cache衰減)通常比Adadelta更受歡迎。

RMSprop

RMSprop演算法是一個非常高效的演算法,它是Geoffrey Hinton在Coursera課程[2]中提到的一種(未發表的)優化演算法。與Adadelta類似,RMSprop試圖通過將對cache計算指數加權移動平均而不是計算所有過去cache的累加帶來的負面影響。

讓我們來看看RMSprop的更新過程虛擬碼:

cache = decay_rate * cache + (1 - decay_rate) * (dW **2)
W += - lr *dW / (np.sqrt(cache) + eps)

你會注意到,RMSprop對權重矩陣W的更新與Adagrad的更新是一樣的——主要是cache的更新。其中decay_rate,通常定義為 ρ \rho ,一般設定為0.9。而唯一不同的是就在於累積平方梯度的求法不同。RMSProp演算法不是像AdaGrad演算法那樣暴力直接的累加平方梯度,而是加了一個衰減係數來控制歷史資訊的獲取多少。見下:

γ ρ γ + ) 1 ρ ) g g \gamma \leftarrow \rho \gamma + )1-\rho) g \odot g

鑑於神經網路都是非凸條件的,RMSProp在非凸條件下結果更好。通過指數衰減的移動平均計算梯度累積,可以丟棄時間間隔較大的歷史資訊。經驗上,RMSProp被證明是一個有效且實用的深度學習優化演算法。

除了SGD,RMSprop可以說是最近深度學習文獻中使用最多的優化演算法,然而,我們將要討論的下一個優化方法——Adam,現在使用更多。

具體的RMSprop演算法流程,可以檢視圖7.3:

圖7.3 RMSprop演算法流程

Adam

Kingma和Ba在2014年的論文《Adam: A Method for Stochastic Optimization》中提出的Adam(自適應矩估計)優化演算法,本質上只是添加了動量的RMSprop。具體的更新虛擬碼如下:

m = beta1 * m + (1-beta1) * dW
v = beta2 * v + (1- beta2) * (dW ** 2)
x += -lr * m / (np.sqrt(v) +eps)

m和v的值類似於SGD的momentum,依賴於t-1時刻之前的值,m表示梯度的第一時刻平均值,v表示梯度的第二時刻非中心方差值。

Adam演算法同時獲得了 AdaGrad 和 RMSProp 演算法的優點。Adam 不僅如 RMSProp 演算法那樣基於一階矩均值計算適應性引數學習率,它同時還充分利用了梯度的二階矩均值(即有偏方差/uncentered variance)。具體來說,Adam演算法計算了梯度的指數移動均值(exponential moving average),其中由超引數 beta1 和 beta2 控制了這些移動均值的衰減率。

具體的Adam演算法流程,可以檢視圖7.4:

圖7.4 Adam演算法流程
在實際應用中,Adam方法效果良好。與其他自適應學習率演算法相比,其收斂速度更快,學習效果更為有效,而且可以糾正其他優化技術中存在的問題,如學習率消失、收斂過慢或是高方差的引數更新導致損失函式波動較大等問題。

Nadam

就像Adam是帶有momentum的RMSprop, Nadam是帶有Nesterov加速度的RMSprop。Nadam是由斯坦福大學的博士生Timothy Dozat提出的。我們通常不會看到在實際應用中使用Nadam,但重要的是要理解Adam的擴充套件確實存在。

如何選擇優化演算法

給定所有優化演算法,您應該選擇哪個?其實答案是非常不確定——2014年,Schaul等人在2014發表的《Unit tests for Stochastic Optimization》,其中試圖對許多優化方法進行了測試,發現自適應學習率演算法表現良好,但沒有明確的哪一個是最好的。

深度學習優化演算法(以及如何選擇它們)仍然是一個開放的研究領域,而且可能會持續很多年。因此,與其針對資料嘗試每一種優化演算法,然後找到一個有用的,還不如掌握兩種或三種優化演算法。深度學習專案的成功通常是優化演算法(以及相關引數)和研究人員如何熟練地“驅動”演算法的結合。

應該瞭解的三種優化演算法: SGD, Adam, and RMSprop

考慮到自適應學習率演算法(如RMSprop和Adam)的成功,你可能會忽略SGD演算法,把它當作一種過時的工具。畢竟,“更好”的方法還是存在的,不是嗎?

然而,忽視SGD演算法將是一個巨大的錯誤。看看最近關於影象分類資料集的最新的深度學習演算法,比如ImageNet: AlexNet[6], VGGNet[11], squeezeNet[32], Inception[17], ResNet[33]——這些最新的網路結構都是使用SGD進行訓練的

既然自適應學習率演算法很好,為什麼還使用SGD進行訓練呢?我們可以清楚地看到,應用自適應學習速率演算法(如RMSprop和Adam ),可以讓網路更快地收斂。然而,收斂速度雖然重要,但並不是最重要的因素——模型的超引數仍然更加重要。在給定優化器(以及相關的模型)情況下,如果你不能將超引數調優到最佳,那麼你的網路將永遠不會獲得合理的準確度。

雖然SGD的收斂速度比自適應學習速率演算法要慢,但它也是一個更深入研究的演算法。研究人員對SGD更為熟悉,多年來一直使用它來訓練網路。

例如,一位職業賽車手,他駕駛同一款賽車的車型和型號已經有五年了。然後,有一天,司機的贊助商改變了主意,逼他們開一輛新車且沒有時間練習新的賽車,車手會在他們的前幾場比賽中表現出色嗎?最可能的情況是,車手對車輛並不熟悉(但由於車手畢竟是專業人士,所以仍可能表現得比較合理)。

深度學習架構和優化演算法也是如此。我們對給定的網路體系結構和優化演算法進行的實驗越多,我們就越能瞭解訓練過程的複雜性。近60年以來,訓練神經網路的演算法基本都是以SGD為主,毫無疑問,SGD演算法至今仍然在沿用——與模型的效能(準確度)相比,它的收斂速度並不重要。

簡單地說:如果我們使用SGD演算法在給定的資料集上獲得更高的準確度,我們很可能會使用SGD,即使訓練時間比使用Adam或RMSprop要慢1.5倍,因為我們更好地理解了模型的超引數。目前最常用的深度學習優化演算法有:

  • SGD
  • RMSprop
  • Adam

在對新資料集建模或者新的模型測試時,建議優先使用SGD演算法。在某些情況下。它可能會獲得很好的效果,當然,也存在某些情況下,結果很差。你可以通過特定的優化演算法瞭解更多的深度學習問題,以及對相關超引數進行調優。記住,深度學習既是科學又是藝術——掌握優化演算法絕對是一門需要大量實踐的藝術。通過本文,你還可以選擇RMSprop或Adam。

我個人建議在優先學習Adam,以我的經驗來看,在大多數情況下,Adam的效能都要優於RMSprop。

總結

在本章中,我們討論了自適應學習速率優化演算法。選擇哪種優化演算法來訓練深度神經網路是高度依賴於你是否對:

  • 資料的熟悉
  • 網路結構的熟悉
  • 優化演算法的熟悉(包括相關的超引數)

與其盲目地嘗試各種優化演算法,還不如熟練掌握兩三中優化演算法,以及如何調優相關的超引數。精通這些優化演算法將使你能夠更輕鬆地將新的模型體系結構應用到以前從未使用過的資料集。

我個人的建議是,在你剛開始學習深度學習時,多花時間去掌握如何使用SGD,尤其是帶有動量的SGD。一旦你覺得可以將SGD應用到各種架構和資料集上,那麼就可以學習Adam和RMSprop。

最後,請記住,模型收斂速度僅次於損失和精度——選擇一個你可以熟練的調優超引數的優化演算法,這樣你可以得到一個高效能的網路模型。