各種優化方法總結比較(sgd/momentum/Nesterov/adagrad/adadelta)


前言

這里討論的優化問題指的是,給定目標函數f(x),我們需要找到一組參數x,使得f(x)的值最小。

本文以下內容假設讀者已經了解機器學習基本知識,和梯度下降的原理。

SGD

SGD指stochastic gradient descent,即隨機梯度下降。是梯度下降的batch版本。

對於訓練數據集,我們首先將其分成n個batch,每個batch包含m個樣本。我們每次更新都利用一個batch的數據,而非整個訓練集。即: 

xt+1=xt+Δxt

Δxt=ηgt

其中, η 為學習率, gt 為x在t時刻的梯度。

這么做的好處在於:

  • 當訓練數據太多時,利用整個數據集更新往往時間上不顯示。batch的方法可以減少機器的壓力,並且可以更快地收斂。
  • 當訓練集有很多冗余時(類似的樣本出現多次),batch方法收斂更快。以一個極端情況為例,若訓練集前一半和后一半梯度相同。那么如果前一半作為一個batch,后一半作為另一個batch,那么在一次遍歷訓練集時,batch的方法向最優解前進兩個step,而整體的方法只前進一個step。

Momentum

SGD方法的一個缺點是,其更新方向完全依賴於當前的batch,因而其更新十分不穩定。解決這一問題的一個簡單的做法便是引入momentum。

momentum即動量,它模擬的是物體運動時的慣性,即更新的時候在一定程度上保留之前更新的方向,同時利用當前batch的梯度微調最終的更新方向。這樣一來,可以在一定程度上增加穩定性,從而學習地更快,並且還有一定擺脫局部最優的能力: 

Δxt=ρxt1ηgt

其中, ρ  即momentum,表示要在多大程度上保留原來的更新方向,這個值在0-1之間,在訓練開始時,由於梯度可能會很大,所以初始值一般選為0.5;當梯度不那么大時,改為0.9。 η  是學習率,即當前batch的梯度多大程度上影響最終更新方向,跟普通的SGD含義相同。 ρ  與  η  之和不一定為1。

Nesterov Momentum

這是對傳統momentum方法的一項改進,由Ilya Sutskever(2012 unpublished)在Nesterov工作的啟發下提出的。

其基本思路如下圖(轉自Hinton的coursera公開課lecture 6a):

Nesterov Momentum

首先,按照原來的更新方向更新一步(棕色線),然后在該位置計算梯度值(紅色線),然后用這個梯度值修正最終的更新方向(綠色線)。上圖中描述了兩步的更新示意圖,其中藍色線是標准momentum更新路徑。

公式描述為: 

Δxt=ρxt1ηΔf(xt1+ρxt1)

Adagrad

上面提到的方法對於所有參數都使用了同一個更新速率。但是同一個更新速率不一定適合所有參數。比如有的參數可能已經到了僅需要微調的階段,但又有些參數由於對應樣本少等原因,還需要較大幅度的調動。

Adagrad就是針對這一問題提出的,自適應地為各個參數分配不同學習率的算法。其公式如下: 

Δxt=ηtτ=1gτ+ϵgt

其中 gt  同樣是當前的梯度,連加和開根號都是元素級別的運算。 eta  是初始學習率,由於之后會自動調整學習率,所以初始值就不像之前的算法那樣重要了。而 ϵ 是一個比較小的數,用來保證分母非0。

其含義是,對於每個參數,隨着其更新的總距離增多,其學習速率也隨之變慢。

Adadelta

Adagrad算法存在三個問題

  • 其學習率是單調遞減的,訓練后期學習率非常小
  • 其需要手工設置一個全局的初始學習率
  • 更新 xt 時,左右兩邊的單位不同一

Adadelta針對上述三個問題提出了比較漂亮的解決方案。

首先,針對第一個問題,我們可以只使用adagrad的分母中的累計項離當前時間點比較近的項,如下式: 

E[g2]t=ρE[g2]t1+(1ρ)g2t

Δxt=ηE[g2]t+ϵgt

這里 ρ 是衰減系數,通過這個衰減系數,我們令每一個時刻的 gt 隨之時間按照 ρ 指數衰減,這樣就相當於我們僅使用離當前時刻比較近的 gt 信息,從而使得還很長時間之后,參數仍然可以得到更新。

針對第三個問題,其實sgd跟momentum系列的方法也有單位不統一的問題。sgd、momentum系列方法中: 

Δxgfx1x

類似的,adagrad中,用於更新 Δx 的單位也不是x的單位,二是1。

而對於牛頓迭代法: 

Δx=H1tgt

其中H為Hessian矩陣,由於其計算量巨大,因而實際中不常使用。其單位為: 
ΔxH1gfx2f2xx

注意,這里f無單位。因而,牛頓迭代法的單位是正確的。

所以,我們可以模擬牛頓迭代法來得到正確的單位。注意到: 

Δx=fx2f2x12f2x=Δxfx

這里,在解決學習率單調遞減的問題的方案中,分母已經是 fx 的一個近似了。這里我們可以構造 Δx 的近似,來模擬得到 H1 的近似,從而得到近似的牛頓迭代法。具體做法如下: 
Δxt=t1τ=1ΔxτE[g2]t+ϵ

可以看到,如此一來adagrad中分子部分需要人工設置的初始學習率也消失了,從而順帶解決了上述的第二個問題。

各個方法的比較

Karpathy做了一個這幾個方法在MNIST上性能的比較,其結論是: 
adagrad相比於sgd和momentum更加穩定,即不需要怎么調參。而精調的sgd和momentum系列方法無論是收斂速度還是precision都比adagrad要好一些。在精調參數下,一般Nesterov優於momentum優於sgd。而adagrad一方面不用怎么調參,另一方面其性能穩定優於其他方法。

實驗結果圖如下:

Loss vs. Number of examples seen 
Loss vs. Number of examples seen

Testing Accuracy vs. Number of examples seen 
Testing Accuracy vs. Number of examples seen

Training Accuracy vs. Number of examples seen這里寫圖片描述

其他總結文章

最近看到了一個很棒的總結文章,除了本文的幾個算法,還總結了RMSProp跟ADAM(其中ADAM是目前最好的優化算法,不知道用什么的話用它就對了)


 

隨機梯度下降(Stochastic gradient descent)和 批量梯度下降(Batch gradient descent )的公式對比、實現對比

梯度下降(GD)是最小化風險函數、損失函數的一種常用方法,隨機梯度下降和批量梯度下降是兩種迭代求解思路,下面從公式和實現的角度對兩者進行分析,如有哪個方面寫的不對,希望網友糾正。


下面的h(x)是要擬合的函數,J(theta)損失函數,theta是參數,要迭代求解的值,theta求解出來了那最終要擬合的函數h(theta)就出來了。其中m是訓練集的記錄條數,j是參數的個數。



1、批量梯度下降的求解思路如下:

(1)將J(theta)對theta求偏導,得到每個theta對應的的梯度

   

(2)由於是要最小化風險函數,所以按每個參數theta的梯度負方向,來更新每個theta


(3)從上面公式可以注意到,它得到的是一個全局最優解,但是每迭代一步,都要用到訓練集所有的數據,如果m很大,那么可想而知這種方法的迭代速度!!所以,這就引入了另外一種方法,隨機梯度下降。


2、隨機梯度下降的求解思路如下:

(1)上面的風險函數可以寫成如下這種形式,損失函數對應的是訓練集中每個樣本的粒度,而上面批量梯度下降對應的是所有的訓練樣本:


(2)每個樣本的損失函數,對theta求偏導得到對應梯度,來更新theta

(3)隨機梯度下降是通過每個樣本來迭代更新一次,如果樣本量很大的情況(例如幾十萬),那么可能只用其中幾萬條或者幾千條的樣本,就已經將theta迭代到最優解了,對比上面的批量梯度下降,迭代一次需要用到十幾萬訓練樣本,一次迭代不可能最優,如果迭代10次的話就需要遍歷訓練樣本10次。但是,SGD伴隨的一個問題是噪音較BGD要多,使得SGD並不是每次迭代都向着整體最優化方向。


3、對於上面的linear regression問題,與批量梯度下降對比,隨機梯度下降求解的會是最優解嗎?

(1)批量梯度下降---最小化所有訓練樣本的損失函數,使得最終求解的是全局的最優解,即求解的參數是使得風險函數最小。

(2)隨機梯度下降---最小化每條樣本的損失函數,雖然不是每次迭代得到的損失函數都向着全局最優方向, 但是大的整體的方向是向全局最優解的,最終的結果往往是在全局最優解附近。


4、梯度下降用來求最優解,哪些問題可以求得全局最優?哪些問題可能局部最優解?

對於上面的linear regression問題,最優化問題對theta的分布是unimodal,即從圖形上面看只有一個peak,所以梯度下降最終求得的是全局最優解。然而對於multimodal的問題,因為存在多個peak值,很有可能梯度下降的最終結果是局部最優。


5、隨機梯度和批量梯度的實現差別

以前一篇博文中NMF實現為例,列出兩者的實現差別(注:其實對應Python的代碼要直觀的多,以后要練習多寫python!)

[java]  view plain  copy
  1. // 隨機梯度下降,更新參數  
  2. public void updatePQ_stochastic(double alpha, double beta) {  
  3.     for (int i = 0; i < M; i++) {  
  4.         ArrayList<Feature> Ri = this.dataset.getDataAt(i).getAllFeature();  
  5.         for (Feature Rij : Ri) {  
  6.             // eij=Rij.weight-PQ for updating P and Q  
  7.             double PQ = 0;  
  8.             for (int k = 0; k < K; k++) {  
  9.                 PQ += P[i][k] * Q[k][Rij.dim];  
  10.             }  
  11.             double eij = Rij.weight - PQ;  
  12.   
  13.             // update Pik and Qkj  
  14.             for (int k = 0; k < K; k++) {  
  15.                 double oldPik = P[i][k];  
  16.                 P[i][k] += alpha  
  17.                         * (2 * eij * Q[k][Rij.dim] - beta * P[i][k]);  
  18.                 Q[k][Rij.dim] += alpha  
  19.                         * (2 * eij * oldPik - beta * Q[k][Rij.dim]);  
  20.             }  
  21.         }  
  22.     }  
  23. }  
  24.   
  25. // 批量梯度下降,更新參數  
  26. public void updatePQ_batch(double alpha, double beta) {  
  27.   
  28.     for (int i = 0; i < M; i++) {  
  29.         ArrayList<Feature> Ri = this.dataset.getDataAt(i).getAllFeature();  
  30.   
  31.         for (Feature Rij : Ri) {  
  32.             // Rij.error=Rij.weight-PQ for updating P and Q  
  33.             double PQ = 0;  
  34.             for (int k = 0; k < K; k++) {  
  35.                 PQ += P[i][k] * Q[k][Rij.dim];  
  36.             }  
  37.             Rij.error = Rij.weight - PQ;  
  38.         }  
  39.     }  
  40.   
  41.     for (int i = 0; i < M; i++) {  
  42.         ArrayList<Feature> Ri = this.dataset.getDataAt(i).getAllFeature();  
  43.         for (Feature Rij : Ri) {  
  44.             for (int k = 0; k < K; k++) {  
  45.                 // 對參數更新的累積項  
  46.                 double eq_sum = 0;  
  47.                 double ep_sum = 0;  
  48.   
  49.                 for (int ki = 0; ki < M; ki++) {// 固定k和j之后,對所有i項加和  
  50.                     ArrayList<Feature> tmp = this.dataset.getDataAt(i).getAllFeature();  
  51.                     for (Feature Rj : tmp) {  
  52.                         if (Rj.dim == Rij.dim)  
  53.                             ep_sum += P[ki][k] * Rj.error;  
  54.                     }  
  55.                 }  
  56.                 for (Feature Rj : Ri) {// 固定k和i之后,對多有j項加和  
  57.                     eq_sum += Rj.error * Q[k][Rj.dim];  
  58.                 }  
  59.   
  60.                 // 對參數更新  
  61.                 P[i][k] += alpha * (2 * eq_sum - beta * P[i][k]);  
  62.                 Q[k][Rij.dim] += alpha * (2 * ep_sum - beta * Q[k][Rij.dim]);  
  63.             }  
  64.         }  
  65.     }  
  66. }  



梯度下降法的缺點是:

  • 靠近極小值時速度減慢。
  • 直線搜索可能會產生一些問題。
  • 可能會'之字型'地下降。

 

三、隨機梯度下降法stochastic gradient descent,也叫增量梯度下降

由於梯度下降法收斂速度慢,而隨機梯度下降法會快很多

–根據某個單獨樣例的誤差增量計算權值更新,得到近似的梯度下降搜索(隨機取一個樣例)

–可以看作為每個單獨的訓練樣例定義不同的誤差函數

–在迭代所有訓練樣例時,這些權值更新的序列給出了對於原來誤差函數的梯度下降的一個合理近似

–通過使下降速率的值足夠小,可以使隨機梯度下降以任意程度接近於真實梯度下降

•標准梯度下降和隨機梯度下降之間的關鍵區別

–標准梯度下降是在權值更新前對所有樣例匯總誤差,而隨機梯度下降的權值是通過考查某個訓練樣例來更新的

–在標准梯度下降中,權值更新的每一步對多個樣例求和,需要更多的計算

–標准梯度下降,由於使用真正的梯度,標准梯度下降對於每一次權值更新經常使用比隨機梯度下降大的步長

–如果標准誤差曲面有多個局部極小值,隨機梯度下降有時可能避免陷入這些局部極小值中


[Machine Learning] 梯度下降法的三種形式BGD、SGD以及MBGD


在應用機器學習算法時,我們通常采用梯度下降法來對采用的算法進行訓練。其實,常用的梯度下降法還具體包含有三種不同的形式,它們也各自有着不同的優缺點。

下面我們以線性回歸算法來對三種梯度下降法進行比較。

一般線性回歸函數的假設函數為:

$h_{\theta}=\sum_{j=0}^{n}\theta_{j}x_{j}$

對應的能量函數(損失函數)形式為:

$J_{train}(\theta)=1/(2m)\sum_{i=1}^{m}(h_{\theta}(x^{(i)})-y^{(i)})^{2}$

下圖為一個二維參數($\theta_{0}$和$\theta_{1}$)組對應能量函數的可視化圖:

1. 批量梯度下降法BGD

批量梯度下降法(Batch Gradient Descent,簡稱BGD)是梯度下降法最原始的形式,它的具體思路是在更新每一參數時都使用所有的樣本來進行更新,其數學形式如下:

(1) 對上述的能量函數求偏導:

(2) 由於是最小化風險函數,所以按照每個參數$\theta$的梯度負方向來更新每個$\theta$:

具體的偽代碼形式為:

repeat{

(for every j=0, ... , n)

}

從上面公式可以注意到,它得到的是一個全局最優解,但是每迭代一步,都要用到訓練集所有的數據,如果樣本數目$m$很大,那么可想而知這種方法的迭代速度!所以,這就引入了另外一種方法,隨機梯度下降。

優點:全局最優解;

缺點:當樣本數目很多時,訓練過程會很慢。

從迭代的次數上來看,BGD迭代的次數相對較少。其迭代的收斂曲線示意圖可以表示如下:

2. 隨機梯度下降法SGD

由於批量梯度下降法在更新每一個參數時,都需要所有的訓練樣本,所以訓練過程會隨着樣本數量的加大而變得異常的緩慢。隨機梯度下降法(Stochastic Gradient Descent,簡稱SGD)正是為了解決批量梯度下降法這一弊端而提出的。

將上面的能量函數寫為如下形式:

利用每個樣本的損失函數對$\theta$求偏導得到對應的梯度,來更新$\theta$:

具體的偽代碼形式為:

1. Randomly shuffle dataset;

2.  repeat {

for i=1, ... , $m${

(for j=0, ... , $n$)

}

}

隨機梯度下降是通過每個樣本來迭代更新一次,如果樣本量很大的情況(例如幾十萬),那么可能只用其中幾萬條或者幾千條的樣本,就已經將theta迭代到最優解了,對比上面的批量梯度下降,迭代一次需要用到十幾萬訓練樣本,一次迭代不可能最優,如果迭代10次的話就需要遍歷訓練樣本10次。但是,SGD伴隨的一個問題是噪音較BGD要多,使得SGD並不是每次迭代都向着整體最優化方向。

優點:訓練速度快;

缺點:准確度下降,並不是全局最優。

從迭代的次數上來看,SGD迭代的次數較多,在解空間的搜索過程看起來很盲目。其迭代的收斂曲線示意圖可以表示如下:

3. 小批量梯度下降法MBGD

有上述的兩種梯度下降法可以看出,其各自均有優缺點,那么能不能在兩種方法之間取得一個折衷呢?即,算法的訓練過程比較快,而且也要保證最終參數訓練的准確率,而這正是小批量梯度下降法(Mini-batch Gradient Descent,簡稱MBGD)的初衷。

MBGD在每次更新參數時使用b個樣本(b一般為10),其具體的偽代碼形式為:

Sayb=10, m=1000.

Repeat{

for i=1, 11, 21, 31, ... , 991{

(for every j=0, ... , $n$)

}

}

4. 總結

Batch gradient descent:Use all examples in each iteration;

Stochastic gradient descent:Use 1 example in each iteration;

Mini-batch gradient descent:Use b examples in each iteration.







免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM