1. 程式人生 > >如何選擇深度學習優化器

如何選擇深度學習優化器

from:https://blog.csdn.net/chenhaifeng2016/article/details/73382273

在很多機器學習和深度學習的應用中,我們發現用的最多的優化器是 Adam,為什麼呢?

下面是 TensorFlow 中的優化器, 
https://www.tensorflow.org/api_guides/python/train

在 keras 中也有 SGD,RMSprop,Adagrad,Adadelta,Adam 等: 
https://keras.io/optimizers/

我們可以發現除了常見的梯度下降,還有 Adadelta,Adagrad,RMSProp 等幾種優化器,都是什麼呢,又該怎麼選擇呢?

在 Sebastian Ruder 的這篇論文中給出了常用優化器的比較,今天來學習一下: 
https://arxiv.org/pdf/1609.04747.pdf

本文將梳理:

  • 每個演算法的梯度更新規則和缺點
  • 為了應對這個不足而提出的下一個演算法
  • 超引數的一般設定值
  • 幾種演算法的效果比較
  • 選擇哪種演算法

優化器演算法簡述

首先來看一下梯度下降最常見的三種變形 BGD,SGD,MBGD, 
這三種形式的區別就是取決於我們用多少資料來計算目標函式的梯度, 
這樣的話自然就涉及到一個 trade-off,即引數更新的準確率和執行時間。

1. Batch gradient descent

梯度更新規則:

BGD 採用整個訓練集的資料來計算 cost function 對引數的梯度:

缺點:

由於這種方法是在一次更新中,就對整個資料集計算梯度,所以計算起來非常慢,遇到很大量的資料集也會非常棘手,而且不能投入新資料實時更新模型

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

我們會事先定義一個迭代次數 epoch,首先計算梯度向量 params_grad,然後沿著梯度的方向更新引數 params,learning rate 決定了我們每一步邁多大。

Batch gradient descent 對於凸函式可以收斂到全域性極小值,對於非凸函式可以收斂到區域性極小值。

2. Stochastic gradient descent

梯度更新規則:

和 BGD 的一次用所有資料計算梯度相比,SGD 每次更新時對每個樣本進行梯度更新, 
對於很大的資料集來說,可能會有相似的樣本,這樣 BGD 在計算梯度時會出現冗餘, 
而 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

看程式碼,可以看到區別,就是整體資料集是個迴圈,其中對每個樣本進行一次引數更新。

缺點:

但是 SGD 因為更新比較頻繁,會造成 cost function 有嚴重的震盪。

BGD 可以收斂到區域性極小值,當然 SGD 的震盪可能會跳到更好的區域性極小值處。

當我們稍微減小 learning rate,SGD 和 BGD 的收斂性是一樣的。

3. Mini-batch gradient descent

梯度更新規則:

MBGD 每一次利用一小批樣本,即 n 個樣本進行計算。這樣它可以降低引數更新時的方差,收斂更穩定。另一方面可以充分地利用深度學習庫中高度優化的矩陣操作來進行更有效的梯度計算。

和 SGD 的區別是每一次迴圈不是作用於每個樣本,而是具有 n 個樣本的批次

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

​​​​​

超引數設定值:

n 一般取值在 50~256

缺點:

不過 Mini-batch gradient descent 不能保證很好的收斂性,

  1. learning rate 如果選擇的太小,收斂速度會很慢,如果太大,loss function 就會在極小值處不停地震盪甚至偏離。 
    有一種措施是先設定大一點的學習率,當兩次迭代之間的變化低於某個閾值後,就減小 learning rate,不過這個閾值的設定需要提前寫好,這樣的話就不能夠適應資料集的特點。

  2. 此外,這種方法是對所有引數更新時應用同樣的 learning rate,如果我們的資料是稀疏的,我們更希望對出現頻率低的特徵進行大一點的更新。

  3. 另外,對於非凸函式,還要避免陷於區域性極小值處,或者鞍點處,因為鞍點周圍的error 是一樣的,所有維度的梯度都接近於0,SGD 很容易被困在這裡。

鞍點就是:一個光滑函式的鞍點鄰域的曲線,曲面,或超曲面,都位於這點的切線的不同邊。

例如這個二維圖形,像個馬鞍:在x-軸方向往上曲,在y-軸方向往下曲,鞍點就是(0,0)


為了應對上面的三點挑戰就有了下面這些演算法。

[應對挑戰 1]

4. Momentum

SGD 在 ravines 的情況下容易被困住, ravines 就是曲面的一個方向比另一個方向更陡,這時 SGD 會發生震盪而遲遲不能接近極小值:

梯度更新規則:

Momentum 通過加入 γv_t−1 ,可以加速 SGD, 並且抑制震盪

當我們將一個小球從山上滾下來時,沒有阻力的話,它的動量會越來越大,但是如果遇到了阻力,速度就會變小。

加入的這一項,可以使得梯度方向不變的維度上速度變快,梯度方向有所改變的維度上的更新速度變慢,這樣就可以加快收斂並減小震盪。

超引數設定值:

一般 γ 取值 0.9 左右。

缺點:

這種情況相當於小球從山上滾下來時是在盲目地沿著坡滾,如果它能具備一些先知,例如快要上坡時,就知道需要減速了的話,適應性會更好。

5. Nesterov accelerated gradient

梯度更新規則:

用 θ−γv_t−1 來近似當做引數下一步會變成的值,則在計算梯度時,不是在當前位置,而是未來的位置上

超引數設定值:

γ 仍然取值 0.9 左右。

效果比較:

藍色是 Momentum 的過程,會先計算當前的梯度,然後在更新後的累積梯度後會有一個大的跳躍。

而 NAG 會先在前一步的累積梯度上(brown vector)有一個大的跳躍,然後衡量一下梯度做一下修正(red vector),這種預期的更新可以避免我們走的太快。

NAG 可以使 RNN 在很多工上有更好的表現。

目前為止,我們可以做到,在更新梯度時順應 loss function 的梯度來調整速度,並且對 SGD 進行加速。

我們還希望可以根據引數的重要性而對不同的引數進行不同程度的更新。

[應對挑戰 2]

6. Adagrad

這個演算法就可以對低頻的引數做較大的更新,對高頻的做較小的更新,也因此,對於稀疏的資料它的表現很好,很好地提高了 SGD 的魯棒性,例如識別 Youtube 視訊裡面的貓,訓練 GloVe word embeddings,因為它們都是需要在低頻的特徵上有更大的更新。

梯度更新規則:

其中 g 為:t 時刻引數 θ_i 的梯度

如果是普通的 SGD, 那麼 θ_i 在每一時刻的梯度更新公式為:

但這裡的 learning rate η 也隨 t 和 i 而變:

其中 G_t 是個對角矩陣, (i,i) 元素就是 t 時刻引數 θ_i 的梯度平方和。

Adagrad 的優點是減少了學習率的手動調節

超引數設定值:

一般 η 就取 0.01。

缺點:

它的缺點是分母會不斷積累,這樣學習率就會收縮並最終會變得非常小。

7. Adadelta

這個演算法是對 Adagrad 的改進,

和 Adagrad 相比,就是分母的 G 換成了過去的梯度平方的衰減平均值,

這個分母相當於梯度的均方根 root mean squared (RMS) ,所以可以用 RMS 簡寫:

其中 E 的計算公式如下,t 時刻的依賴於前一時刻的平均和當前的梯度:

梯度更新規則:

此外,還將學習率 η 換成了 RMS[Δθ],這樣的話,我們甚至都不需要提前設定學習率了:

超引數設定值:

γ 一般設定為 0.9,

8. RMSprop

RMSprop 是 Geoff Hinton 提出的一種自適應學習率方法。

RMSprop 和 Adadelta 都是為了解決 Adagrad 學習率急劇下降問題的,

梯度更新規則:

RMSprop 與 Adadelta 的第一種形式相同:

超引數設定值:

Hinton 建議設定 γ 為 0.9, 學習率 η 為 0.001。

9. Adam

這個演算法是另一種計算每個引數的自適應學習率的方法。

除了像 Adadelta 和 RMSprop 一樣儲存了過去梯度的平方 vt 的指數衰減平均值 ,也像 momentum 一樣保持了過去梯度 mt 的指數衰減平均值:

如果 mt 和 vt 被初始化為 0 向量,那它們就會向 0 偏置,所以做了偏差校正, 
通過計算偏差校正後的 mt 和 vt 來抵消這些偏差:

梯度更新規則:

超引數設定值:

建議 β1 = 0.9,β2 = 0.999,ϵ = 10e−8

實踐表明,Adam 比其他適應性學習方法效果要好。


效果比較

下面看一下幾種演算法在鞍點和等高線上的表現:

SGD optimization on saddle point

SGD optimization on loss surface contours

上面兩種情況都可以看出,Adagrad, Adadelta, RMSprop 幾乎很快就找到了正確的方向並前進,收斂速度也相當快,而其它方法要麼很慢,要麼走了很多彎路才找到。

由圖可知自適應學習率方法即 Adagrad, Adadelta, RMSprop, Adam 在這種情景下會更合適而且收斂性更好。


如何選擇

如果資料是稀疏的,就用自適用方法,即 Adagrad, Adadelta, RMSprop, Adam。

RMSprop, Adadelta, Adam 在很多情況下的效果是相似的。

Adam 就是在 RMSprop 的基礎上加了 bias-correction 和 momentum,

隨著梯度變的稀疏,Adam 比 RMSprop 效果會好。

整體來講,Adam 是最好的選擇。

很多論文裡都會用 SGD,沒有 momentum 等。SGD 雖然能達到極小值,但是比其它演算法用的時間長,而且可能會被困在鞍點。

如果需要更快的收斂,或者是訓練更深更復雜的神經網路,需要用一種自適應的演算法。