轉載自https://www.2cto.com/kf/201607/526447.html
本章總結優化學習率的知識,而前置知識就是“線性回歸、梯度下降算法”,因此如果這一章你看的雲里霧里甚至連學習率是什么都不知道的話就需要先吧前置知識搞定了。
其他說明
因為本總結的前置知識是“線性回歸、梯度下降算法”,所以之后的內容都是以“求目標函數f(x)的極小值”為目的。
不過不用擔心求極大值的話該怎么辦,因為直接給f(x)加個負號就將問題轉換為了求極小值問題了。
在順便一提,個人感覺正因為研究了這么多求極小值的東西,於是大伙為了省事,就凡是遇到求極大值的問題則先將其轉成求極小值,於是乎會經常看到這句話“習慣上我們將其轉換成求極小值”....
什么是優化學習率
以梯度下降說明。
假設我將學習率固定為1時需要迭代10次才會收斂的話,那如果我將學習率改為第一次步長為8,第二次步長為2,則可能兩次就收斂了。(這里的數字不太准確,但大概是這樣的意思)
很明顯,后者的收斂速度更快,而上面對學習率的調整就是優化學習率。
PS:就好像一個人下山,如果他以每步1M步伐下山可能要走10小時,那若他一開始以每步8M,然后等走了一半多了在每步2M的話,則到達山腳的時間會明顯縮短。
話說,雖然在寫這片文章時我還沒入這一行,但我聽到的都是些“工作時很多時候就拍腦門選一個學習率就好,若感覺收斂太慢就調大些”這樣的內容,感覺沒必要在這上面花費太多功夫。
不過個人感覺,如果能把這個知識掌握了,那工作起來會事半功倍。
怎么優化學習率
這個得一點點講了。
既然我們的目標是優化學習率,那我們需要先轉換下視角:你看啊,對於某個函數,如果我們的目標就是求函數中的參數x,那我們就將函數看成是關於x的函數。同理,既然這里的目標是函數中的學習率α,那我們就將函數看作是關於α的函數。又因為一般函數模型是:f(xk+αdk),其中dk是搜索方向(如對梯度下降來說,dk是負梯度方向),所以在轉換視角后,我們將其看作是關於α的函數h(α),即:
h(α)= f(xk+αdk)
PS:一般學習率是大於0的,即α>0
既然已經是關於α的函數了,那對於梯度下降來說我們的目標就從“x為多少時函數的值最小 -- 注:樣本xk是已知的,當前的搜索方向dk即梯度也可以求出來,只不過哪個xk會使函數最小不知道”,即:
arg_xmin f(xk+αdk)
變成了“在給定xk和dk的前提下,尋找α為多少時,能讓函數下降的最快”,即:求對關於α的函數h(α)求“α = ? 時,函數h(α)最小”。
這就簡單了,對h(α)求導並另導數為0唄,即:
h’(α)= ▽f(xk+αdk)Tdk= 0
這樣求得的α就是一個對當前xk的一個十分優秀的學習率α。
畫個圖的話就像這樣:
以前學習率固定時,可能每次只下降這么多:
通過上面的方法就能一次性下降這么多(粉線是切線)

不過,如果你細心的話現在應該有點繞,即:h(α) 不就是 f(xk+αdk) 嗎?那我對h(α) 求導后找到個最小值不就是f(xk+αdk)的最小值嗎?按照這里理論,我不就一次性讓函數收斂了?怎么上面的圖還沒有一次性收斂?你畫錯了吧!
嘛,上面的圖的確有些不准確,是幫助理解而已,因此我要補充下面這句話:對h(α)求導並讓導數為0后可以得到一個對當前xk的十分優秀的學習率α,但這個α可能並不能讓原函數一次性收斂。
原因是:我們之前通過“視角轉換”將函數變成了關於α的函數h(α),所以如果畫坐標軸的話,那坐標軸的x軸就變成了α軸,即:函數圖像會變成關於α的圖像(這和原函數的圖像是不同的)。於是對h(α)求導並讓導數為0后可以得出一個關於α的圖像的極小值點,這時就得到了一個“對當前xk的一個十分優秀的學習率α”,但因為“關於α的圖像和原函數的關於x的圖像是兩個圖像”,所以這個α可能並不能讓原函數一次性收斂。
不過,雖然不能讓原函數一次性收斂,但無論如何,也比固定α好,對吧。
現在總結下上面的步驟:
1、使用原函數對α求導,求出學習率α;
2、按照搜索方向更新函數(如梯度下降)
3、重復上面兩步直到收斂。
一個更簡單的方法(二分線性搜索)
說實話啊,雖然上面的步驟沒問題,但如果計算h’(α)=0十分惡心咋辦?
難道(╯‵□′)╯︵┻━┻不求了?
當然可以!
且聽我一一道來。
首先,對於f(xk+αdk),如果令α = 0的話就有:
h’(0)= ▽f(xk +0*dk)Tdk = ▽f(xk)Tdk
上面的▽f(xk)是梯度(這是對原函數求導啊),dk是搜索方向,如果令dk為負梯度方向即:dk = -▽f(xk) 的話,就有:h’(0) < 0,即α = 0時,h’(0) < 0。
這時如果我們找到一個足夠大的α,使得h’(α)>0的話,則必存在某α,可以使h’(α)=0,而這個α就是我們要尋找的學習率。
於!是!使用折半查找就OK了!如:
對於h’(α1)< 0、h’(α2) > 0
若h’( (α1+α2)/2 ) < 0,那就另a1 = (α1+α2)/2
若h’( (α1+α2)/2 ) > 0,那就另a2 = (α1+α2)/2
重復上面的步驟,直到找到h’(α)=0,這樣就找到了α。
再優化一下(回溯線性搜索)
上面的折半查找已經很方便了,但以h’(α)=0作為是否找到α的條件還有些麻煩,而使用回溯線性搜索的Arimijo准則作為判斷條件就很方便了。
首先是Armijo准則:首先給一個較大的學習率,然后不斷縮減學習率,如果對於函數f(xk+αdk)當前的學習率使函數從當前的位置f(xk)的減小一定程度后還大於預設的期望值,那這個學習率就符合要求了。
什么意思?你看,對於函數f(xk+αdk),既然是求最小值,那對於當前的值f(xk)減小一定程度后就有個新值f(xk+1),於是,如果我們將f(xk+1)作為預設的期望值,即我們希望f(xk)在某個學習率α的情況下減小一定程度后可以到達f(xk+1),那這個α就是我們希望得到的α了對吧。而因為 這個減小程度在Armijo准則中是公式:
c1α▽f(xk)Tdk,c1∈(0, 1)
因為dk一般取梯度負方向,所以用式子表達上面的話的話就是:
f(xk+1)= f(xk) + c1α▽f(xk)Tdk,c1∈(0, 1)
但是在計算中實現上面的等號挺麻煩的,因為我們是不斷縮減學習率,只要我們縮減的程度沒把握好,就會有“上一個還f(xk+1) < f(xk) + c1α▽f(xk)Tdk,下一個就f(xk+1) > f(xk) +c1α▽f(xk)Tdk”的情況。
於是為了方便,只要f(xk+1) ≤ f(xk) + c1α▽f(xk)Tdk就OK了,而這就是Armijo准則的方程。
PS:為什么要給一個較大的學習率后還不停的縮減?直接選這個較大的學習率不就好了? 看下圖: 如果學習率太大一下子從x1走到了x2的話,那還求個屁的最小值啊。 於是我們就先規定個期望值,比如:你這次下降到f(x3)就行了。這樣就能控制學習率為一個我們期望的值了。 |
回溯與二分線性搜索的異同
二分線性搜索的目標是求得滿足h’(α)≈0的最優步長近似值,而回溯線性搜索放松了對步長的約束,只要步長能使函數值有足夠大的變化即可。
二分線性搜索可以減少下降次數,但在計算最優步長上花費了不少代價;回溯線性搜索找到一個差不多的步長即可。
回溯線性搜索代碼(出自小象學院的鄒博老師)
紅框:若傳來的學習率a不滿足h’(a) > 0就將a擴大2倍,因此到達綠色框的代碼時a已經滿足h’(a) > 0。或者說紅框中是為了找到“第一個”不滿足函數下降的學習率。正常情況下,只要沿着負梯度方向下降微小的值,next<now是恆成立的,因此,不斷執行紅框的代碼,可以不斷抬高學習率,直到發現不滿足條件的(即:“步子太大”),從而保證接下來綠框中的有效執行。< p="">
綠框: 如果學習率不滿足Armijo准則,就把學習率a降一半,看看新的學習率是否滿足。
最后返回學習率。
回溯線性搜索的改進-二次插值法
怎么還沒完啊?
我也這樣想過,但改進是永無止境的,認命吧- -....
不過在介紹插值法之前還得再說個很簡單的預備知識,如下:
如果知道3個點,那就可以確定一個二次曲線經過這三個已知點,換句話說為了確定一個二次曲線就需要3個類型的信息,因此我們就可以這樣想:如果題目給定了在一個點x1處的函數值y1=f(x1)、在該點處的切線值即x1處的導數值f’(x1)、x2點處的函數值y2=f(x2),那么也是能唯一的確定一個二次函數,看下圖:
而如果x1=0,x2=a的話,那這個二次函數的方程就是下面的樣子:
PS:這個是這樣算出來的: 假設這個二次函數的方程是 f(x) = px2 + qx + z,因為f(0)、f’(0)、f(a)是已知的,f’(x)的可以求出來,即f’(x) = 2px + q,那把這三個值代入f(x)和f’(x)就可以把p、q、z求出來了,就得出上面的式子了。
對這個式子求極值的方法是:
假設式子為:h(a) = qx2 + px + z
則x在 - p/(2q) 處可以取得極值
這是初中的知識,所以別問為什么,像初中生一樣直接拿去用就好。
好了預備知識說完了,下面介紹插值法。
經過前面的內容已經知道:我們找學習率a的方法是,找一個h’(a) < 0,一個h’(a) > 0,然后不停的二分查找,直到h’(a) = 0。
那有沒有一個更好的方法?有的。
首先,對於學習率a,其函數h(a)是一個二次函數。
PS:一個a代入h(a)有一個值,最后就是在以a為橫軸h(a)為縱軸的坐標軸上畫了一條彎曲的曲線,這是個二次曲線沒問題吧
然后對於這個二次函數我們總結下已知的信息:
1,h(a)一定經過兩個點:a=0處的值h(0)、當前的准備嘗試的學習率a0的值h(a0)。其中h(0)就是當前的函數值f(xk),因為對於h(α) = f(xk+αdk),如果a=0,就有h(0) = f(xk);而當前准備嘗試的學習率如果滿足Armijo准則就直接返回該學習率,否則才需要找個更好的學習率。
2,當前xk處的的導數可以求出來,即f’(xk)已知,也就是h’(0)已知。
即 :已知h(0)、h’(0)、h(a0)
接下來利用剛才的預備知識,我們就可以構造出一個二次函數來近似學習率a的曲線了,即:
PS:這個只是近似,因為只是通過3個數據來確定的曲線,和真正的h(a)是有些不同的,不過,雖然這條曲線和真正的曲線有些誤差,但可以使用,這就足夠了。
而我們的目標是什么來着?對,求h’(a)=0時的a,也就是求h(a)的極值,那就直接利用初中的知識
式1
求hq(a)的極值就OK了,這多簡單,初中生都會。
過程總結
1,利用式1求a1
2,若a1滿足Armijo准則,則輸出該學習率,否則繼續迭代。
代碼(出自小象學院的鄒博老師)
最后總結
一般的說,回溯線性搜索和二次插值線性搜索能夠基本滿足實踐中的需要。