梯度下降最常見的三種變形是BGD,SGD,MBGD,區別是梯度下降時用多少數據來計算目標函數的梯度。
批量梯度下降法(Batch Gradient Descent)更新參數時使用所有樣本來進行更新。
隨機梯度下降法(Stochastic Gradient Descent)更新參數時使用一個樣本來進行更新。(但平時提到的SGD是指的Mini-batch SGD)。
小批量梯度下降法(Mini-batch Gradient Descent)對於m個樣本的訓練集,更新參數時使用n樣本來進行更新,1<n<m:
批量梯度下降法和隨機梯度下降法對比:
- 訓練速度:隨機梯度下降法由於每次僅僅採用一個樣本來迭代,訓練速度很快,而批量梯度下降法在樣本量很大時,訓練速度稍慢。
- 收斂速度:由於隨機梯度下降法一次迭代一個樣本,導致迭代方向變化很大,不能很快的收斂到局部最優解。
- 準確度:BGD對於凸函數可以收斂到全局最優解,對於非凸函數可以收斂到局部最優解。隨機梯度下降法用於僅僅用一個樣本決定梯度方向,導致解很有可能不是最優。SGD每次使用一個樣本進行梯度計算方差比較大,目標函數波動比較大,但因此可以帶來波動,使優化的方向從當前的局部極小值跳到另一個更好的局部極小值,學習率足夠小時,SGD可以收斂到BGD一樣的效果。
- 在線學習:BGD不支持在線更新,SGD支持在線更新。
- 內存佔用:BGD數據集大到無法放入內存中時就不再適用。
小批量梯度下降法優勢:結合了BGD與SGD的優點每一次利用一小批樣本進行梯度的更新,既可以保證參數優化方向的穩定性,目標函數不會出現劇烈震盪,同時又能加快收斂速度,減小計算量。
缺點:
- 不能保證很好的收斂性,學習率太小,收斂速度會很慢,如果太大,損失函數在極小值處發生震盪甚至偏離。(可以先設定大一點的學習率,當兩次迭代之間的變化低於某個閾值後,就減小學習率)。對於非凸函數,還要避免陷於局部極小值處,或者鞍點處,因爲鞍點周圍的error是一樣的,所有維度的梯度都接近於0,SGD 很容易被困在這裏。(會在鞍點或者局部最小點震盪跳動,因爲在此點處,如果是訓練集全集帶入即BGD,則優化會停止不動,如果是mini-batch或者SGD,每次找到的梯度都是不同的,就會發生震盪,來回跳動。)
- SGD對所有參數更新時應用同樣的 learning rate,如果我們的數據是稀疏的,我們更希望對出現頻率低的特徵進行大一點的更新。LR會隨着更新的次數逐漸變小。
鞍點:一個光滑函數的鞍點鄰域的曲線,曲面,或超曲面,都位於這點的切線的不同邊。例如這個二維圖形,像個馬鞍:在x-軸方向往上曲,在y-軸方向往下曲,鞍點就是(0,0)。
爲了應對上面的兩點挑戰就有了下面這些算法。
梯度下降法改進
在深度學習優化算法中,Momentum、RMSprop、Adam都涉及指數加權平均,它對趨勢的一種刻畫:
其中,θt是第t時刻的實際值,vt近似爲t時刻1/(1-β)個θ的指數加權平均值,如當β=0.1時,vt代表了近10天的平均值;β=0.02時,vt近似代表了近50天的平均值,如圖,紅色是β=0.1、綠色是β=0.02時vt的變化,藍色爲真實值。其實,Vt不僅僅包含這個窗口內的值,它包含從t=0開始的所有值的加權平均。但之前的那些值都太小可以忽略。:
偏差修正(Bias correction):使用指數加權平均時每個最新數據值,依賴於以前的數據結果,在最開始的階段,沒有足夠的數據組成window_size,最開始的平均值求出來都偏小。如果v0=0,那麼v1 = (1-β)*θ1,特別地,如果β=0.9,那麼v1 = 0.1 * θ1,這樣導致v1會特別小,需要進行一定程度的修正, 具體的修正方法是對vt除以( 1-β^t),當t特別小的時候,可以起到較爲明顯的修正效果,但是當t變大時,分母接近於1,基本沒有進行修正。Vt變爲 Vt = Vt / (1 -
β ^ t)
。這樣最開始t比較小,Vt就會大一些。隨着t的增大β^t
逐漸變爲0,Vt也就恢復成原來的樣子了。
動量梯度下降法(Momentum)
基本思想:計算梯度的指數加權平均數,並利用該梯度更新權重。假設我們使用梯度下降法更新參數的路徑如下圖中藍色的線所示:
SGD遇到某個維度梯度比較大會被大梯度方向帶着一直往那邊走,但是這不一定是最快的下降方向。表現出來就是猶豫不決,來回波動,收斂很慢。當在不同方向上梯度相差非常大,會來回波動。而且你不能用比較大的學習速率,可能會直接超出函數的範圍。只能用較小的學習率,導致學習非常慢。
不關心之前的梯度是多少,如果本地梯度很小,它就會走的很慢。
會發生震盪而遲遲不能接近極小值。路徑上下波動減慢了梯度下降法的速度,如果用更大的學習率,可能導致這種波動進一步加大,變成圖中的紫色的線。因此,我們希望在縱軸上學習慢一點,消除這種上下的擺動,在橫軸上,希望快速從左向右移動,移動到最小值處。
因爲,觀察可以發現縱軸分量時而向上,時而向下,取平均值就比較小了。而橫軸分量一直是向右的,取平均值不會造成太大影響。這就是Momentum的原理。使用Momentum之後的效果:收斂更快
Momentum優化關注以前的梯度是多少,它將梯度當做加速度來使用,想象一個保齡球在光滑的表面滾下一個平緩的斜坡:最開始很慢,但速度會越來越快,爲了模擬某種摩擦機制並防止動量增長多大,該算法引入了一個新的超參數β,簡稱動量,其必須設置在0(高摩擦),1(無摩擦)之間。一個推薦的值爲0.9
指數加權平均數,可以反映近一段時間的趨勢,在縱軸上的上下波動,使得平均值接近於0,而在橫軸方向的平均值仍然較大。
公式 Momentum 通過加入 γ*vt−1 ,可以加速 SGD, 並且抑制震盪
其中,beta一般取值0.9,是指數加權平均的參數。alpha是學習速率。
優點
- 相比SGD,獲得更快的收斂速度,減小震盪。如果在峽谷地區(某些方向較另一些方向上陡峭得多,常見於局部極值點),SGD會在這些地方附近振盪,從而導致收斂速度慢。這種情況下,動量(Momentum)便可以解決。動量在參數更新項中加上一次更新量(即動量項,相當於指數加權平均),
- 對方向一致的參數能夠加速學習,對梯度改變方向的參數能夠減少其更新,因此就是momentum能夠在相關方向上加速學習,抑制振盪,從而加速收斂。
缺點
- 小球總是跟着斜坡走,沒有考慮斜坡之後的變化趨勢。到達最優解之後,還在繼續大幅度更新,會越過最優解。這種情況相當於小球從山上滾下來時是在盲目地沿着坡滾,如果它能具備一些先知,例如快要上坡時,就知道需要減速了的話,適應性會更好。
- 增加了一個超參數來微調,一般情況下,推薦β爲0.9
當我們將一個小球從山上滾下來時,沒有阻力的話,它的動量會越來越大,但是如果遇到了阻力,速度就會變小。
加入的這一項,可以使得梯度方向不變的維度上速度變快,梯度方向有所改變的維度上的更新速度變慢,這樣就可以加快收斂並減小震盪。
Adagrad
前面的算法在每次更新時,所有的參數學習速率都是相同的。Adagrad在每一個更新步驟中對於每一個模型參數θi使用不同的學習速率ηi,不同參數的學習速率是不同的。
Adagrad可以在每一個時刻t針對每一個參數使用不一樣的學習速率。對於梯度比較大的地方使用較小的學習速率,對於梯度比較小的地方使用較大的學習速率。因此,AdaGrad非常適合於處理稀疏數據。
在每一個時刻t針對每一個參數的更新學習速率的調節是利用該參數的歷史梯度信息來完成的。
G是對應的參數i到目前時刻t位置的梯度g的平方的和,epsilon爲常數防止除0,一般爲1e-7,1e-8。另外,如果不做開方操作,算法的效果會非常差。
優點:算法利用歷史的梯度信息自動調節學習率,省去了人工調整學習速率的煩惱。
缺點:分母上對梯度平方的不斷累加,累加值會隨着訓練不斷的增加,使得學習速率不斷的減小,直到無限小模型學習不到任何東西爲止
RMSprop(root mean square prop)
爲了降低Adagrad中學習速率衰減過快,在後期學習率可能無限小導致找不到有用的解的問題。RMSprop在Adagrad的基礎上使用梯度平方的指數加權平均來代替累加梯度的平方和。變量s可以看做是最近1/(1-gamma)
個時刻的g平方的加權平均。參數的學習速率不會再一直下降了。
RMSprop 在mini batch中計算梯度g,然後對該梯度按照元素進行平方,記爲,然後其進行指數加權平均,記爲s:然後,和Adagrad一樣,將每個參數的學習速率調整一遍,同樣是按元素操作:
eta爲初始學習速率。和Adagrad一樣,每個參數都擁有自己的學習速率。
優點
- 參數學習率避免了在訓練過程中一直下降的問題。
- RMSprop改進了Adagrad學習速率衰減過快的問題,同時其適用於處理非平穩。
缺點:依然依賴一個全局學習率。
對梯度較大的方向減小其學習速率,在梯度較小的方向上增加其學習速率。
假設縱軸代表參數b,橫軸代表參數W:減緩?方向的學習,即縱軸方向,同時加快,至少不是減緩橫軸方向的學習, RMSprop 算法可以實現這一點,將趨勢變成下面的綠色的線:
Adam(Adaptive Moment Estimation)
Adam普適性強,效果好,速度也很快。Adam是組合了Momentum 和 RMSprop的優化算法。使用了Momentum動量變量v和RMSprop按梯度平方的指數加權平均變量s,並將它們初始化爲0。在每次迭代中,首先計算梯度g,並遞增迭代次數:
和Momentum類似,給定超參數(作者建議0.9),對梯度g進行指數加權平均得到動量變量v:
和RMSprop一樣,給定超參數(作者建議0.999),對梯度g的平方進行指數加權平均得到s:
v和s可以近似看做最近1/(1-beta1)
個時刻梯度g和最近1/(1-beta2)
個時刻梯度g的平方的加權平均。假設beta1=0.9, beta2=0.999,v和s都初始化爲0,那麼在時刻t=1我們得到v=0.1g, s=0.001g
。可以看到,在迭代的初期,v和s可能過小而無法準確的估計g和g的平方。爲此,Adam使用了Bias Correction:
在迭代初期t比較小,上式分母接近於0,相當於放大了v和s。在迭代後期,分母接近於1,偏差修正幾乎不再有影響。它使用的是經過偏差修正後的指數加權平均數
接下來,Adam使用偏差修正後的v和s,重新調整每個參數的學習速率:
最後,更新參數:
總結
主要從兩個出發點來提出優化算法:
- 調整更新的步長。比如SGD是梯度g;Momentum是g的指數加權平均;NAG是改進的Momentum,利用之後的梯度信息,提前剎車;
- 調整學習速率,每個參數都有自己的學習速率。比如Adagrad使用梯度平方的累加和調整;RMSprop使用梯度平方的指數加權平均調整;Adadelta使用梯度平方的指數加權平均,再加上參數改變量平方的指數加權平均來調整;
目標:優化收斂速度
優化算法 | 備註 |
---|---|
SGD | 最樸素的優化算法,梯度直接作爲改變量 |
Momentum | 改進SGD: 使用梯度進行指數加權平均,作爲新的改變量 |
NAG | 改進Momentum: 先用上一個時刻的改變量近似得到下一時刻的位置,再使用該時刻的梯度進行指數加權平均,作爲最終的改變量 |
目標:每個參數都有自己的學習率
優化算法 | 備註 |
---|---|
Adagrad | 使用梯度平方累加和,再開根號作爲分母;初始eta爲分子;來調整學習速率 |
RMSprop | 改進Adagrad: 使用梯度平方的指數加權平均,再開根號作爲分母;初始化eta爲分子;來調整學習速率 |
Adadelta | 改進Adagrad: 使用梯度平方的指數加權平均,再開根號作爲分母;參數改變量平方的指數加權平均作爲分子;來調整學習速率 |
目標:更普適的方法
優化算法 | 備註 |
---|---|
Adam | 綜合Momentum和RMSprop,並使用Bias Correction來修正。Momentum用來確定更新步長,RMSprop用來調節學習速率 |
參考:
- 吳恩達人工智能課程 https://mooc.study.163.com/smartSpec/detail/1001319001.htm
- 大佬的博客 http://ruder.io/optimizing-gradient-descent/index.html#batchgradientdescent4.
- LUON 動手深度學習 https://zh.gluon.ai/chapter_optimization/index.html
NAG
NAG全稱是Nesterov accelerated gradient,它賦予Momentum感知接下來斜坡情況的能力。Momentum的小球只會沿着斜坡的方向走,即時到達了山底,再往前走又是上山的路了,它還在繼續走,因爲它不知道後面的情況到底是什麼。NAG就是期望一個更聰明的小球,它可以預知之後關於坡度的一些情況。這樣當它發現快到達山底的時候就減速,準備停下來了。
相比於Momentum唯一的變化,就是把在當前位置的求梯度,換成了對近似下一個位置求的梯度:
Momentum:
NAG:
在Momentum中,在t時刻,我們知道而且我們還可以求出目標函數在$\theta_t$處的導數,然後就可以更新動量然後,就可以更新參數了:
我們先把V_t的計算分成兩部分:歷史積累動量 + 目標函數在當前位置的梯度。可以看到,既考慮了歷史上的動量(更新方向與速度),也考慮了在當前點的更新方向與速度。兩者相加之後就得到了新的動量,用來新一輪的更新。可以看到這裏起重要作用的是後面一部分:目標函數在當前位置的梯度,它表示當前位置坡度的走向,而這將會被算入總的動量中一點一點的決定我們小球的走向。
爲了感知接下來的坡度走向,我們需要知道下一刻的位置從而可以計算出在該位置的梯度。但是,如果不先完成更新現在的位置,就無法得知下一刻的位置;可是我們想根據下一刻的位置來更新當前的位置。。。
怎麼辦,先有雞還是先有蛋?
一般遇到這種問題的解決辦法就是:近似
我們先近似的模擬向前走一步!怎麼走那?原來的走法是歷史動量 + 當前位置梯度。近似一下,我們只保留第一部分:歷史動量。模擬走出這一步,作爲小球的下一個位置。這個位置的梯度近似的包含了後面斜坡的走勢信息,我們用這個去更新原來的動量,再去更新參數,就爲當前時刻的更新引入了斜坡將來的信息了。
下面我們從圖上來感受下:
第一段小藍線:當前位置的梯度
第二段長藍線:之前積累的動量
第一段棕線:先近似的滾一下,先把歷史動量滾出來!
第一段紅線:小球近似滾之後,新位置的梯度
第一段綠線:NAG最終的更新動量
藍色是 Momentum 的過程,會先計算當前的梯度,然後在更新後的累積梯度後會有一個大的跳躍。
而 NAG 會先在前一步的累積梯度上(brown vector)有一個大的跳躍,然後衡量一下梯度做一下修正(red vector),這種預期的更新可以避免我們走的太快。
NAG 可以使 RNN 在很多任務上有更好的表現。
目前爲止,我們可以做到,在更新梯度時順應 loss function 的梯度來調整速度,並且對 SGD 進行加速。
我們還希望可以根據參數的重要性而對不同的參數進行不同程度的更新。
總結一下:
- NAG通過引入下一個時刻位置的梯度信息,來感知之後的坡度,從而調整我們的更新步伐。
- 先按照歷史累積動量走一次,新的位置近似認爲是下一個時刻的位置;然後求出下一個時刻的位置的梯度;
- 也就是把原位置的梯度換成了下一個時刻位置的梯度。下一個時刻位置是通過走歷史動量近似得到的。
優點
-
參數的更新,在Momentum的基礎上又考慮了斜坡的走向。“提前剎車”
到目前位置,我們利用累積動量加速了SGD,並且根據感知斜坡走向來調整我們的更新。
我們還想做:根據每個參數的重要性,改善不同參數的學習速率,重要的大一些,不重要的小一些。
不同參數賦予不同更新幅度: AdaGrad、Adadelta、RMSprop。
Adadelta
和RMSprop一樣,另外一個解決Adagrad學習率只降不升問題的算法是Adadelta。更有意思的是,Adadelta沒有學習率這個超參數。
Adadelta和RMSprop一樣,累積量s不再使用梯度g平方直接累加。而是使用梯度g平方的指數加權平均來計算s。首先,在mini batch上計算梯度g;然後,使用梯度g的平方來做指數加權平均:
然後,計算當前需要迭代的參數的變換量g’:
上式中的dela_x初始化爲0,並用當前迭代變換量g’的平方的指數加權平均來更新:
最後,更新參數:
優點
- 同樣解決了Adagrad的學習率不斷下降的問題
- 同時沒有了超參數學習速率。使用參數改變量的平方的指數加權平均,然後開根號來代替