第二十一節 牛頓法和L-BFGS求函數最優解算法
這一節中,咱們講解一個新的求函數最優化的方法就是L-BFGS。如下是本節目錄。app
目錄機器學習
5-多元函數利用牛頓法求駐點 spa
6-BFGS算法翻譯
咱們知道算法在計算機中運行的時候是須要很大的內存空間的.就像咱們解決函數最優化問題經常使用的梯度降低,它背後的原理就是依據了泰勒一次展開式.泰勒展開式展開的次數越多,結果越精確,沒有使用三階四階或者更高階展開式的緣由就是目前硬件內存不足以存儲計算過程當中演變出來更復雜體積更龐大的矩陣.L-BFGS算法翻譯過來就是有限內存中進行BFGS算法,L是limited memory的意思.那算法爲何叫BFGS呢,請看下圖:
上圖中從左到右依次是Broyden,Fletcher,Goldfarb,Shanno.四位數學家名字的首字母是BFGS,因此算法的名字就叫作BFGS算法.接下來咱們就一塊兒來學習BFGS算法的內容。
咱們先來回顧下牛頓法求根問題,好比求1元2次方程的根公式爲,咱們一般管這種形式的根叫解析根。所謂解析解就是你不用給我具體的值,就是一個公式。3次方程也是有解析解的,可是當函數達到5次方以上,就很差找解析解了,對於這種複雜的函數,很遺憾咱們不能找到它的所有根,可是至少有辦法找到它的一個根。
咱們看一個對於一元函數的例子:
對於一個沒法解出解析解的函數來講,如今是一元函數,在只有一個x的狀況下,我最終想找到x令y=0,即函數的根,怎麼找到它?牛頓和另一我的同時分別發現,假如這個函數是連續可導的,我隨機出來一個x1,總能求它在這點x1的導數,導數是一個實數,它是能表明切線的斜率,那麼咱們就在這個x1點上畫一個原函數切線,這個切線必定會與x軸相交,除非特別倒黴,你一步就隨機到它的駐點上了,也不用求了,你找的就是駐點。不倒黴的狀況下必定會使x1點的切線和x軸有個交點,咱們命名爲x2。 點完以後,又能夠找一下x2對應在函數上的點,再畫一條切線找到了x3,這時候相比x1,距離跟的位置來講比較近,而後發現通過有限次數的迭代以後,怎麼迭代都不會變化。它仍是會產生震盪,通過震盪以後,最終會收斂在某一個點上,而這個點就是函數的根。因此說牛頓法利用幾何直覺就是在找到某一個函數與x軸的交點。
咱們分析下幾何原理:
函數自己f(x)也是已知的,那麼f(x1)就能夠計算。x2是x1切線的位置,咱們創建一個關於x2,x1的解析式,三角形這條邊是x1-x2,另一條邊是f(x1),若是用f(x1)/ x1-x2就應該是這條線的斜率,斜率又等於x1這點導數的值。因此x2,x1創建一個關係,x2 = x1-f(x1)/ f`(x1),此時x2就可求了。咱們大的思路想從x1找到x2,從x2找到x3,最終找着發現xn,xn+1它倆沒區別的時候xn就是函數的根。所以創建了一個xn,xn-1的之間關係的迭代公式:
xn=xn-1- f(xn-1)/ f`(xn-1)
咱們在求數值解的時候,雖然咱們求根法是求損失函數最小值,當最小值只差一點點的時候,對模型的預測結果影響不大,可是它在底部會震盪好久。 對於這種在底部頻繁震盪的狀況下,一般會設置超參tolerance,當xk,xk+1的變化已經小於你設的閾值的時候,我就認爲它已經收斂了,而不去非得接近它,駐點數自己就是不那麼可控的。設置超參tolerance,它幾乎在不犧牲精度的狀況下來對咱們這個函數最優化算法進行。
總結下牛頓法求根的流程:
.一、已知函數f(x)的狀況下隨機產生x0。
二、由已知的x0按照 xn=xn-1- f(xn-1)/ f`(xn-1)公式進行n次迭代。
三、當迭代結果xn與上一次迭代結果xn-1相同或小於必定閾值時,本次的結果即爲函數f(x)的根。
既然利用上述辦法找到任意函數的根,能不能借這個找到函數最小值呢?咱們能夠利用駐點的知識,雖然駐點不必定是極值點,極值點也不必定是駐點,但大部分狀況下兩個值相等,駐點也就是導數爲零的點,即原函數最小值的點。 因此咱們須要找到導函數爲零的點,實際上也就是導函數的根。導函數是一個函數,它是用來計算一個函數導數的工具,給我一個x,我就算這個原函數在這個點的導數是多少的這麼一個函數。若是咱們能把原函數的導函數寫出來,進而求導函數的根,就解決了求原函數最小值的問題。
既然都是求根問題,咱們可不能夠利用上面的方法呢?確定是能夠的,只不過如今的函數是咱們要求的導函數而已。咱們看下剛纔原函數求根的迭代公式:xn+1 = xn-f(xn)/ f`(xn)。對於導函數來講,惟一的區別就是f(xn)表達式不一樣,因此咱們此時的原函數就是f`(xn),此時f`(xn)的導函數就是f``(xn)。最終的迭代公式就是:
xk = xk-1-f'(xk-1)/ f''( xk-1
經過這個東西,我最終找到xn再也不是f(x)的根,而是f(x)導數的根,也就是駐點。
總結下利用牛頓法求函數的駐點過程:
一、當函數f(x) 的一階導數 f’(x) = 0 時點(x,f(x))爲函數f(x)的駐點
二、求某函數的駐點即爲求該函數的導函數的根,一樣能夠利用牛頓法進行求解
三、對於f(x) 函數來講 迭代公式爲 xk = xk-1 - f’(xk-1)/f’’(xk-1)
牛頓法求駐點本質其實是二階泰勒展開公式。咱們先來回顧下什麼是泰勒展開。所謂泰勒展開就是把任意一個複雜函數在某個點附近,用一個有限長度的多項式來擬合,那麼一般多項式在xk點附近展開是φ(x)=f(x)+ f’(x-xk)+ 1/2!f''(xk)*(x-xk)^2+1/3!f'''(xk)(x-xn)^3...,一直往上加,越加越像原函數。 咱們看下一階展開就是φ(x)=f(x)+ f’(x-xk)。它本質就是y=ax+b,一條直線,只不過a和b裏面雜糅了不少關於xk函數的數值,a和b是經過xk這個點的函數還有一階導函數算出來的,因此一階泰勒展開就是在xk附近用一條直線儘可能的去擬合原函數。什麼叫作xk儘可能的去擬合原函數?意思是在xk點附近,我不關注其它地方,我就在你周圍畫一條直線,你能跟我原先xk點的附近重合的越多越好。而二階泰勒展開式是ax2+bx+c,只不過a,b,c是經過這些導數什麼雜糅在一塊兒算出來,不管這些東西等於多少,它始終是一個實數,它必定就是這個形勢,這個形式是一個拋物線。
咱們看下任意函數在 xk點附近的二階泰勒展開公式爲:
該公式表達的函數φ(x) 的幾何意義爲:經過2次函數對於原函數的最佳擬合。當φ'(x)=0時:
解釋下這個公式怎麼來的:對x求導,沒有對xk求導的,xk是個已知數,第一項f(xk)沒有x,求導等於0。第二項對x的求導,把它展開變成x*f’(xk)就剩這麼一個東西,f’(xk)它是個數,它不是x函數。第三項對x求導結果是1/2 f''(xk).2(x-xk) 。綜合以上結果就獲得φ'(x)=0的解析式,也就是函數二階泰勒展開所擬合出來的拋物線的最小值。
把上述φ'(x)=0的解析式展開成x= xk -f’(xk)/f’’(xk)。發現恰好和以前牛頓法求駐點xk = xk-1 - f’(xk-1)/f’’(xk-1)的迭代公式一致。因此下一次xxk的迭代值就是以它擬合出來的拋物線的最小值對應的x來做爲我原函數根的下一次迭代值。
咱們畫圖示意牛頓法求駐點的本質:
由於一階泰勒展開是一條直線它沒有最小值,而拋物線有最小值,實際上它就是在拿擬合出來的拋物線的最小值當成更好一點的x做爲下一次的起始點,下次到這新的點,就又找了一個拋物線,以此類推,相似於咱們每次拿一個碗形的曲線去套原先的曲線,因此它能更好的擬合在某一點附近的真實曲線狀況,正由於如此,這個東西帶來的好處就是牛頓法比梯度降低在底部震盪次數小不少,它可以讓咱們在求函數最優解的過程當中有更少的收斂次數。
上面所說的都是針對一元的,而機器學習裏面都是多元的,所謂的x在機器學習裏面是誰?你要優化損失函數,損失函數是跟着w來的,咱們必定要了然一個事,在機器學習的訓練集裏,x是已知數,你惟一未知數就是w。x都是w的係數,它在損失函數裏面不管什麼狀況,最終都會變成w的係數。那麼這裏面的w其實是機器學習裏面的未知數x,w有多少個,每每不止一個。對於多元函數求駐點怎麼求?實際在多元函數中,一階導數映射到多元函數裏就是梯度:即一階導數f'(x) ----->梯度
梯度就是它的全部一階導數給它寫一塊去。好比你原來就一個x,求個導就完事了。你如今有十個x,你求誰都不合適,你就乾脆把十個逐個求個叫偏導,而後把這第一個x求偏導的函數放在這個向量的第一位,第二個求偏導的函數放在向量第二位
,最後一個求偏導放在最後一位,組成一個向量。這個向量裏面存的目前來說仍是一個函數,這個叫作梯度函數向量,而梯度是否是指的是某個點的梯度,就像導數指的是某一個點的導數同樣,那麼梯度裏邊存的就再也不是函數,而是把某組x帶到這一組函數裏面,去獲得了那一組實數的向量值,全部你只要說梯度,雖然它裏面寫的是字母,但實際上知道這是一個真真切切的實數。 它是一個實數向量。 那麼梯度是什麼狀況?假設你有十個w,梯度就有10個元素,由於要對10個未知的w逐個求偏導放到向量裏面。
對第一個w求偏導,它得的結果是一個導函數,它們一般咱們在寫梯度的時候,有時候會這麼寫,這個x表明一個向量,它並非向量中的某個元素,這個x就已經包含了若干個x了,x1到xn,k就表明第幾代x。 這個梯度的意思就是說你先把這些偏導函數擱在這以後,而後再對當前這一代xk的具體的值帶到這裏來求出的結果,這個東西叫梯度。涉及到梯度,就意味着有必定的方向。
多元函數中,咱們以前的求駐點的迭代公式xk = xk-1 - f’(xk-1)/f’’(xk-1),f’(x)在多元函數中就是它對應的的梯度g(x) ,f’’( x)叫作Hessian矩陣對應關係爲:一階導數f''(x) ----->Hessian矩陣
這個矩陣是怎麼求?就是它要求兩次導,假如說原來對x1求導,求了以後還對x1求一次導,它還須要再對x1到xn分別求一次導,這樣就造成了一個巨大的偏導數的矩陣,這個矩陣的狀況應該是N乘N的,它的對角線元素是對同一個自變量求兩次,而其它是各類各樣的排列組合。這個就是二階導數Hessian矩陣。
因此咱們的迭代公式演變爲:從到
其中gk就是多元函數一階導,Hk就是多元函數二階導。gk原來在分子中,Hessian矩陣應該是除以二階導數,因此變成了矩陣的逆。咱們能夠看一下Hk矩陣,逆矩陣仍是一個N*N的,gk是一個N*1的矩陣,它倆相乘獲得是一個N*1的向量,就是一個高高的向量, N行1列。xk自己也是一個高高的向量,它倆作減法徹底沒有問題。可是Hk矩陣的N*N就給咱們帶來了一個很是不喜歡的問題,這個矩陣太難運算的,當你有1000個維度的時候,就是1000×1000的矩陣,而後1萬個維度的時候,10000×10000,維度就爆炸了。而牛頓法求駐點又是一個迭代算法,因此這個困難咱們還要面臨無限屢次,致使了牛頓法求駐點在機器學習中沒法使用.有沒有什麼解決辦法呢。
BFGS算法是經過迭代來逼近的算法.逼近的方式以下:
其中:。I是單位矩陣,
BFGS就是經過迭代來逼近Hk的逆矩陣矩陣,其中第一步的D矩陣是單位矩陣.所謂單位矩陣就是隻有對角線元素爲1,其他全爲零的矩陣。根據以前的迭代公式:,除了第一步仍是須要計算以前的逆矩陣H1,第一步迭代須要計算出x2=x1-H1*g1,s1=x2-x1,y1=g2-g1。由於有x2,因此g2是其梯度,也可求,有了s1,y1即可以求D2來近似代替H2的逆矩陣,而後一步步迭代,求出駐點。
咱們要經過牛頓求駐點法和BFGS算法來求得一個函數的根,兩個算法都須要迭代,慢慢逼近函數根,通過k次迭代之後,所獲得的解就是機器學習中目標函數導函數的根.這種兩個算法共同迭代的計算方式,咱們稱之爲On The Fly。
回顧一下梯度降低的表達式,在BFGS算法迭代的第一步x2=x1-D1*g1,單位矩陣與梯度g相乘,就等於梯度g,形式上同梯度降低的表達式是相同的。至關於學習率等於1的梯度降低,因此BFGS算法能夠理解爲從梯度降低逐步轉換爲牛頓法求函數解的一個算法.
雖然咱們使用了BFGS算法來利用單位矩陣逐步逼近H矩陣,可是根據Dk+1的公式,每次計算的時候都要存儲上一代的Dk矩陣,Dk矩陣有多大呢.假設咱們的數據集有十萬個維度(不算特別大),那麼每次迭代所要存儲D矩陣的結果是74.5GB.
咱們沒法保存如此巨大的矩陣內容,如何解決呢? L-BFGS 算法上陣。
咱們每一次對D矩陣的迭代,都是經過迭代計算sk和yk獲得的.既然存不下D矩陣,那麼咱們存儲下全部的sk和yk,想要獲得D10就用單位矩陣同存儲下的s1和y1到s10和y10計算就能夠了.這樣一個時間換空間的辦法,有效節省了內存空間。
可是,僅僅是這樣仍是不夠的,由於當迭代次數很是大的時候,咱們的內存一樣存不下.這個時候只能丟掉一些存不下的數據.假設咱們設置的存儲向量數爲100,當s和y迭代超過100時,就會扔掉第一個s和y,存儲s2到s101和y2到y101,每多一次迭代就對應的扔掉最前邊的s和y。假如最後收斂次數是1000的話,只保留s901,y901從而計算出D901 ,而後再保留s902,y902計算出D902,依次根據s1000,y1000,從而算出D1000,按理說須要D900才能計算出D901 ,此時咱們粗暴的將D901置爲單位矩陣I,這樣雖然損失了精度,但確能夠保證使用有限的內存將函數的解經過BFGS算法求獲得。
雖然L-BFGS算法是線性收斂,可是每次迭代的開銷很是小,所以L-BFGS算法執行速度仍是很快的,並且因爲每一步迭代都能保證近似矩陣的正定,所以算法的魯棒性仍是很強的。