1.固定學習率的梯度下降
y=x^4+2x ,初值取x=1.5,學習率使用0.01
#coding:utf-8 #求x^4+2x的導數 def g(x): return 4.0*x**3+2; #梯度下降法求f(x)的最小值 x=1.5 a=0.01 y1=x**4+2*x y2=1000 i=0 while y2-y1>10**-20: i=i+1 d=g(x) x-=d*a y2 = y1 y1=x**4+2*x print("%d \t %f \t%f\n" %(i,a,x)) print (y1)
運行結果如下:
迭代次數 學習率 x
…… …… ……
283 0.010000 -0.793701
284 0.010000 -0.793701
285 0.010000 -0.793701
286 0.010000 -0.793701
y=-1.1905507889761484
可知通過286次的迭代達到我們要求得精度
下面做個試驗看一下不同的函數對相同的學習率有什么影響
(1) y=x^2 ,初值取x=1.5,學習率使用0.01
分析:
效果還不錯,經過200次迭代,x=0.0258543,經過1000次迭代,x=2.52445×10 -9
(2)y=x^4 ,初值取x=1.5,學習率使用0.01
分析:
效果不理想,經過200次迭代,x=0.24436; 經過1000次迭代,x=0.111275
通過對比,明顯看到第一個函數更理想,想要達到我們的要求得迭代次數更少。同時發現,不同的學習率對不同的函數時不一樣的,每個函數的每次迭代都應該尋找一個最適合的學習率才可以使得迭代次數變少並保證函數收斂,不會震盪。
2.優化學習率
調整學習率: 在斜率(方向導數)大的地方,使用小學習率,在斜率(方向導數)小的地方,使用大學習率
(1)計算學習率的方法
視角轉換:
記當前點為x k ,當前搜索方向為d k (如:負梯度方向),因為學習率α是待考察的對象,因此,將下列函數f(x k +αd k )看做是關於α的函數h(α)。
h(α)=f(x k +αd k) ,α>0
當α=0時,h(0)=f(x k )
導數
學習率α的計算標准:
因為梯度下降是尋找f(x)的最小值,那么,在x k 和d k 給定的前提下,即尋找函數f(x k +αd k )的最小值。即:
進一步,如果h(α)可導,局部最小值處的α滿足:
學習率函數導數的分析:
將α=0帶入:
下降方向d k 可以選負梯度方向
從而:
如果能夠找到足夠大的α,使得
則必存在某α,使得
α * 即為要尋找的學習率。
(2)求a的兩種方法
1)二分線性搜索:不斷將區間[α1, α2]分成兩半,選擇端點異號的一側,知道區間足夠小或者找到當前最優學習率。
2)回溯線性搜索:基於Armijo准則計算搜素方向上的最大步長,其基本思想是沿着搜索方向移動一個較大的步長估計值,然后以迭代形式不斷縮減步長,直到該步長使得函數值f(x k +αd k )相對與當前函數值f(x k )的減小程度大於預設的期望值(即滿足Armijo准則)為止。
代碼實現:
1 def get_A_Atmiho(x,d,a): 2 c1=0.3 3 now=f(x) 4 next=f(x-a*d) 5 #下面的循環是尋找最大的步長a,使得目標函數可以向減小的方向移動 6 count=30 7 while next<now: 8 a=a*2 9 next=f(x-a*d) 10 count=-1 11 if count==0: 12 break 13 #尋找一個比較大的a使得減小后的函數值相對於當前函數值的差滿足預設的期望值 14 count=50 15 while next>now-c1*a*d**2: 16 a=a/2 17 next=f(x-a*d) 18 count-=1 19 if count==0: 20 break 21 return a;
加上上面這個求步長的函數后,每次求值不管x的初始值是什么,迭代次數一般不多於20次就可達到要求得精度,而以前固定步長都要迭代200步左右。通過調整c1可以改變預設期望值,當c1比較小時,一般迭代次數就會減少
回溯與二分線性搜索的異同:
(1)二分線性搜索的目標是求得滿足h‘(α)≈0的最優步長近似值,而回溯線性搜索放松了對步長的約束,只要步長能使函數值有足夠大的變化即可。
(2)二分線性搜索可以減少下降次數,但在計算最優步長上花費了不少代價;回溯線性搜索找到一個差不多的步長即可。