我眼中的機器學習(四) 快速尋找最優解


快速尋找最優解 -基礎知識
通過上文,  我們知道了, 如果盲目使用隨機算法或者遍歷算法尋找最優解的話,  需要計算的空間將會太大. 為了能夠讓大家直觀的感受一下實際應用的計算量, 我這里再舉個例子, 1997年5月11日 IBM的深藍AI戰勝卡國際象棋名家斯帕羅夫. 我們知道 圍棋的棋盤是19路總共361格, 如果計算機需要計算10步則需要計算的狀態數量為361^10 = 37589973457545958193355601 個,  而前文我們提到的當步長為0.01時需要計算的狀態數量為160000, 耗時約5秒, 而剛才提到的10步需要的計算量約為上文160000的 234937334109662238708倍. 
 
不難看出, 如果不使用一定的優化技巧, 使用暴力窮舉來計算實際任務, 性能上將很容量成為瓶頸.
 
相對遍歷或者窮舉的方法, 梯度下降法(gradient descent ) 就是這樣一種又快又准原理簡單又容易實現的優化算法
 
所謂的梯度下降法就是讓數學模型的參數(coefficient)沿着梯度的負方向進行快速迭代下降的過程, 該過程會一直迭代下去直到誤差的范圍符合用戶的要求(成功創建模型)或者迭代次數達到上限時(失敗)。
 
在正式介紹梯度下降算法之前, 本章先梳理一下梯度下降法會涉及到的基本概念
 
導數通常描述的是在只有一個自變量(一維)的函數空間內的某一點隨着函數自變量變化時,函數本身的變化率(敏感程度)。導數的計算結果為一個標量(也就是一個數值), 值越大, 單位長度的自變量變化帶來的影響越大。直觀的幾何意思是函數在某一點的斜率。
 
當函數有多個自變量時(多元函數也叫多維函數), 由於求導可以針對不同的自變量進行, 所以針對只有某個自變量進行變化的情況下求解的導數被稱為 偏導數。偏導數描述的是函數僅沿着坐標軸的某個方向進行變化時的函數變化率。
 
既然函數可以沿着坐標軸的某個方向進行求導, 那么自然也可以對沿着其它方向變化的函數進行求導(比如沿着與X軸成45度夾角的方向), 在這個情況下求出來的導數我們稱之為 方向導數。 也就是說方向導數為多元多項式中(比如二元二次函數)某個點沿着某個向量方向進行求導后得到的值。(二元函數的自變量可以沿着[x,y]方向變化, 三元函數則可以沿[x,y,z]方向進行求導)
 
 
梯度為多元函數的偏導數組成的一個向量, 是一維導數在高維空間的推廣(generalization)。 同樣描述的是函數隨着自變量進行變化時的變化率, 只是這個時候的自變量由一維(一個)變成了多維(多個自變量)。 沿着梯度方向進行求導時, 導數值最大, 也就是說函數在某個點沿着梯度方向變化時, 函數的值變化最快。
 
 
如下圖所示, 左邊的山是由函數f(x,y) 代表高度的情況下繪制出來的, 右邊是這座山在二維平面的投影形成的等高線圖。 右圖中的紅點可以沿着任意方向前進, 但是我們可以發現不同方向的高度變化是不一樣的。 紅點的箭頭方向是梯度方向, 也是高度變化最劇烈的方向。
 
 
 
再如下圖為一個二元二次函數  f( x, y) = −(cos 2 x + cos 2 y) 2
圖中的X,Y軸組成的平面上的紅色箭頭的方向 就是梯度的方向, 箭頭的長度由函數在這個點上沿梯度方向求導計算出來的。
 
總結一下: 
導數是一個數值, 代表了函數在某個點的變化率。
梯度一個特殊的方向,因為它的方向是由函數在某個點的偏導數決定的 
 
知道了梯度的相關概念, 我們就直接來說說簡單版的梯度下降算法(也叫 最速下降法 Gradient descent)
 
(1)首先對於任意一個函數, 我們都可以隨機選擇一個點作為我們的起始點X_0
(2)為了保證函數F(X)在朝某個方向移動  \gamma(單位步長)距離時 ,使函數值變的盡可能的小, 我們需要沿着梯度負方向的進行移動.  沿着梯度方向移動了一定長度后, 我們得到了點X_1與F(X_1).  
注意:只有在移動的距離足夠小時, 我們才能保證移動后的點X_1的函數值F(X_1) 小於F(X_0).  因為導數針對的是某個點來計算的, 不同點的導數不一樣, 所以步長不宜設的太長。
(3) 計算F(X_1)與F(X_0)的差值, 判斷單位步長的移動帶來的函數值的變化是否已經小於一個我們預設的, 非常小的一個值。
如果小於的話, 那就不需要再移動了, 因為繼續移動的話函數值F(X)的變化也只會是非常小的。
如果本次移動帶來的函數值變化非常大, 則說明算法還有進一步迭代的必要。則重復第二步, 和第三步
 
 
 
 
接着我們來說說一個實例
因為例子比較簡單, 我們在應用梯度算法之前先使用在高中學過的令導數等於0計算駐點(極值點)的方法
$$ f(x) = x ^4-3x ^3+2 $$
的最小值
$$f'(x) = 4x^3-9x^2 =x^2(4x-9)$$
令f'(x)=0 可得駐點 $$x_1=0, x_2=2.25$$
將駐點代回方程 可得 最大值2 與最小值 -6.54296875
 
將剛才說的算法寫成PYTHON腳本
# -*- coding: cp936 -*-
xOld = 0
xNew = 1 # The algorithm starts at x=6
moveDistance = 0.01 # step size
precision = 0.00001
def evaluateEquation(x):
    """計算原函數在自變量為x時的值"""
    return x**4-3*x**3+2
def evaluateGradient(x):
    """計算梯度向量"""
    return 4 * x**3 - 9 * x**2
step=0
while abs(evaluateEquation(xNew) - evaluateEquation(xOld)) > precision:
    step+=1
    xOld = xNew
    xNew = xOld - moveDistance * evaluateGradient(xNew)
    print "step",step,"xold=",xOld, "xnew=",xNew
print("Local minimum occurs at ", xNew, "with minimum value",evaluateEquation(xNew))
print "step",step

 

  

 
 
運行后得到
>>>
step 1 xold= 1 xnew= 1.05
step 2 xold= 1.05 xnew= 1.10292
step 3 xold= 1.10292 xnew= 1.1587338169
step 4 xold= 1.1587338169 xnew= 1.21734197218
step 5 xold= 1.21734197218 xnew= 1.27855469659
step 6 xold= 1.27855469659 xnew= 1.34207564416
step 7 xold= 1.34207564416 xnew= 1.40748858095
step 8 xold= 1.40748858095 xnew= 1.47424999816
step 9 xold= 1.47424999816 xnew= 1.54169100548
step 10 xold= 1.54169100548 xnew= 1.60903167429
step 11 xold= 1.60903167429 xnew= 1.67540991642
step 12 xold= 1.67540991642 xnew= 1.73992485396
step 13 xold= 1.73992485396 xnew= 1.80169165901
step 14 xold= 1.80169165901 xnew= 1.85990167873
step 15 xold= 1.85990167873 xnew= 1.91387933776
step 16 xold= 1.91387933776 xnew= 1.96312685144
step 17 xold= 1.96312685144 xnew= 2.00734969025
step 18 xold= 2.00734969025 xnew= 2.04645960885
step 19 xold= 2.04645960885 xnew= 2.08055667019
step 20 xold= 2.08055667019 xnew= 2.10989555269
step 21 xold= 2.10989555269 xnew= 2.13484344301
step 22 xold= 2.13484344301 xnew= 2.15583674372
step 23 xold= 2.15583674372 xnew= 2.17334219049
step 24 xold= 2.17334219049 xnew= 2.1878256603
step 25 xold= 2.1878256603 xnew= 2.19972976112
step 26 xold= 2.19972976112 xnew= 2.20945968856
step 27 xold= 2.20945968856 xnew= 2.21737593374
step 28 xold= 2.21737593374 xnew= 2.22379211672
step 29 xold= 2.22379211672 xnew= 2.22897629956
step 30 xold= 2.22897629956 xnew= 2.23315441132
step 31 xold= 2.23315441132 xnew= 2.23651475494
step 32 xold= 2.23651475494 xnew= 2.23921288183
step 33 xold= 2.23921288183 xnew= 2.24137637832
step 34 xold= 2.24137637832 xnew= 2.24310930133
step 35 xold= 2.24310930133 xnew= 2.24449613419
step 36 xold= 2.24449613419 xnew= 2.24560522103
step 37 xold= 2.24560522103 xnew= 2.24649169063
step 38 xold= 2.24649169063 xnew= 2.24719990952
step 39 xold= 2.24719990952 xnew= 2.24776551743
step 40 xold= 2.24776551743 xnew= 2.24821710187
step 41 xold= 2.24821710187 xnew= 2.2485775668
step 42 xold= 2.2485775668 xnew= 2.24886524544
('Local minimum occurs at ', 2.2488652454412037, 'with minimum value', -6.542955721127889)
step 42

 

 
可以看到腳本進行了42次迭代后, 得到了最小值-6.54295572 (x=2.248) 與使用手工計算出來的最小值-6.54296875 的誤差為0.00001303
 
那么現在你心中的疑問可能是
1.既然令導數為零可以直接求解, 為什么不直接讓電腦計算令導數為零的方程式
答案是:  答案在前兩篇的文章"我眼中的機器學習(二)" 中已經提過了, 當樣本數據中有噪點時, 或者不可解時, 標准解方程的方式無用.
當然基於矩陣思想的最小二乘法通過計算高維空間中的一個向量在低維子空間的投影也是可以求解出誤差最小的解的, 但是計算一個矩陣的逆是相當耗費時間的, 所以許多時候我們會更傾向於使用計算量並不算大的常規的最優化算法--比如梯度下降, 牛頓法等.
 
2.如何為梯度下降算法選擇合適的步長, 多大的步長變化是最有效率的
關於這一點我會在下一章進一步說明.
 
 
 
 
 
 
 
http://mathinsight.org/directional_derivative_gradient_introduction

Nykamp DQ, “Directional derivative on a mountain.” From Math Insighthttp://mathinsight.org/applet/directional_derivative_mountain

Keywords: directional derivative


免責聲明!

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



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