梯度下降優化方法概述

梯度下降是優化神經網絡和機器機器學習算法的首選優化方法。本文重度參考SEBASTIAN RUDER的文章。對于英文比較好的同學請直接閱讀原文。本文只為個人的學習總結,難免有所欠缺和不足。

一、梯度下降變種

根據訓練數據集的大小,梯度下降有三種變體,但是本質是一樣的,不一樣的是每次使用多少條樣本。如果內存一次可以計算所有樣本的梯度,稱為:批梯度下降(Batch gradient descent);如果內存一次只允許一個樣本,稱為:隨機梯度下降(Stochastic gradient descent);大部分時候,內存一次是可以計算部分樣本的,稱為:最小批梯度下降(Mini-batch gradient descent)。三種變體的數據表達如下:

1.1批梯度下降(Vanilla gradient descent,又稱Batch gradient descent)

\theta = \theta - \eta \cdot \nabla_\theta J( \theta)

1.2隨機梯度下降(Stochastic gradient descent)

\theta = \theta - \eta \cdot \nabla_\theta J( \theta; x^{(i)}; y^{(i)})

1.3最小批梯度下降(Mini-batch gradient descent)

\theta = \theta - \eta \cdot \nabla_\theta J( \theta; x^{(i:i+n)}; y^{(i:i+n)})

注意,在其他地方并沒對上述三種變體做嚴格區別,統稱為SGD(隨機梯度下降),下文其余部分,我們也不加區分,統稱為SGD

二、梯度下降的幾種優化方法

傳統的梯度下降法不能保證一個很好的收斂,而且有一些挑戰需要被解決。

  1. 選擇這個合適的學習率是比較困難的。特別是對一個新的模型和新數據集時候,我們是不知道選擇什么樣的學習率是合適的。只能不斷的去嘗試。
  2. 學習率調度算法可以在訓練的過程中去調整模型的學習率。模型一開始的時候可以使用大一點的學習率,后面再使用小一點的學習率去微調模型。更好的方法是一開始也用一個小的學習率去warm-up訓練,讓參數先適應數據集。但是無論哪種學習率調度算法都需要預先定義調度算法,這種方法也是沒有辦法很好的適應模型的特征的、
  3. 對每一個參數都使用同樣的學習率是不合適的。對于稀疏的數據或者特征非常不均衡的數據。最好是使用不同學習率學習不同頻率的特征。
  4. 另外的挑戰是對于高階非凸的損失函數,往往會陷于局部極值點。還有一種鞍點的情況,模型也是很難學習的。此時損失函數在各個方向的梯度接近于0。SGD是很難逃脫與鞍點或者局部極值點的。

針對上面的一些問題,慢慢出現了一些針對梯度下降的優化方法。
在介紹SGD變種之前。先給出各個變種的一般范式。后天的各個變種優化方法都離不開這個范式。

(1)計算目標函數關于參數的梯度

g_t = \nabla_\theta J( \theta)

(2)根據歷史梯度計算一階和二階動量(二階指的是梯度的平方)
m_t = \phi(g_1, g_2, ..., g_t) \\ v_t = \psi(g_1, g_2, ..., g_t)

(3)更新模型參數
\theta_{t+1}=\theta_t-\frac{1}{\sqrt{v_t+\epsilon}}m_t

2.1 動量法(Momentum)

v_t = \gamma v_{t-1} + \eta \nabla_\theta J( \theta) \\ \theta = \theta - v_t

做一個簡單的推導。

image.png

發現,參數\theta每次的更新量為之前的梯度和乘以一個常量。下圖坐標是樸樹SGD的圖示,右邊是加上動量的SGD圖示。發現在水平方向得到了加速,在豎直方向得到了收斂。所以如果之前1到t-1時刻的梯度方向比較一致,那么加了動量的SGD會在這個方向加速;如果之前時刻的梯度方向不太一致,或者說抖動的比較厲害;那么加了動量的SGD會在這個方向減速,也就是以更小的速度更新參數。
image.png

Adagrad

SGD、SGD-M都是相同的學習率更新參數。但是對于高頻出現的特征我們希望用更小的學習率更新參數。所以提出了自適應梯度更新方法Adagrad。Adagrad對于低頻出現的特征我們希望用更大的學習率更新參數。所以在稀疏數據的場景下Adagrad表現較好。Adagrad中的ada是adapt(自適應)的意思

\theta_{t+1, i} = \theta_{t, i} - \dfrac{\eta}{\sqrt{G_{t, ii} + \epsilon}} \cdot g_{t, i}

其中G_{t,ii}表示\theta過去所有時刻梯度平方和,注意分母是帶根號的,不帶根號效果會很差。
缺點:分母會越來越大,導致最后的學習率是無窮小的值。這樣模型就學不到東西了。

RMSprop

E[g^2]_t = 0.9E[g^2]_{t-1} + 0.1g^2_t \\ \theta_{t+1} = \theta_{t} - \dfrac{\eta}{\sqrt{E[g^2]_t} + \epsilon} g_t
從表達是可以看出RMSprop是為了解決Adagrad中學習率會越來越小的問題。RMSprop處理使用之前的累計額梯度平方和還使用了當前時刻的梯度平方。這樣就會防止學習率越來越小。

Adam

Adam可以認為是RMSprop和Momentum的結合。

m_t = \beta_1 m_{t-1} + (1 - \beta_1) g_t \\ v_t = \beta_2 v_{t-1} + (1 - \beta_2) g_t^2

其中m_0=0, v_0=0
由于\beta_1, \beta_2都是趨向于1的數,所以開始時刻m_t,v_t趨向于0的一端,導致一開始的時候梯度很小。所以作者Adam對上面的公式做了偏差矯正(bias-corrected)。公式如下

\hat{m}_t = \dfrac{m_t}{1 - \beta^t_1} \\ \hat{v}_t = \dfrac{v_t}{1 - \beta^t_2}

即在原來的基礎上除以1-\beta^t。 那么\hat{m}_0=g_1, 隨著t的變大,1-\beta^t趨向于1。即\hat{m}_t趨向于m_t
最終參數更新表達如下:

\theta_{t+1} = \theta_{t} - \dfrac{\eta}{\sqrt{\hat{v}_t} + \epsilon} \hat{m}_t

所以理論上Adam優化方法是比較好的優化方法。即加了動量,針對不同參數又使用了不同的學習率。當時在目前很多開源的代碼中,很多了大佬還是使用了SGD-M方法,并沒有使用Adam。關于這一點歡迎大家一起討論。

放一張經典的圖

contours_evaluation_optimizers.gif
v2-4a3b4a39ab8e5c556359147b882b4788_b.gif

參考文獻

  1. An overview of gradient descent optimization algorithms
  2. 從 SGD 到 Adam —— 深度學習優化算法概覽(一)
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容