優化方法

優化方法

來自專欄 計算機視覺·周刊

以下內容來自CS231n筆記:有關優化方法的一節和自己的一些補充

引言

考慮以下問題,找出一條直線,如途中黃線所示,將兩類正反例分開

每個點都可以用一對坐標和一個標籤表示

每個點可用 egin{Bmatrix} egin{pmatrix} x_{1} , x_{2} end{pmatrix} , y_{i} end{Bmatrix},x_{1,2}subset R,y_{i}subsetegin{Bmatrix} 0,1 end{Bmatrix} egin{Bmatrix} egin{pmatrix} x_{1} , x_{2} end{pmatrix} , y_{i} end{Bmatrix} ,則這條直線可以表示為 omega _{1}x_{1}+omega_{2}x_{2}+b=0 ,記 W=egin{pmatrix} omega_{1}\ omega_{2}\ b end{pmatrix}X=egin{pmatrix} x_{1}\ x_{2}\ 1 end{pmatrix} ,這條直線則可記為 W^{T}X=0

y=W^{T}X ,則將任意的點的一對坐標代入, left| y 
ight| 可以衡量該點到直線的距離, sign(y) 可以表示該點在直線的哪一邊。如果 left| y
ight|越大,那麼我們就越可以確信這一點分類是正確的(因為它遠離了邊界,就不太可能分類出錯)。以此我們將 y 外套上一層 sigmoid(x)=frac{1}{1+e^{-x}} ,就能衡量該點屬於某一類的概率。對於某個點 egin{Bmatrix} egin{pmatrix} x_{1} , x_{2} end{pmatrix} , y_{i} end{Bmatrix}L(y_{i},sigmoid(W^{T}X)) = igl(egin{smallmatrix} y_i-frac{1}{1+e^{w_{1}x_{1}+w_{2}x_{2}+b}} end{smallmatrix}igr)^{2} , L(y_{i},sigmoid(W^{T}X)) 為損失函數,衡量了這一條直線,在將這一點進行分類的時候的誤差是多少。對於給定的數據集,這條直線在這一數據集上的損失為 L=frac{1}{N}sum_{i=1}^{N}L_{i} ,則現在尋找到這條直線的任務就變為 W=egin{equation} mathop{argmin}_{(omega_{1},omega_{2},b)}    mathrm{L} end{equation} 。在給定數據集的情況下,由以上可知,損失 L 是直線的三個參數的函數,最小化損失的過程,就是優化過程,對於以上損失函數可操作的機器學習演算法,優化的過程就是訓練的過程。

基於梯度的優化方法

1.梯度下降法(Vanilla gradient descent)

延續之前的問題,由梯度的定義我們可以知道,梯度對應的方向是多元函數增長最快的方向,取負之後,梯度方向就是函數下降最快的方向。我們可以利用這一特點,通過多次迭代,找到最小的參數值。如下:

W_{t+1}=egin{bmatrix} omega_{1,t}+alphafrac{partial L }{partial omega_{1,t}}\ omega_{2,t}+alphafrac{partial L }{partial omega_{2,t}}\ b_{t}+alphafrac{partial L }{partial b_{t}} end{bmatrix}=W_{t}+alphaDelta_WL

其中 alpha為學習率,是特別重要的一個超參數(需要我們自己手動調節,無法通過學習得到)。 alpha 過大,就會導致在迭代到極小值附近,會發生抖動,導致模型無法收斂。 alpha 過小就會導致模型收斂過慢。

其代碼實現如下:

while True: grad = evaluate_gradient(loss_function, data) weight -= learning_rate*grad

梯度下降的缺點:

1.每一次訓練都需要使用全部的數據集,對於深度學習這樣,比如ImageNet這樣1T的圖片集,每一輪迭代的代價太大,不可承受

2.如果當訓練到鞍點,極小值,或者各個坐標軸的梯度都極小的時候,此時會出現梯度消失的現象,訓練無法進行。在深度學習這種維數相當爆炸的數據集上,可以發現大部分數據點都處於鞍點之上。訓練無法繼續進行。

3.由於學習率恆定,在訓練到不同階段,恆定的學習率不一定適合。

針對以上缺點,前人提出了許多改進的演算法。

2.隨機梯度下降(Stochastic Gradient Descent)

針對梯度下降法的第一點,我們提出了隨機梯度下降。因為損失函數的梯度是損失函數對各個參數值偏導的累加。在實際的優化中,我們並不在一次迭代中計算所有維度的梯度,而是隨機取幾個維度計算梯度後迭代。同時,在實際中,在一次迭代中我們也不使用全部的數據集,而是使用一個小的子集來訓練,這樣就能加速單輪迭代的計算速度。SGD和GD還有一個缺點,就是梯度方向和最小值不一定在一條直線上。如果只是沿著梯度方向前進時。對於不需要走很大步,就能走到合適位置的維度,由於學習率在這一維度上過大,就有可能導致ZigZag現象,使得收斂過程變慢。如下圖:

ZagZig

3.帶動量的隨機梯度下降(SGD with Momentum)

針對SGD和GD都存在的鞍點問題和ZigZag問題,我們可以引入動量加以解決。引用動量之後,就不是直接用梯度對權值進行直接的更新,而是速度,更新的公式如下:

v_{t+1}=
ho v_t+
abla_{random}L

x_{t+1}=x_t-alpha v_{t+1}

從更新的角度看,每次的更新是由上一次更新和當前的梯度共同決定的。當損失函數位於鞍點時,不會因為梯度消失,而停止學習。當位於極小值點的時候,也有一定的可能越過極值點,但是仍存在被極值點限制住的可能。當下降到最小值時,會出現來回的抖動,類似於球滾到谷底後,來回滾動一樣。

更新方向和梯度以及速度的關係

vx = 0while True: grad = evaluate_gradient_random(loss_function, data) vx = rho * vx + grad weight -= learning_rate*vx

4.牛頓動量(Nesterov Momentum)

牛頓動量法和剛才講的動量有著略微的不同,其不同之處在於所計算的梯度不是當前所在位置的梯度,而是當前節點加上當前速度後的梯度。因為牛頓動量額外利用了另一個節點的信息,在單純的凸優化問題上的表現時是優於一般動量的。但是在深度學習的非凸優化中,其表現和一般動量差不多。

牛頓動量更新方向和梯度以及速度的關係,可以結合上圖對比

其更新的規則如下:

v_{t+1}=
ho v_t-alpha 
abla L(x_t + 
ho v_t)

x_{t+1}=x_t+v_{t+1}

實際上計算這樣的梯度是比較不直觀的,我們通常用換元法換元後進行計算。如下:

	ilde{x}_t=x_t+
ho v_t ,則 	ilde{x}_{t+1}=	ilde{x}_t-
ho v_t+(1+
ho) v_{t+1}=	ilde{x}_t+v_{t+1}+
ho(v_{t+1}-v_t)

while True: grad = evaluate_gradient_random(loss_function, data) old_v = v v = rho * v - leaning_rate*dx x += v + rho * (v - old)_v

下圖比較了SGD, SGD with Momentum, Nesterov Momentum三種方法:

可以看得出來帶了動量的優化的軌跡都試圖繞開局部最小值,並且動量方法收斂更快,這方面的行為兩個演算法都表現得差不多。但是一般動量和牛頓動量的方向更新各有差別,因此具體的軌跡也有所差別。

下圖則表現了,動量方法如何消除ZigZag現象,當在某一維度上,當前的坐標距離最小值的坐標很接近了,在這一維度上就會發生來回的滾動,在來回的滾動過程中,ZigZag現象就會被抵消,收斂速度也會變快,從上圖我們也可以看出。

以上的方法都是在沒有修改學習率的情況下,對GD演算法提出的優化,下面介紹通過修改學習率對GD演算法的優化。

5.AdaGrad

AdaGrad和GD演算法的差別在於,每一次迭代的實際學習率是人為設定的學習率除以累計梯度的平方和。最開始的時候,累計梯度的平方和為0,我們的分母將會是一個很小的數,此時的學習率就會很大,隨著迭代次數的增加,累計梯度平方和將會越來越大,分母不斷增加,導致真實的學習率越來越小。其更新公式如下:

GradSquare = 
abla Lullet
abla L

x_{t+1}=x_{t} - frac{alpha}{GradSquare +10^{-8}}
abla L

其代碼如下:

gradsquare = 0while True: grad = evaluate_gradient_random(loss_function, data) gradsquare = grad * grad ##注意這行和下面RMSProp的差別 weight -= learning_rate * grad /(gradsquare + 1e-8)

AdaGrad有一個較為致命的問題就是,學習率始終是在衰減的,就有可能導致在還未達到最小值之前,學習率就以及很低,導致了演算法不能收斂。針對這一問題,提出了RMSProp演算法

6.RMSProp演算法

RMSProp演算法和AdaGrad演算法的差別並不大,區別在於分母的位置不再是累計梯度平方和,而是累計梯度平方和的指數加權平均。這樣,如果梯度長時間處於一個很小的值,分母就會隨之變小,就避免了學習率過早變為很小的值導致學習率GG。代碼如下:

gradsquare = 0while True: grad = evaluate_gradient_random(loss_function, data) gradsquare = decay_rate * gradsquare + (1 - dacay_rate) * grad * grad weight -= learning_rate * grad /(gradsquare + 1e-8)

下圖是動量方法,SGD和RMSProp的差別,可以看到RMSProp的優化只是針對學習率進行了優化,其行為和SGD差不多,但是在訓練早期,RMSProp學習率較大,因此收斂速度稍快於SGD。

7.Adam

Adam演算法是目前最優秀的深度學習優化演算法,它結合了動量方法和RMSProp方法,其收斂行為接近於帶動量了RMSprop方法,在實際使用中,這是默認的深度學習訓練演算法

結合前面的講解,Adam應該很容易理解了

圖片展示了不同演算法正常的收斂行為和速度

圖片展示了不同演算法在鞍點處行為


推薦閱讀:

談談機器學習與數據分析中的問題定義
機器學習演算法系列--生成模型與判別模型
機器音樂的背後是創造力嗎?
斯坦福大學《機器學習》- 核心內容(2.3)

TAG:機器學習 | 深度學習DeepLearning | 人工智慧 |