文章轉(zhuǎn)自:http://www.reibang.com/p/c7e642877b0e
說明:本文關于梯度和梯度下降的概念全部copy自前述鏈接棉圈,文章內(nèi)容淺顯易懂,不失為一篇好文某抓,感謝作者的分享揖膜!
以下鏈接較為深入看锉,同樣也是好文:https://www.cnblogs.com/pinard/p/5970503.html
文章主要內(nèi)容:
- 梯度下降的場景假設
- 梯度
- 梯度下降算法的數(shù)學解釋
- 梯度下降算法的實例
- 梯度下降算法的實現(xiàn)
- Further reading
梯度下降的場景假設
梯度下降法的基本思想可以類比為一個下山的過程姿锭。假設這樣一個場景:一個人被困在山上,需要從山上下來(i.e. 找到山的最低點伯铣,也就是山谷)呻此。但此時山上的濃霧很大,導致可視度很低腔寡。因此焚鲜,下山的路徑就無法確定,他必須利用自己周圍的信息去找到下山的路徑放前。這個時候忿磅,他就可以利用梯度下降算法來幫助自己下山。具體來說就是凭语,以他當前的所處的位置為基準葱她,尋找這個位置最陡峭的地方,然后朝著山的高度下降的地方走似扔,同理吨些,如果我們的目標是上山搓谆,也就是爬到山頂,那么此時應該是朝著最陡峭的方向往上走豪墅。然后每走一段距離泉手,都反復采用同一個方法,最后就能成功的抵達山谷偶器。
我們同時可以假設這座山最陡峭的地方是無法通過肉眼立馬觀察出來的斩萌,而是需要一個復雜的工具來測量,同時屏轰,這個人此時正好擁有測量出最陡峭方向的能力颊郎。所以,此人每走一段距離亭枷,都需要一段時間來測量所在位置最陡峭的方向袭艺,這是比較耗時的搀崭。那么為了在太陽下山之前到達山底叨粘,就要盡可能的減少測量方向的次數(shù)。這是一個兩難的選擇瘤睹,如果測量的頻繁升敲,可以保證下山的方向是絕對正確的,但又非常耗時轰传,如果測量的過少驴党,又有偏離軌道的風險。所以需要找到一個合適的測量方向的頻率获茬,來確保下山的方向不錯誤港庄,同時又不至于耗時太多!
梯度下降
梯度下降的基本過程就和下山的場景很類似恕曲。
首先,我們有一個可微分的函數(shù)。這個函數(shù)就代表著一座山换团。我們的目標就是找到這個函數(shù)的最小值协屡,也就是山底。根據(jù)之前的場景假設茸俭,最快的下山的方式就是找到當前位置最陡峭的方向吊履,然后沿著此方向向下走,對應到函數(shù)中调鬓,就是找到給定點的梯度 艇炎,然后朝著梯度相反的方向,就能讓函數(shù)值下降的最快腾窝!因為梯度的方向就是函數(shù)之變化最快的方向(在后面會詳細解釋)
所以缀踪,我們重復利用這個方法腺晾,反復求取梯度,最后就能到達局部的最小值辜贵,這就類似于我們下山的過程悯蝉。而求取梯度就確定了最陡峭的方向,也就是場景中測量方向的手段托慨。那么為什么梯度的方向就是最陡峭的方向呢鼻由?接下來,我們從微分開始講起
微分
看待微分的意義厚棵,可以有不同的角度蕉世,最常用的兩種是:
- 函數(shù)圖像中,某點的切線的斜率
- 函數(shù)的變化率
幾個微分的例子:
上面的例子都是單變量的微分婆硬,當一個函數(shù)有多個變量的時候狠轻,就有了多變量的微分,即分別對每個變量進行求微分
梯度
梯度實際上就是多變量微分的一般化彬犯。
下面這個例子:
我們可以看到向楼,梯度就是分別對每個變量進行微分,然后用逗號分割開谐区,梯度是用<>包括起來湖蜕,說明梯度其實一個向量。
梯度是微積分中一個很重要的概念宋列,之前提到過梯度的意義
- 在單變量的函數(shù)中昭抒,梯度其實就是函數(shù)的微分,代表著函數(shù)在某個給定點的切線的斜率
- 在多變量函數(shù)中炼杖,梯度是一個向量灭返,向量有方向,梯度的方向就指出了函數(shù)在給定點的上升最快的方向
這也就說明了為什么我們需要千方百計的求取梯度坤邪!我們需要到達山底熙含,就需要在每一步觀測到此時最陡峭的地方,梯度就恰巧告訴了我們這個方向罩扇。梯度的方向是函數(shù)在給定點上升最快的方向婆芦,那么梯度的反方向就是函數(shù)在給定點下降最快的方向,這正是我們所需要的喂饥。所以我們只要沿著梯度的方向一直走消约,就能走到局部的最低點!
梯度下降算法的數(shù)學解釋
上面我們花了大量的篇幅介紹梯度下降算法的基本思想和場景假設员帮,以及梯度的概念和思想或粮。下面我們就開始從數(shù)學上解釋梯度下降算法的計算過程和思想!
此公式的意義是:J是關于Θ的一個函數(shù)捞高,我們當前所處的位置為Θ0點氯材,要從這個點走到J的最小值點渣锦,也就是山底。首先我們先確定前進的方向氢哮,也就是梯度的反向袋毙,然后走一段距離的步長,也就是α冗尤,走完這個段步長听盖,就到達了Θ1這個點!
下面就這個公式的幾個常見的疑問:
-
α是什么含義裂七?
α在梯度下降算法中被稱作為學習率或者步長皆看,意味著我們可以通過α來控制每一步走的距離,以保證不要步子跨的太大扯著蛋背零,哈哈腰吟,其實就是不要走太快,錯過了最低點徙瓶。同時也要保證不要走的太慢毛雇,導致太陽下山了,還沒有走到山下倍啥。所以α的選擇在梯度下降法中往往是很重要的禾乘!α不能太大也不能太小,太小的話虽缕,可能導致遲遲走不到最低點,太大的話蒲稳,會導致錯過最低點氮趋!
-
為什么要梯度要乘以一個負號?
梯度前加一個負號江耀,就意味著朝著梯度相反的方向前進剩胁!我們在前文提到,梯度的方向?qū)嶋H就是函數(shù)在此點上升最快的方向祥国!而我們需要朝著下降最快的方向走昵观,自然就是負的梯度的方向,所以此處需要加上負號舌稀。
梯度下降算法的實例
我們假設有一個單變量的函數(shù):
微分函數(shù):
初始化啊犬,起點為:
學習率為:
根據(jù)梯前述度下降的計算公式:
我們開始進行梯度下降的迭代計算過程:
如圖,經(jīng)過四次的運算壁查,也就是走了四步觉至,基本就抵達了函數(shù)的最低點,也就是山底:
多變量函數(shù)的梯度下降
我們假設有一個目標函數(shù):
現(xiàn)在要通過梯度下降法計算這個函數(shù)的最小值睡腿。我們通過觀察就能發(fā)現(xiàn)最小值其實就是 (0语御,0)點峻贮。但是接下來,我們會從梯度下降算法開始一步步計算到這個最小值应闯!
我們假設初始的起點為:
初始的學習率為:
函數(shù)的梯度為:
進行多次迭代:
我們發(fā)現(xiàn)纤控,已經(jīng)基本靠近函數(shù)的最小值點:
梯度下降算法的實現(xiàn)
下面我們將用python實現(xiàn)一個簡單的梯度下降算法。場景是一個簡單的線性回歸的例子:假設現(xiàn)在我們有一系列的點碉纺,如下圖所示
(注意:實際的線性回歸完全不需要用迭代的方式做嚼黔,這里只是作為一個梯度下降算法的例子。)
我們將用梯度下降法來擬合出這條直線惜辑!
首先唬涧,我們需要定義一個代價函數(shù),在此我們選用均方誤差代價函數(shù)
此公示中
- m是數(shù)據(jù)集中點的個數(shù)
- ?是一個常量盛撑,這樣是為了在求梯度的時候碎节,二次方乘下來就和這里的?抵消了,自然就沒有多余的常數(shù)系數(shù)抵卫,方便后續(xù)的計算狮荔,同時對結(jié)果不會有影響
- y 是數(shù)據(jù)集中每個點的真實y坐標的值
-
h 是我們的預測函數(shù),根據(jù)每一個輸入x介粘,根據(jù)Θ 計算得到預測的y值殖氏,即
我們可以根據(jù)代價函數(shù)看到,代價函數(shù)中的變量有兩個姻采,所以是一個多變量的梯度下降問題雅采,求解出代價函數(shù)的梯度,也就是分別對兩個變量進行微分
明確了代價函數(shù)和梯度慨亲,以及預測的函數(shù)形式婚瓜。我們就可以開始編寫代碼了。但在這之前刑棵,需要說明一點巴刻,就是為了方便代碼的編寫,我們會將所有的公式都轉(zhuǎn)換為矩陣的形式蛉签,python中計算矩陣是非常方便的胡陪,同時代碼也會變得非常的簡潔。
為了轉(zhuǎn)換為矩陣的計算碍舍,我們觀察到預測函數(shù)的形式
我們有兩個變量柠座,為了對這個公式進行矩陣化,我們可以給每一個點x增加一維乒验,這一維的值固定為1愚隧,這一維將會乘到Θ0上。這樣就方便我們統(tǒng)一矩陣化的計算:
然后我們將代價函數(shù)和梯度轉(zhuǎn)化為矩陣向量相乘的形式:
程序?qū)崿F(xiàn):
首先,我們需要定義數(shù)據(jù)集和學習率
import numpy as np
# Size of the points dataset.
m = 20
# Points x-coordinate and dummy value (x0, x1).
X0 = np.ones((m, 1))
X1 = np.arange(1, m+1).reshape(m, 1)
X = np.hstack((X0, X1))
# Points y-coordinate
y = np.array([
3, 4, 5, 5, 2, 4, 7, 8, 11, 8, 12,
11, 13, 13, 16, 17, 18, 17, 19, 21
]).reshape(m, 1)
# The Learning Rate alpha.
alpha = 0.01
接下來我們以矩陣向量的形式定義代價函數(shù)和代價函數(shù)的梯度
def error_function(theta, X, y):
'''Error function J definition.'''
diff = np.dot(X, theta) - y
return (1./2*m) * np.dot(np.transpose(diff), diff)
def gradient_function(theta, X, y):
'''Gradient of the function J definition.'''
diff = np.dot(X, theta) - y
return (1./m) * np.dot(np.transpose(X), diff)
最后就是算法的核心部分狂塘,梯度下降迭代計算
def gradient_descent(X, y, alpha):
'''Perform gradient descent.'''
theta = np.array([1, 1]).reshape(2, 1)
gradient = gradient_function(theta, X, y)
while not np.all(np.absolute(gradient) <= 1e-5):
theta = theta - alpha * gradient
gradient = gradient_function(theta, X, y)
return theta
當梯度小于1e-5時录煤,說明已經(jīng)進入了比較平滑的狀態(tài),類似于山谷的狀態(tài)荞胡,這時候再繼續(xù)迭代效果也不大了妈踊,所以這個時候可以退出循環(huán)!
完整代碼如下:
import numpy as np
# Size of the points dataset.
m = 20
# Points x-coordinate and dummy value (x0, x1).
X0 = np.ones((m, 1))
X1 = np.arange(1, m+1).reshape(m, 1)
X = np.hstack((X0, X1))
# Points y-coordinate
y = np.array([
3, 4, 5, 5, 2, 4, 7, 8, 11, 8, 12,
11, 13, 13, 16, 17, 18, 17, 19, 21
]).reshape(m, 1)
# The Learning Rate alpha.
alpha = 0.01
def error_function(theta, X, y):
'''Error function J definition.'''
diff = np.dot(X, theta) - y
return (1./2*m) * np.dot(np.transpose(diff), diff)
def gradient_function(theta, X, y):
'''Gradient of the function J definition.'''
diff = np.dot(X, theta) - y
return (1./m) * np.dot(np.transpose(X), diff)
def gradient_descent(X, y, alpha):
'''Perform gradient descent.'''
theta = np.array([1, 1]).reshape(2, 1)
gradient = gradient_function(theta, X, y)
while not np.all(np.absolute(gradient) <= 1e-5):
theta = theta - alpha * gradient
gradient = gradient_function(theta, X, y)
return theta
optimal = gradient_descent(X, y, alpha)
print('optimal:', optimal)
print('error function:', error_function(optimal, X, y)[0,0])
運行代碼泪漂,計算得到的結(jié)果如下:
所擬合出的直線如下:
小結(jié):
至此廊营,我們就基本介紹完了梯度下降法的基本思想和算法流程,并且用python實現(xiàn)了一個簡單的梯度下降算法擬合直線的案例萝勤!
最后露筒,我們回到文章開頭所提出的場景假設:
這個下山的人實際上就代表了反向傳播算法,下山的路徑其實就代表著算法中一直在尋找的參數(shù)Θ敌卓,山上當前點的最陡峭的方向?qū)嶋H上就是代價函數(shù)在這一點的梯度方向慎式,場景中觀測最陡峭方向所用的工具就是微分 。在下一次觀測之前的時間就是有我們算法中的學習率α所定義的趟径。
可以看到場景假設和梯度下降算法很好的完成了對應瘪吏!