梯度下降-Momentum


總結:
梯度下降算法中,學習率太大,函數無法收斂,甚至發散,如下圖。學習率足夠小,理論上是可以達到局部最優值的(非凸函數不能保證達到全局最優),但學習率太小卻使得學習過程過於緩慢,合適的學習率應該是能在保證收斂的前提下,能盡快收斂。對於深度網絡中,參數眾多,參數值初始位置隨機,同樣大小的學習率,對於某些參數可能合適,對另外一些參數可能偏小(學習過程緩慢),對另外一些參數可能太大(無法收斂,甚至發散),而學習率一般而言對所有參數都是固定的,所以無法同時滿足所有參數的要求。通過引入Momentum可以讓那些因學習率太大而來回擺動的參數,梯度能前后抵消,從而阻止發散。
 
改進:不能的參數,設置不同的學習率??Nesterov算法...
怎么避免局部最優??
                                            
 
 
作者:馮超
鏈接:https://zhuanlan.zhihu.com/p/21475880
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

為了保證完整性,今天再扯一下另外一個在梯度下降中十分重要的東西,那就是沖量——momentum。

這是一個十分神秘的變量,我也只能以最簡單的方式理解它,於是在這里班門弄斧了。正如它的中文名字一樣,在優化求解的過程中,沖量扮演了對之前優化量的持續發威的推動劑。一個已經完成的梯度+步長的組合不會立刻消失,只是會以一定的形式衰減,剩下的能量將繼續發揮余熱。我們先不加解釋的給出基於沖量的梯度下降的代碼:

def momentum(x_start, step, g, discount = 0.7):   
    x = np.array(x_start, dtype='float64')
    pre_grad = np.zeros_like(x)
    for i in range(50):
        grad = g(x)
        pre_grad = pre_grad * discount + grad
        x -= pre_grad * step
        
        print '[ Epoch {0} ] grad = {1}, x = {2}'.format(i, grad, x)
        if abs(sum(grad)) < 1e-6:
            break;
    return x
可以看出這個算法和之前的梯度下降法相比,唯一不同的就是多了一個pre_grad*discount,這就是沖量發揮余熱的地方。

那么沖量究竟有什么作用呢?今天主要扯它其中的一個作用,那就是幫助你穿越“山谷”。怎么來理解穿越“山谷”呢?先來一個待優化函數。這次的問題相對復雜些,是一個二元二次函數z=x^2+50y^2

def f(x):
    return x[0] * x[0] + 50 * x[1] * x[1]
def g(x):
    return np.array([2 * x[0], 100 * x[1]])
xi = np.linspace(-200,200,1000)
yi = np.linspace(-100,100,1000)
X,Y = np.meshgrid(xi, yi)
Z = X * X + 50 * Y * Y

上面這個函數在等高線圖上是這樣的:

其中中心的藍色點表示了最優值。我們根據這個圖發揮下想象,這個函數在y軸十分陡峭,在x軸相對平緩些。好了話說完我們趕緊拿朴素梯度下降來嘗試下:

gd([150,75], 0.016, g)

經過50輪的迭代,他的優化過程圖如下所示:

可以看出我們從某個點出發,整體趨勢向着最優點前進,這個是沒有問題的,但是前進的速度似乎有點乏力,是不是步長又設小了?有了之前的經歷,這一回我們在設置步長時變得小心了許多:

res, x_arr = gd([150,75], 0.019, g)
contour(X,Y,Z, x_arr)

好像成效不是很明顯啊,而且優化的過程中左右來回抖是怎么回事?看着這個曲線讓我想起了一個極限運動:

(來自網絡,如有侵權立即刪除)

沒錯,其實算法眼中的這個函數很這張圖很像,而算法也果然沒有讓大家“失望”,選擇了一條艱難的道路進行優化——就像從一邊的高台滑下,然后滑到另一邊,這樣艱難地前進。沒辦法,這就是梯度下降法。在它的眼中,這樣走是最快的,而事實上,每個優化點所對應的梯度方向也確實是那個方向。

大神們這時可能會聊起特征值的問題,關於這些問題以后再說。好吧,現在我們只能繼續挑步長,說不定步長再大點,“滑板少年”還能再快點呢!

res, x_arr = gd([150,75], 0.02, g)
contour(X,Y,Z, x_arr)

好吧……我們的滑板少年已經徹底玩脫了……這已經是我們能設的最大的步長了(上一次關於步長和函數之間的關系在這里依然受用),再設大些我們的滑板少年就飛出去了。對於這個問題,由於兩個坐標軸方向的函數屬性不同,為了防止在優化的過程中發散,步長只能夠根據最陡峭的方向設定。當然,解決快速收斂這個問題還有其他的辦法,這里我們看看沖量如何搞定這位滑板少年。

很自然地,我們在想,要是少年能把行動的力量集中在往前走而不是兩邊晃就好了。這個想法分兩個步驟:首先是集中力量向前走,然后是盡量不要在兩邊晃。這時候,我們的沖量就閃亮登場了。我們發現滑板少年每一次的行動只會在以下三個方向進行:

  • 沿-x方向滑行
  • 沿+y方向滑行
  • 沿-y方向滑行

我們可以想象到,當使用了沖量后,實際上沿-y和+y方向的兩個力可以相互抵消,而-x方向的力則會一直加強,這樣滑板少年會在y方向打轉,但是y方向的力量會越來越小,但是他在-x方向的速度會比之前快不少!

好了,那我們看看加了沖量技能的滑板少年的實際表現:

momentum([150,75], 0.016, g)

總算沒有讓大家失望,盡管滑板少年還是很貪玩,但是在50輪迭代后,他還是來到了最優點附近。可以說是基本完成了我們的任務吧。當然由於沖量的問題,前面幾輪迭代他在y軸上玩得似乎比以前還歡樂,這個問題我們后面會提。但不管怎么說,總算完成目標了。

后來,又有高人發明了解決前面沖量沒有解決的問題的算法,干脆不讓滑板少年愉快地玩耍了,也就是傳說中的Nesterov算法。這里就不細說了,有時間詳細聊下。直接給出代碼和結果:

def nesterov(x_start, step, g, discount = 0.7):   
    x = np.array(x_start, dtype='float64')
    pre_grad = np.zeros_like(x)
    for i in range(50):
        x_future = x - step * discount * pre_grad
        grad = g(x_future)
        pre_grad = pre_grad * 0.7 + grad 
        x -= pre_grad * step
        
        print '[ Epoch {0} ] grad = {1}, x = {2}'.format(i, grad, x)
        if abs(sum(grad)) < 1e-6:
            break;
    return x
nesterov([150,75], 0.012, g)

好了,滑板少年已經哭暈在廁所……

費了這么多話,我們總算把穿越“山谷”這件事情說完了,下面還要說一個數值上的事情。在CNN的訓練中,我們的開山祖師已經給了我們沖量的建議配置——0.9(剛才的例子全部是0.7),那么0.9的沖量有多大量呢?終於要來點公式了……

我們用G表示每一輪的更新量,g表示當前一步的梯度量(方向*步長),t表示迭代輪數,\gamma表示沖量的衰減程度,那么對於時刻t的梯度更新量有:

G_t=\gamma*G_{t-1}+g_t
G_t=\gamma*(\gamma*G_{t-2}+g_{t-1})+g_t
G_t=\gamma^2*G_{t-2}+\gamma*g_{t-1}+g_t
G_t=\gamma^t*g_0+\gamma^{t-1}*g_1+...+g_t

那么我們可以計算下對於梯度g0對從G0到GT的總貢獻量為

(\gamma^t + \gamma^{t-1} + ... + \gamma + 1)*g_0

我們發現它的貢獻是一個等比數列,如果\gamma=0.9,那么跟據等比數列的極限運算方法,我們知道在極限狀態下,它一共貢獻了自身10倍的能量。如果\gamma=0.99呢?那就是100倍了。

那么在實際中我們需要多少倍的能量呢?

本文相關代碼詳見:https://github.com/hsmyy/zhihuzhuanlan/blob/master/momentum.ipynb

等比數列的極限運算方法,我們知道在極限狀態下,它一共貢獻了自身10倍的能量。如果 \gamma =0.99呢?那就是100倍了。

那么在實際中我們需要多少倍的能量呢?

本文相關代碼詳見:https://github.com/hsmyy/zhihuzhuanlan/blob/master/momentum.ipynb


免責聲明!

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



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