神經網路之梯度下降與反向傳播(上)

一、概述

對於一個函數,希望找到使函數值達到全局最小的自變數值。這是優化理論研究的問題。梯度下降法是一種基於函數一階性質的優化演算法。人工神經網路的訓練主要採用梯度下降法,其計算過程中採用誤差反向傳播的方式計算誤差函數對全部權值和偏置值的梯度。本文首先介紹梯度下降法,下篇將介紹反向傳播演算法並實現一個全連接神經網路。

首先用語言來描述幾個概念。這裡的描述盡量抓重點,但是不夠精確。精確的概念只能用公式把握,在下文中都有闡述。

  • 仿射函數仿射函數是線性函數。仿射函數的圖形是空間中一個平面。
  • 函數可導若函數在某一點可導,則函數在這一點附近可用一個仿射函數很好地近似。該仿射函數的圖形(平面),就是函數在這一點的切平面。
  • 梯度函數在某一點的梯度是一個自變數空間內的向量。自變數順著梯度方向變化時函數值上升得最快。梯度的模(長度)是函數值上升的速率。梯度朝某方向投影的長度是自變數順著該方向變化時函數值的變化率。
  • 梯度下降一種優化演算法,該演算法從任一點開始,沿該點梯度的反方向運動一段距離,再沿新位置的梯度反方向運行一段距離 ...... 如此迭代。解一直朝下坡最陡的方向運動,希望能運動到函數的全局最小點。

下文中都以二元函數fleft(x,yright):mathcal{R}^2rightarrow mathcal{R}為例。因為二元函數的自變數空間是 xy 平面,函數圖形所在空間是三維空間,便於可視化。其它維度可以類推。

二、仿射函數

仿射函數的圖形是一個平面。如圖 1 。

圖 1 ——仿射函數圖形(平面)

該平面的方程是:

z=fleft(x,yright)=0.5x+0.2y+3=left(0.5,0.2right)left( begin{array}{ccc}x  y end{array}right) +3quad[2.1]

該平面的截距是 3 。當 (x, y) 取 (0, 0) 時 z 的值為 3 ,即平面與 z 軸相交於 (0, 0, 3) 。將該方程變形:

-0.5x-0.2y+z=left( -0.5,-0.2,1right)left( begin{array}{ccc} xyzend{array}right)=3quad[2.2]

所有平面上的點都滿足式 2.1(或式 2.2 )。式 2.2 中的 (-0.5, -0.2, 1) 是該平面的法向量(圖 1 中的紅色箭頭)。該平面上的線段是它的兩個端點向量 (x1, y1, z1) 和 (x2, y2, z2) 之差 (x2-x1, y2-y1, z2-z1) 。因為 (x1, y1, z1) 和 (x2, y2, z2) 都在該平面上,所以這個線段與法向量 (-0.5, -0.2, 1) 正交:

left(-0.5,-0.2,1right)left(begin{array}{ccc}x_2-x_1y_2-y_1z_2-z_1end{array}right)=left(-0.5,-0.2,1right)left(begin{array}{ccc}x_2y_2z_2end{array}right)-left(-0.5,-0.2,1right)left(begin{array}{ccc}x_1y_1z_1end{array}right)=3-3=0quad[2.3]

例如,圖 1 中兩個黑色圓點都在平面上,其坐標分別是 (0, 0, 3) 和 (2, 5, 5) 。藍色箭頭和黃色箭頭分別是它們對應的向量。紫色箭頭是這兩個向量之差 (2, 5, 2)。該差向量經過平移就是平面上的一個線段。 (2, 5, 2) 與法向量 (-0.5, -0.2, 1) 內積為 0 ,即它們正交。平面上所有線段都與法向量正交, 即法向量垂直於該平面。法向量指示一個方向。該方向確定了平面的傾向和傾角。法向量的長度(模)不重要。如果將式 2.2 兩端同時乘以 2 ,法向量長了一倍,但平面沒有變化:

-1x-0.4y+2z=left( -1,-0.4,2right)left( begin{array}{ccc} xyzend{array}right)=6quad[2.4]

雖然常量項從 3 變成了 6 ,但由於 z 的係數變成了 2 ,故平面的截距仍是 3 。如果法向量第三個分量為 0 ,則平面是豎直的。例如式 2.5 :

left( -2,-3,0right)left( begin{array}{ccc} xyzend{array}right)=-2x-3y=3quad[2.5]

式 2.5 要求 x 和 y 滿足 -2x-3y=3 ,z 值任意。它確定的是一個豎直平面。如果平面非豎直,則總可以通過縮放使 z 的係數為 1 。於是非豎直平面的法向量總可以寫成 (a1, a2, 1) 的形式。第三分量保持為 1 的前提下,a1 和 a2 的絕對值越大,法向量越靠近 xy 面,平面也就被「撬起」得越高;反之 a1 和 a2 的絕對值越小,法向量越接近豎直,平面被 「放躺」 得越平。想像把法向量當作一個把手來回扳動,平面也就可以隨意調整朝向。

圖 2 展示了 8 個法向量不同的平面。子圖標題是每個平面的法向量。圖中紅色箭頭指示了法向量的方向,但其長度沒有反映法向量的模。注意隨著 a1 和 a2 絕對值的不同,平面陡峭程度的變化。

圖 2 ——法向量不同的平面

脫離具體數值,仿射函數的方程形式為:

z=a_1x+a_2y+b=left(a_1,a_2right)left(begin{array}{ccc}xyend{array}right)+bquad[2.6]

式 2.6 等價於:

-a_1x-a_2y+z=left(-a_1,-a_2,1right)left(begin{array}{ccc}xyzend{array}right)=bquad[2.7]

全體滿足式 2.6(或 2.7)的點 (x, y, z) 構成三維空間中一個非豎直的平面。(a1, a2) 決定了平面的傾向和傾角。b 稱截距。平面於 z 軸相交於 (0, 0, b) 。b 決定了平面位置的高低。(-a1, -a2, 1) 是該平面的法向量,法向量垂直於平面。a1 和 a2 的絕對值越大,法向量越接近水平,平面就被撬得越陡峭。 (-a1, -a2) 作為 xy 面內的向量決定了平面的傾向,也就是下坡的方向。相反的 (a1, a2) 是上坡的方向。下一節將會提到:函數 f 在某點可導,則 f 可在這一點被一個仿射函數(平面)很好地近似。該近似平面爬坡最陡的 (a1, a2) 方向就是 f 在該點上升最快的方向,即 f 在這一點的梯度。參考圖 3 。

圖 3 ——梯度方向坡最陡

三、導數和梯度

對於函數fleft(x,yright):mathcal{R}^2rightarrow mathcal{R},在某個點 (x0, y0) 附近找到一個仿射函數去近似它 :

fleft(x,yright)approx left(a_1,a_2right)left(begin{array}{ccc}xyend{array}right)+bquad[3.1]

一個好的近似,首先要求該仿射函數在 (x0, y0) 與 f 是相等:

fleft(x_0,y_0right)=left(a_1,a_2right)left(begin{array}{ccc}x_0y_0end{array}right)+bquad[3.2]

截距 b 由此確定:

b=fleft(x_0,y_0right)-left(a_1,a_2right)left(begin{array}{ccc}x_0y_0end{array}right)quad[3.3]

將 b 代回式 3.1 ,近似式可重寫為:

fleft(x,yright)=fleft(x_0,y_0right)+left(a_1,a_2right)left(begin{array}{ccc}xyend{array}right)-left(a_1,a_2right)left(begin{array}{ccc}x_0y_0end{array}right)+R=fleft(x_0,y_0right)+left(a_1,a_2right)left(begin{array}{ccc}x-x_0y-y_0end{array}right)+Rquad[3.4]

通過引入一個余項 R ,approx 成為 = 。R 是仿射函數與 f 的差,在 (x0, y0) 為 0 。好的近似要求 R 隨著 (x, y) 接近 (x0, y0) 而減小至消失,且減小得比 (x, y) 接近 (x0, y0) 的速度更快。用數學語言來表述,就是要求:

R=oleft(||(x,y)-(x_0,y_0)||right)quad[3.5]

||(x, y)-(x0, y0)|| 是 (x, y) 與 (x0, y0) 的差的模,即它們之間的距離。式 3.5 表示余項 R 是 (x, y) 與 (x0, y0) 之間距離的高階無窮小:隨著 (x, y) 與 (x0, y0) 之間的距離趨近於 0 ,R 與該距離的比值也趨近於 0 。 R 減小得比 (x, y) 接近 (x0, y0) 更快:

lim_{||(x,y)-(x_0,y_0)|| rightarrow 0}{frac{left|Rright|}{||(x,y)-(x_0,y_0)||} } =0quad[3.6]

小結一下。在 (x0, y0) 想用一個仿射函數(平面)去近似代表 f 。在 (x0, y0) 上該仿射函數和 f 相等。在其他位置或有差距,但這個差距隨著靠近 (x0, y0) 而減小至消失,且減小得比靠近 (x0, y0) 的速度更快。

這樣的近似仿射函數在 f 的某一點 (x0, y0) 如果存在,則是唯一的。如果在 (x0, y0) 存在這樣的近似仿射函數,就說 f 在 (x0, y0) 可導。該仿射函數是 f 在 (x0, y0) 的一階近似。仿射函數的圖形(平面)是 f 在 (x0, y0) 的切平面。

如圖 4 ,綠色曲面為函數z=-0.02x^2-0.02y^2+20。藍色平面為該函數在 (20, 5) 處的切平面 z=-0.8x-0.2y+28.5 。切平面的法向量是 (-0.8, -0.2, 1),其方向如圖中傾斜箭頭所示(箭頭的長度不等於法向量的模,為了看得清楚而拉長了)。

圖 4 ——二次曲面在 (1,1) 的切平面(四種角度)

如果left(Delta x, Delta yright)是某個非零向量 ,根據式 3.4、式 3.5 和式 3.6 可得到:

lim_{alpha rightarrow 0}{frac{fleft(x_0+alphaDelta x,y_0+alphaDelta yright)-fleft(x_0,y_0right)}{alpha||left(Delta x,Delta yright)||} } =lim_{alpha rightarrow 0}{frac{alphaleft(a_1,a_2right)left(begin{array}{ccc}Delta x Delta yend{array}right)+oleft(||alphaleft(Delta x, Delta yright)||right)}{alpha||left(Delta x,Delta yright)||} } =frac{left(a_1,a_2right)left(begin{array}{ccc}Delta xDelta yend{array}right)}{||left(Delta x, Delta yright)||} quad[3.7]

最左側是 f 在 (x0, y0) 點沿著left(Delta x, Delta yright)方向的方嚮導數。也就是自變數沿著該方向變化時 f 的變化速率。f 在不同的left(Delta x, Delta yright)方向上變化速率不同,其值是 (a1, a2) 在left(Delta x, Delta yright)方向上的投影:

frac{left(a_1,a_2right)left(begin{array}{ccc}Delta xDelta yend{array}right)}{||left(Delta x, Delta yright)||} =frac{||left(a_1,a_2right)||times ||left(Delta x,Delta yright)||times costheta }{||left(Delta x, Delta yright)||} =||left(a_1,a_2right)||times costheta quad[3.8]

theta 是 (a1, a2) 與left(Delta x, Delta yright)之間的夾角。可見自變數變化方向與 (a1, a2) 相同時,函數變化速率最大(>0);自變數變化方向與 (a1, a2) 相反時,函數變化速率最小(<0);自變數變化方向與 (a1, a2) 垂直時,函數變化速率為 0 。(a1, a2) 就是 f 在 (x0, y0) 的梯度。梯度投影到某個方向的長度就是 f 沿該方向的變化速率。為了確定梯度的取值,計算 f 在 (x0, y0) 沿 (1, 0) 的方嚮導數,即 f 在 (x0, y0) 對 x 的偏導數:

frac{partial f}{partial x} left(x_0,y_0right)=lim_{alpha rightarrow 0}{frac{fleft(x_0+alpha ,y_0right)-fleft(x_0,y_0right)}{alpha } } =lim_{alpha rightarrow 0}{frac{fleft(x_0+alpha,y_0right)-fleft(x_0,y_0right)}{alpha||left(1, 0right)||} }=left(a_1,a_2right)left(begin{array}{ccc}10end{array}right)=a_1quad[3.9]

即梯度的第一個元素是 f 在 (x0, y0) 對 x 的偏導數。同樣,梯度的第二個元素是 f 在 (x0, y0) 對 y 的偏導數。於是 f 在 (x0, y0) 的梯度triangledown f left(x_0,y_0 right)就是:

triangledown f left(x_0,y_0 right)=left(frac{partial f}{partial x}left(x_0,y_0right),  frac{partial f}{partial y } left(x_0,y_0right)right)quad[3.10]

小結一下。可導函數在任一點的梯度是自變數空間中的一個向量(二元函數的梯度是 xy 平面上的向量,而不是 xyz 空間里的向量)。函數圖形在這一點的切平面的法向量投影在自變數空間中,就是該點梯度的反方向。某點的梯度是函數以及它的切平面在該點上升最快的方向,即方嚮導數最大的方向。梯度的長度(模)就是在該方向的方嚮導數(變化率)。梯度向任何自變數空間方向的投影的長度(模)是函數在該方向上的方嚮導數(變化率)。梯度可以是 0 向量。在梯度為 0 向量的點上各方向的變化率都為 0 。這是函數達到極大/極小值的一階必要非充分條件(例如鞍點不是極大/極小值,但是梯度也為 0 )。

四、梯度下降

想像你於伸手不見五指的黑夜身處一座地形複雜的山中。你看不清山的全貌,只能根據重力感知立足之處的坡度。如果想要下山,你該怎麼做?你根據此處的重力感覺,向下坡最陡的方向邁一步。然後根據新位置的坡度,再向下坡最陡的方向邁出下一步。如果來到一個位置,你感覺已經站在了平地上,再沒有下坡的方向,你也就無從邁出下一步了。此時你可能已經成功到達海拔最低的山底,但也有可能身處半山腰處一塊平地或者一個盆地底部。

這就是梯度下降法的形象描述。山就是三維空間中函數的圖形。某個位置下坡最陡的前進方向就是函數在該點梯度的反方向。向前邁一步,就是讓自變數沿著梯度反方向運動一個距離(步長)。感覺已站在平地,就是當前點的梯度為 0 。梯度下降演算法的迭代公式為:

left(begin{array}{ccc}x_{i+1}  y_{i+1}end{array}right)=left(begin{array}{ccc}x_i  y_{i}end{array}right)-eta times triangledown f left(x_i, y_iright),  eta>0,  i=0,1,2,... quad[4.1]

(x0, y0) 為隨機的初始點。eta 為步長。考慮一個具體例子。「香蕉函數」的方程是:

z=left(1-xright)^2+100left(y-x^2right)^2quad[4.2]

圖 5 ——香蕉函數圖形(多角度)

圖 5 是香蕉函數的圖形。之所以被稱為香蕉函數,是因為該函數的等高線圖形狀像香蕉。香蕉函數的全局最小點在 (1, 1) (圖 5 左上角圖中紅點)。香蕉函數的梯度為:

triangledown f left(x,y right)=left( frac{partial z}{partial x}left(x,yright),  frac{partial z}{partial y}left(x,yright) right)= left( 2left(x-1right)-400xleft(y-x^2right) ,  200left(y-x^2right) right)quad[4.3]

圖 6 ——香蕉函數梯度場、駐點以及梯度平緩峽谷

圖 6 展示了香蕉函數的梯度場。注意圖中小箭頭僅指示該點梯度方向,其長度並不反映梯度大小。從式 4.3 可以計算得出,香蕉函數梯度為 (0, 0) 的點是 (1, 1) 。在 y=x^2二次曲線上,梯度的 y 分量為 0 ,梯度的 x 分量為 2(x-1) 。

在二次曲線 y=x^2上(圖 6 黃色曲線),若 x>1 ,則梯度 x 分量大於 0 ,曲面向正 x 方向上坡;反之若 x<1 ,梯度 x 分量小於 0,曲面向 -x 方向上坡。x 離 1 越遠則坡越陡。x 為 1 時梯度 x 分量為 0 ,梯度是 (0, 0) ,各個方向都不上下坡。(0, 0) 是曲面的駐點(圖 6 中黃色圓點)。曲面在 (0, 0) 取得最小值 0 。以下把 y=x^2稱作二次曲線峽谷。

在香蕉函數上運行梯度下降法。以 (-1.9 -0.9) 為初始點。以 0.0001 為步長。當梯度長度(模)小於 1e-4 時停止。梯度下降演算法運行結果如圖 7 所示。

圖 7 ——香蕉函數上的梯度下降( 0.0001 步長)

演算法共迭代 199078 步。最終停止在 (0.9999, 0.9998) ,很接近 (1, 1) 。可認為演算法成功找到了最優點。圖 7 中紅色線是解的運動軌跡,紅點是最終位置。黃色虛線顯示函數值隨著迭代下降。解進入二次曲線峽谷時有一個明顯的轉向,之後沿著峽谷向最優點前進。如果增大步長,演算法會收斂得更快。下面以 0.0009 為步長實驗一下。結果如圖 8 。

圖 8 ——香蕉函數上的梯度下降( 0.0009 步長)

停止點仍是 (0.9999, 0.9998) ,步數為 18567 步,收斂速度加快了 10 倍。可以看到在梯度較大的地方由於運動距離大,解一下跳過了二次曲線峽谷而衝上了對面山坡。經過兩大步的調整後解進入了峽谷,開始向目標緩慢前進。

步長的選擇學問很多。若步長過短,則演算法收斂慢。若步長太長,則有可能一下衝過谷底,或者發生震蕩,難以精確收斂到最優解。步長顯然應該與待優化函數自變數本身的尺度有關。一般來講步長應該隨著演算法迭代而調整。辦法包括但不限於:

  • 隨著迭代進行而衰減。演算法開始時採用較大的步長,隨著解接近最優解,逐步縮小步長,在最優解周圍細緻搜索;
  • 根據梯度選擇步長。梯度小的地方函數平坦,採用較大步長快速跨過平坦區。梯度大的地方函數變化劇烈,採用較小步長以免「衝過頭」;

梯度下降法演算法何時停止?梯度為 0 的點滿足極小點的一階必要條件,是全局最小點的候選點。找到這樣的點演算法就「走不動」了——解不再更新。但是由於步長或計算機浮點數精度所限,解基本上不可能運動到梯度精確為 0 的點。可以設置一個閾值,例如上例中採用 1e-4 。若當前點的梯度的模小於閾值,則認為該點梯度近似為 0 ,演算法停止。由於步長不合適,演算法可能在最優點周圍來回震蕩而無法停止。可以通過設置最大迭代次數來避免這種情況。

梯度下降演算法只利用了目標函數的一階特性。最好情況無非是找到梯度為 0 的點(駐點)。梯度為 0 是全局最小點的必要非充分條件。它有可能根本不是極小點(是鞍點),也有可能是局部極小點。陷入局部極小點是梯度下降法的一大問題。可以從多個不同的初始點嘗試多次運行演算法。還可以加入「衝量」(momentum)。加入衝量的更新式是:

left(begin{array}{ccc}x_{i+1}  y_{i+1}end{array}right)=left(begin{array}{ccc}x_{i}  y_{i}end{array}right)-eta times left[left(1-gammaright)times triangledown f left(x_i,y_iright) + gamma times triangledown f left(x_{i-1}, y_{i-1}right)right],  eta>0,  0<gamma <1quad[4.4]

通過一個 0 與 1 之間的因子gamma,將上一次的前進方向混合進本次前進方向。就好像有了一個慣性。衝量有助於緩解震蕩以及防止陷入局部極小點。

圖 9 展示了在 6 種不同更新策略下梯度下降法在二次曲面 z=0.5x^2+0.1y^2上的運行情況。每個子圖的標題中有迭代次數。每種策略的說明和實現參見文末代碼。

圖 9 ——在二次曲面上實驗 6 種更新策略

五、例舉:線性回歸

求線性回歸的最小二乘解涉及矩陣求逆。在樣本量大/維度高的情況下計算量較大。這時可以使用梯度下降法近似來求最小二乘解。尋找關於回歸直線斜率 a 和截距 b 的誤差函數 e 的全局最小點(最小二乘解就是 e 的全局最小點,通過解析地求梯度為 0 點而得到):

eleft(a,bright)=frac{1}{2}sum_{i=1}^{n}{left(bar{y_i}-y_iright)^2}= frac{1}{2}sum_{i=1}^{n}{left(ax_i+b-y_iright)^2}quad[5.1]

(xi, yi) 為待擬合的樣本點,共 n 個。e 在 (a, b) 的梯度是:

triangledown e left(a,b right)=left(frac{partial e}{partial a}left(a,bright),  frac{partial e}{partial b}left(a,bright)right)=left(sum_{i=1}^{n}{x_ileft(ax_i+b-y_iright)} ,  sum_{i=1}^{n}{left(ax_i+b-y_iright)}right)quad[5.2]

實驗一下。生成 100 個直線 y=1.2x+2.0 上的點。對每個點的 y 值加上均值為 0 ,標準差為 0.6 的正態雜訊。如圖 10 。

圖 10 ——圍繞直線的有雜訊點以及最小二乘線性回歸直線

圖 10 左側為 100 個樣本點,右側顯示了用最小二乘法求得的線性回歸直線。如圖中標註,回歸直線的方程是 y=1.211x+1.972 ,比較準確。(1.211, 1.972) 就是 e 的全局最小點,也是梯度下降法所要尋找的目標點。

圖 11 ——梯度下降法尋找最小二乘解

圖 11 中的曲面是以直線斜率 a 和截距 b 為自變數的誤差 e 曲面。梯度下降演算法起始點為 (-100, -100) 。步長為 0.0001 。梯度模停止閾值為 1e-4 。迭代共進行了 6789 步。紅線是解的運行路徑。紅點是最終點。紅點的坐標是 (1.2112, 1.9725) 。忽略舍入誤差,梯度下降演算法成功找到了最小二乘解。圖 12 顯示了 100 個樣本點、直線 y=1.2x+2.0 、最小二乘回歸直線 y=1.211x+1.972 以及運用梯度下降找到的直線 y=1.2112x+1.9725 。

圖 12 ——隨機點、最小二乘法求得的回歸直線以及梯度下降法找到的直線

六、結語

梯度下降法的本質是在某個位置將目標函數一階展開,利用其一階性質持續向函數值下降最快的方向前進,以期找到函數的全局最小解。梯度下降屬於梯度優化方法大類,此外還有最速下降法,共軛梯度法等等。還有其他方法基於目標函數的二階性質,比如牛頓法、擬牛頓法等。

用來訓練神經網路的反向傳播演算法是梯度下降法。不過它需要求得誤差函數對眾多權重和偏置值的偏導數。反向傳播法在前向計算網路輸出的過程中把一些「局部誤差」反向傳播。藉助這些局部誤差計算誤差函數對每個權重和偏置值的偏導數,得到梯度。下一篇專欄中將詳細介紹反向傳播演算法。

最後附上本文代碼。

import numpy as npnimport matplotlib.pyplot as pltnfrom matplotlib import cmnfrom mpl_toolkits.mplot3d import Axes3Dnnndef quadratic(x, y):n return 0.5 * x ** 2 + 0.1 * y ** 2nnndef quadratic_grad(x, y):n return np.array([x, 0.2 * y])nnnmax_eta = 1.66nmin_eta = 0.001nnndef strategy1(grad, last_grad, iters):n """n 固定步長 min_eta 。n """n global max_eta, min_etan eta = min_etan return -eta * gradnnndef strategy2(grad, last_grad, iters):n """n 固定步長 max_eta 。n """n global max_eta, min_etan return -max_eta * gradnnndef strategy3(grad, last_grad, iters):n """n 固定步長 max_eta ,以 0.1 為係數加入衝量。n """n global max_eta, min_etan return -max_eta * ((1 - 0.1) * grad + 0.1 * last_grad)nnndef strategy4(grad, last_grad, iters):n """n 初始步長為 max_eta ,以 0.9 為衰減因子衰減步長。保障步長大於等於 min_eta 。n """n global max_eta, min_etann if not iters:n eta = max_etan else:n eta = min_eta if max_eta * 0.9 ** iters <= min_eta else max_eta * 0.9 ** itersnn return -eta * gradnnndef strategy5(grad, last_grad, iters):n """n 根據梯度的大小。在梯度大的地方減小步長,在梯度小的地方增加步長。保障步長大於等於 min_eta 。n 具體計算方法是:步長=max_eta / e^(magnitude/10.0) 。n e 是自然對數的底,magnitude 是當前梯度的長度。n """n global max_eta, min_etann magnitude = np.sqrt(np.dot(grad, grad))n coe = np.power(np.e, magnitude / 10.0)n if coe > 0:n eta = max_eta / coen else:n eta = min_etann eta = min_eta if eta <= min_eta else etan return -eta * gradnnndef strategy6(grad, last_grad, iters):n """n 根據當前梯度與上一位置的梯度交角調整步長。n 交角大,認為地形崎嶇變化大,縮小步長。若交角小,認為地形變化不大,增大步長。n 具體步長公式為:步長 = max_eta * (cos_theta + 1.0001) / 2.0001 。n cos_theta 是本次梯度與上一次梯度的交角餘弦值。加上 1.0001 是將係數調整為正數。n """n global max_eta, min_etann l_grad = np.sqrt(np.dot(grad, grad))n l_last_grad = np.sqrt(np.dot(last_grad, last_grad))nn if l_grad > 0 and l_last_grad > 0:n cos_theta = np.dot(grad, last_grad) / (l_grad * l_last_grad)n eta = max_eta * (cos_theta + 1.001) / 2.0001n else:n eta = max_etann eta = min_eta if eta <= min_eta else etan return -eta * gradnnndef draw_chart(fun, path, ax):n x, y = np.meshgrid(np.arange(-8.0, 8.0, 0.1), np.arange(-8.0, 8.0, 0.1))n z = fun(x, y)nn ax.plot_surface(x, y, z, rstride=1, cstride=1, alpha=0.5, cmap=cm.coolwarm)n ax.contourf(x, y, z, zdir=z, offset=-10.0, cmap=cm.coolwarm)nn ax.set_xlabel(X)n ax.set_ylabel(Y)n ax.set_zlabel(Z)n ax.set_zlim([-10.0, 40.0])nn if path is not None:n ax.plot(path[0], path[1], [-10.0] * len(path[0]), c="#b22222", linewidth=0.8)n ax.scatter(path[0][-1], path[1][-1], [-10.0], c="#b22222")nnndef gradient_descent(init_position, gradient_fun, step_fun, tolerance=1e-4, max_iters=None):n x = [init_position[0]]n y = [init_position[1]]n iters = 0n last_grad = np.array([0.0, 0.0])nn while True:n cx = x[-1]n cy = y[-1]nn grad = gradient_fun(cx, cy)n step = step_fun(grad, last_grad, iters)nn x.append(cx + step[0])n y.append(cy + step[1])nn last_grad = gradn iters += 1n magnitude = np.sqrt(np.dot(grad, grad))nn if magnitude < tolerance or (max_iters is not None and iters >= max_iters):n breaknn return {"final_pos": [x[-1], y[-1]], "iters": iters, "final_grad": grad, "path": [x, y]}nnnfig = plt.figure(figsize=(20, 30))nnstrategies = [strategy1, strategy2, strategy3, strategy4, strategy5, strategy6]nnfor step_func, index in zip(strategies, np.arange(1, len(strategies) + 1)):n ax = fig.add_subplot(3, 2, index, projection="3d")n result = gradient_descent([-6.0, -6.0], quadratic_grad, step_func)n draw_chart(quadratic, result["path"], ax)n ax.set_title("strategy: {:d} loops: {:,}".format(index, result["iters"]))n print("running strategy {:d}".format(index))nnplt.savefig("strategies.png")nplt.cla()nplt.clf()nplt.close()n

七、參考書目

[1]《最優化導論》(美)Edwin K. P. Chong(美) Stanislaw H. Zakbook.douban.com


推薦閱讀:

梯度下降法快速教程 | 第三章:學習率衰減因子(decay)的原理與Python實現
為什麼梯度的負方向是局部下降最快的方向?
詳解softmax函數以及相關求導過程
為什麼梯度下降演算法(BGD批量梯度下降)用的是所有樣本點梯度的均值作為最終的梯度方向?
圖像處理中加權直方圖是什麼意思?

TAG:梯度下降 | 神经网络 | 优化 |