梯度是多元函數對各個自變量偏導數造成的向量。多元函數的梯度表示:
\[\nabla f(x) = \left( \frac{\partial f}{\partial x_1},...,\frac{\partial f}{\partial x_n} \right)^T \]python
若是Hessian矩陣正定,函數有極小值;若是Hessian矩陣負定,函數有極大值;若是Hessian矩陣不定,則須要進一步討論。算法
若是二階導數大於0,函數有極小值;若是二階導數小於0,函數有極大值;若是二階導數等於0,狀況不定。網絡
目標是求多元函數\(f(x)\)的極小值。梯度降低法是經過不斷迭代獲得函數極小值,即如能保證\(f(x +\Delta x)\)比\(f(x)\)小,則不斷迭代,最終能獲得極小值。想象你在山頂往山腳走,若是每一步到的位置比以前的位置低,就能走到山腳。問題是像哪一個方向走,能最快到山腳呢?
由泰勒展開式得:
\[f(x + \Delta x) - f(x) = (\nabla f(x))^T \Delta x + o(\Delta x) \]
若是\(\Delta x\)足夠小,能夠忽略\(o(\Delta x)\),則有:
\[f(x + \Delta x) - f(x) \approx (\nabla f(x))^T \Delta x\]
因而只有:
\[(\nabla f(x))^T \Delta x < 0 \]
能使
\[ f(x + \Delta x) < f(x) \]
由於\(\nabla f(x)\)與\(\Delta x\)均爲向量,因而有:
\[ (\nabla f(x))^T \Delta x = \| \nabla f(x)\|\|\Delta x\|cos\theta\]
其中,\(\theta\)是向量\(\nabla f(x)\)與\(\Delta x\)的夾角,\(\| \nabla f(x)\|\)與\(\|\Delta x\|\)是向量對應的模。可見只有當
\[cos\theta < 0\]
才能使得
\[ (\nabla f(x))^T \Delta x < 0 \]
又因
\[ cos\theta \ge -1 \]
可見,只有當
\[cos\theta = -1\]
即\(\theta = \pi\)時,函數數值下降最快。此時梯度和\(\Delta x\)反向,即夾角爲180度。所以當向量\(\Delta x\)的模大小必定時,取
\[\Delta x = -\alpha \nabla f(x)\]
即在梯度相反的方向函數值降低的最快。此時函數的降低值爲:
\[ (\nabla f(x))^T \Delta x = -\| \nabla f(x)\|\|\Delta x\| = - \alpha \| \nabla f(x)\|^2 \]
只要梯度不爲\(0\),往梯度的反方向走函數值必定是降低的。直接用可能會有問題,由於\(x+\Delta x\)可能會超出\(x\)的鄰域範圍以外,此時是不能忽略泰勒展開中的二次及以上的項的,所以步伐不能太大。
通常設:
\[\Delta x = -\alpha \nabla f(x)\]
其中\(\alpha\)爲一個接近於\(0\)的正數,稱爲步長,由人工設定,用於保證\(x+\Delta x\)在x的鄰域內,從而能夠忽略泰勒展開中二次及更高的項,則有:
\[ (\nabla f(x))^T \Delta x = -\| \nabla f(x)\|\|\Delta x\| = - \alpha \| \nabla f(x)\|^2 < 0 \]
此時,\(x\)的迭代公式是:
\[x_{k+1} = x_k - \alpha \nabla f(x_k)\]
只要沒有到達梯度爲\(0\)的點,則函數值會沿着序列\(x_{k}\)遞減,最終會收斂到梯度爲\(0\)的點,這就是梯度降低法。
迭代終止的條件是函數的梯度值爲\(0\)(實際實現時是接近於\(0\)),此時認爲已經達到極值點。注意咱們找到的是梯度爲\(0\)的點,這不必定就是極值點,後面會說明。app
初始值的設定
通常的,對於不帶約束條件的優化問題,咱們能夠將初始值設置爲0,或者設置爲隨機數,對於神經網絡的訓練,通常設置爲隨機數,這對算法的收斂相當重要。機器學習
學習率的設定
學習率設置爲多少,也是實現時須要考慮的問題。最簡單的,咱們能夠將學習率設置爲一個很小的正數,如0.001。另外,能夠採用更復雜的策略,在迭代的過程當中動態的調整學習率的值。好比前1萬次迭代爲0.001,接下來1萬次迭代時設置爲0.0001。函數
\(argmin\frac{1}{2}[(x_{1}+x_{2}-4)^2 + (2x_{1}+3x_{2}-7)^2 + (4x_{1}+x_{2}-9)^2]\)性能
如下只是爲了演示計算過程,便於理解梯度降低,代碼僅供參考。更好的代碼我將在之後的文章中給出。學習
# 原函數 def argminf(x1, x2): r = ((x1+x2-4)**2 + (2*x1+3*x2 - 7)**2 + (4*x1+x2-9)**2)*0.5 return r # 全量計算一階偏導的值 def deriv_x(x1, x2): r1 = (x1+x2-4) + (2*x1+3*x2-7)*2 + (4*x1+x2-9)*4 r2 = (x1+x2-4) + (2*x1+3*x2-7)*3 + (4*x1+x2-9) return r1, r2 # 梯度降低算法 def gradient_decs(n): alpha = 0.01 # 學習率 x1, x2 = 0, 0 # 初始值 y1 = argminf(x1, x2) for i in range(n): deriv1, deriv2 = deriv_x(x1, x2) x1 = x1 - alpha * deriv1 x2 = x2 - alpha * deriv2 y2 = argminf(x1, x2) if y1 - y2 < 1e-6: return x1, x2, y2 if y2 < y1: y1 = y2 return x1, x2, y2 # 迭代1000次結果 gradient_decs(1000) # (1.9987027392533656, 1.092923742270406, 0.4545566995437954)