注:本系列所有博客將持續更新並發布在github上,您可以通過github下載本系列所有文章筆記文件
1 引言
最近打算開始寫一些關於機器學習方面的博客,算是對以往接觸過的算法的一個總結,在考慮從哪個算法開始。想了想還是從基礎算法開始,例如本文要說的梯度下降。說梯度下降算法是基礎中的基礎絕不為過,我們必須承認,機器學習中,很多算法都與優化有關,梯度下降算法算是最受歡迎的一類的優化算法,線性回歸、邏輯回歸、SVM、深度學習等等算法都用到了梯度下降。
2 梯度
我們先來分析一個下山問題:假設我們在一座山上,要做的是以最快的速度趕往一個最低的那個山谷,但是我們不知道附近的地形,不知道路線,更不知道海拔最低的山谷在哪。要做到盡快,我們就只能走一步算一步,即每走一步時都選擇下降最多的那個方向走,換句話說就是往最陡的方向走,當走到一個位置無論下一步往哪里邁,海拔都不會降低時,我們就認為我們已經到達了我們要去的山谷。
梯度下降算法與這個下山問題求解思路是一樣的。
假設存在函數$f(x)$,圖像如下圖所示,起始點是的初始值,希望找到函數$f(x)$的最小值點。
在下山問題中,我們人可以通過視覺或者其他外部感官上的觸覺來感知東南西北不同方向的坡度,然后選擇最陡的方向,但在函數求最小值問題中,計算機可沒有視覺等外部感官,那么怎么來判斷那個方向最陡呢?
還記得大學的時候學過(其實高中也學過)的導數知識嗎?導數定義如下:
${f}'(x)=\underset{\Delta x\to 0}{\mathop{\lim }}\,\frac{\Delta y}{\Delta x}=\underset{\Delta x\to 0}{\mathop{\lim }}\,\frac{f({{x}_{0}}+\Delta x)-f({{x}_{0}})}{\Delta x}$
當然,定義不是關鍵,關鍵在於它的的幾何意義:函數$f(x)$在$x={{x}_{0}}$處的導數表示在這一點上的切線斜率,換句話說,函數$f(x)$在${{x}_{0}}$處的導數代表着$f(x)$在$x={{x}_{0}}$附近的變化率,也就是導數可以衡量$x$取值在${{x}_{0}}$附近時$f(x)$隨$x$變化的快慢。$\left| {f}'(x) \right|$越大,$f(x)$隨x變化得越快,函數在圖像上表現得越陡峭。
導數解決了一元函數中函數值隨自變量變化快慢的問題,但對於多元函數例如上面3為圖像所表示的函數,導數就力有未逮了,這時候我們需要用到偏導的知識:
$\frac{\partial }{\partial {{x}_{i}}}f({{x}_{0}},{{x}_{1}},\ldots ,{{x}_{n}})=\underset{\Delta x\to 0}{\mathop{\lim }}\,\frac{\Delta y}{\Delta x}=\underset{\Delta x\to 0}{\mathop{\lim }}\,\frac{f({{x}_{0}},\ldots ,xi+\Delta x,\ldots ,{{x}_{n}})-f({{x}_{0}},\ldots ,{{x}_{i}},\ldots ,{{x}_{n}})}{\Delta x}$
導數與偏導數本質是一致的,但偏導可以衡量除$x$外其他自變量保持不變時,函數值隨xj所在維度變化快慢。分別對不同維度求偏導,我們就可以知道函數$f({{x}_{0}},{{x}_{1}},\ldots ,{{x}_{n}})$在不同維度(方向)變化快慢,從而綜合各個方向,獲取一個最佳的方向收斂(下山)。
好了,我們現在可以回歸到梯度的問題了。什么是梯度呢?函數在某一點的梯度是一個向量,它的方向與取得最大方向導數的方向一致,而它的模為方向導數的最大值。
我們以一元線性回歸為例,假設模型為:
$y=f(x)={{\theta }_{0}}+{{\theta }_{1}}\cdot x$
$\begin{align}
& \frac{\partial J({{\theta }_{0}},{{\theta }_{1}},\ldots ,{{\theta }_{n}})}{\partial {{\theta }_{k}}}=\frac{\partial }{\partial {{\theta }_{k}}}\frac{1}{2m}\sum\limits_{i=1}^{m}{{{({{\theta }_{0}}+{{\theta }_{1}}\cdot {{x}_{1}}+{{\theta }_{2}}\cdot {{x}_{2}}+\ldots +{{\theta }_{n}}\cdot {{x}_{n}}-{{y}_{i}})}^{2}}} \\
& =\frac{1}{2m}\sum\limits_{i=1}^{m}{2\cdot ({{\theta }_{0}}+{{\theta }_{1}}\cdot {{x}_{1}}+{{\theta }_{2}}\cdot {{x}_{2}}+\ldots +{{\theta }_{n}}\cdot {{x}_{n}}-{{y}_{i}})\cdot }\frac{\partial }{\partial {{\theta }_{k}}}({{\theta }_{0}}+{{\theta }_{1}}\cdot {{x}_{1}}+{{\theta }_{2}}\cdot {{x}_{2}}+\ldots +{{\theta }_{n}}\cdot {{x}_{n}}-{{y}_{i}}) \\
\end{align}$
$\begin{align}
& \frac{\partial J({{\theta }_{0}},{{\theta }_{1}},\ldots ,{{\theta }_{n}})}{\partial {{\theta }_{k}}}=\frac{1}{2m}\sum\limits_{i=1}^{m}{2\cdot ({{\theta }_{0}}+{{\theta }_{1}}\cdot {{x}_{1}}+{{\theta }_{2}}\cdot {{x}_{2}}+\ldots +{{\theta }_{n}}\cdot {{x}_{n}}-{{y}_{i}})\cdot }{x_k} \\
& =\frac{1}{m}\sum\limits_{i=1}^{m}{(f({{x}_{i}})-{{y}_{i}})\cdot }{x_k} \\
\end{align}$
3 更新梯度
知道怎么求偏導,我們就可以獲得在不同位置下的梯度,進一步的,就可以進行梯度更新,還是先以上面說過的一元線性回歸為例,假設本次參數初始取值為${{\theta }_{0}}$、${{\theta }_{1}}$,下一次參數取值${{{{\theta }'}}_{0}}$和${{{{\theta }'}}_{1}}$:
${{{{\theta }'}}_{0}}\text{=}{{\theta }_{0}}\text{-}\beta \frac{\partial J({{\theta }_{0}},{{\theta }_{1}})}{\partial {{\theta }_{0}}}\text{=}{{\theta }_{0}}-\frac{\beta }{m}\sum\limits_{i=1}^{m}{(f({{x}_{i}})-{{y}_{i}})}$
${{{{\theta }'}}_{1}}\text{=}{{\theta }_{1}}\text{-}\beta \frac{\partial J({{\theta }_{0}},{{\theta }_{1}})}{\partial {{\theta }_{1}}}\text{=}{{\theta }_{1}}-\frac{\beta }{m}\sum\limits_{i=1}^{m}{({{x}_{i}}(f({{x}_{i}})-{{y}_{i}}))}$
然后通過上面的兩個公式不斷迭代更新參數${{\theta }_{0}}$和${{\theta }_{1}}$,直到梯度不在下降,即偏導數為0。用上面的下山問題來說,就是每走一步都計算一下最陡的方向,然后朝這個方向邁一步,然后又計算哪個方向最陡,繼續朝這個方向邁步……直到走到一個地方無論朝哪個方向走,海拔都不會降低,那么就認為到了最低的山谷。
那么,上面兩個式子中的$\beta$是什么呢?在梯度下降算法中,這個$\beta$被稱為學習率,用於控制下降的速度。還是用下山問題來解釋,偏導可以告訴我們,哪個方向最陡,而且偏導的大小就意味着朝這個方向邁一步可以走多遠,如果你覺得這一步的的距離滿足不了你,那么你可以讓B大於1,偏導乘以這個$\beta$,那么你一步可以走的更遠;如果你覺得下山步子太大危險,你可以讓$\beta$處於0和1之間,然后偏導乘以$\beta$,這樣一步邁出距離就會小一些。
是不是$\beta$越大越好呢?不是,有句話怎么說來着,步子大了容易扯着蛋,本來一步正常是走1米,你非要一步走1千米,就可能直接從這座山跨到領一座山,直接躍過了山谷,還怎么找山谷。
是不是$\beta$越小越好呢?也不是,$\beta$太小的話,下山太慢,正常一步1米,你非要一步1毫米,幾十年也下不了山,另外,如果半山腰處有個小坑窪,如果踩了進去,由於步子太小,無論朝哪個方向邁步,都是上坡,就會以為到了山谷,在函數優化問題上,這就是陷入局部最優。
所以,$\beta$的大小還是要視情況而定。
更一般化的,我們將上述梯度更新公式應用到更多維的情況。應用到多維上也是一樣的,只不過計算量更大,因為每一維度都要先求偏導,然后通過下面公式更新參數:
${{{{\theta }'}}_{k}}\text{=}{{\theta }_{k}}\text{-}\beta \frac{\partial J({{\theta }_{0}},{{\theta }_{1}})}{\partial {{\theta }_{k}}}\text{=}{{\theta }_{k}}-\frac{\beta }{m}\sum\limits_{i=1}^{m}{({{x}_{k}}(f({{x}_{i}})-{{y}_{i}}))}$
4總結
本文介紹了梯度下降算法,精髓盡囊括其中。希望對各位讀者有所幫助。