- 梯度下降的場(chǎng)景假設(shè)
- 梯度
- 梯度下降算法的數(shù)學(xué)解釋
- 梯度下降算法的實(shí)例
- 梯度下降算法的實(shí)現(xiàn)
- Further reading
本文將從一個(gè)下山的場(chǎng)景開(kāi)始,先提出梯度下降算法的基本思想榴捡,進(jìn)而從數(shù)學(xué)上解釋梯度下降算法的原理恰画,最后實(shí)現(xiàn)一個(gè)簡(jiǎn)單的梯度下降算法的實(shí)例围详!
歡迎關(guān)注公眾號(hào): 進(jìn)擊的633
持續(xù)更新深度學(xué)習(xí)相關(guān)
梯度下降的場(chǎng)景假設(shè)
梯度下降法的基本思想可以類(lèi)比為一個(gè)下山的過(guò)程外驱。假設(shè)這樣一個(gè)場(chǎng)景:一個(gè)人被困在山上屠凶,需要從山上下來(lái)(i.e. 找到山的最低點(diǎn)馋记,也就是山谷)号坡。但此時(shí)山上的濃霧很大,導(dǎo)致可視度很低梯醒。因此宽堆,下山的路徑就無(wú)法確定,他必須利用自己周?chē)男畔⑷フ业较律降穆窂饺紫啊_@個(gè)時(shí)候畜隶,他就可以利用梯度下降算法來(lái)幫助自己下山。具體來(lái)說(shuō)就是号胚,以他當(dāng)前的所處的位置為基準(zhǔn)代箭,尋找這個(gè)位置最陡峭的地方,然后朝著山的高度下降的地方走涕刚,同理嗡综,如果我們的目標(biāo)是上山,也就是爬到山頂杜漠,那么此時(shí)應(yīng)該是朝著最陡峭的方向往上走极景。然后每走一段距離,都反復(fù)采用同一個(gè)方法驾茴,最后就能成功的抵達(dá)山谷盼樟。
image.png
我們同時(shí)可以假設(shè)這座山最陡峭的地方是無(wú)法通過(guò)肉眼立馬觀(guān)察出來(lái)的,而是需要一個(gè)復(fù)雜的工具來(lái)測(cè)量锈至,同時(shí)晨缴,這個(gè)人此時(shí)正好擁有測(cè)量出最陡峭方向的能力。所以峡捡,此人每走一段距離击碗,都需要一段時(shí)間來(lái)測(cè)量所在位置最陡峭的方向筑悴,這是比較耗時(shí)的。那么為了在太陽(yáng)下山之前到達(dá)山底稍途,就要盡可能的減少測(cè)量方向的次數(shù)阁吝。這是一個(gè)兩難的選擇,如果測(cè)量的頻繁械拍,可以保證下山的方向是絕對(duì)正確的突勇,但又非常耗時(shí),如果測(cè)量的過(guò)少坷虑,又有偏離軌道的風(fēng)險(xiǎn)甲馋。所以需要找到一個(gè)合適的測(cè)量方向的頻率,來(lái)確保下山的方向不錯(cuò)誤迄损,同時(shí)又不至于耗時(shí)太多摔刁!
梯度下降
梯度下降的基本過(guò)程就和下山的場(chǎng)景很類(lèi)似。
首先海蔽,我們有一個(gè)可微分的函數(shù)共屈。這個(gè)函數(shù)就代表著一座山。我們的目標(biāo)就是找到這個(gè)函數(shù)的最小值党窜,也就是山底拗引。根據(jù)之前的場(chǎng)景假設(shè),最快的下山的方式就是找到當(dāng)前位置最陡峭的方向幌衣,然后沿著此方向向下走矾削,對(duì)應(yīng)到函數(shù)中,就是找到給定點(diǎn)的梯度 豁护,然后朝著梯度相反的方向哼凯,就能讓函數(shù)值下降的最快吴汪!因?yàn)樘荻鹊姆较蚓褪呛瘮?shù)之變化最快的方向(在后面會(huì)詳細(xì)解釋)
所以堕扶,我們重復(fù)利用這個(gè)方法舱污,反復(fù)求取梯度是越,最后就能到達(dá)局部的最小值,這就類(lèi)似于我們下山的過(guò)程终佛。而求取梯度就確定了最陡峭的方向吭历,也就是場(chǎng)景中測(cè)量方向的手段抡医。那么為什么梯度的方向就是最陡峭的方向呢达址?接下來(lái)蔑祟,我們從微分開(kāi)始講起
微分
看待微分的意義,可以有不同的角度沉唠,最常用的兩種是:
- 函數(shù)圖像中疆虚,某點(diǎn)的切線(xiàn)的斜率
-
函數(shù)的變化率
幾個(gè)微分的例子:
image.png
上面的例子都是單變量的微分,當(dāng)一個(gè)函數(shù)有多個(gè)變量的時(shí)候,就有了多變量的微分径簿,即分別對(duì)每個(gè)變量進(jìn)行求微分
梯度
梯度實(shí)際上就是多變量微分的一般化罢屈。
下面這個(gè)例子:
我們可以看到,梯度就是分別對(duì)每個(gè)變量進(jìn)行微分牍帚,然后用逗號(hào)分割開(kāi)儡遮,梯度是用<>包括起來(lái)乳蛾,說(shuō)明梯度其實(shí)一個(gè)向量暗赶。
梯度是微積分中一個(gè)很重要的概念,之前提到過(guò)梯度的意義
- 在單變量的函數(shù)中肃叶,梯度其實(shí)就是函數(shù)的微分蹂随,代表著函數(shù)在某個(gè)給定點(diǎn)的切線(xiàn)的斜率
- 在多變量函數(shù)中,梯度是一個(gè)向量因惭,向量有方向岳锁,梯度的方向就指出了函數(shù)在給定點(diǎn)的上升最快的方向
這也就說(shuō)明了為什么我們需要千方百計(jì)的求取梯度!我們需要到達(dá)山底蹦魔,就需要在每一步觀(guān)測(cè)到此時(shí)最陡峭的地方激率,梯度就恰巧告訴了我們這個(gè)方向。梯度的方向是函數(shù)在給定點(diǎn)上升最快的方向勿决,那么梯度的反方向就是函數(shù)在給定點(diǎn)下降最快的方向乒躺,這正是我們所需要的。所以我們只要沿著梯度的方向一直走低缩,就能走到局部的最低點(diǎn)嘉冒!
梯度下降算法的數(shù)學(xué)解釋
上面我們花了大量的篇幅介紹梯度下降算法的基本思想和場(chǎng)景假設(shè),以及梯度的概念和思想咆繁。下面我們就開(kāi)始從數(shù)學(xué)上解釋梯度下降算法的計(jì)算過(guò)程和思想讳推!
此公式的意義是:J是關(guān)于Θ的一個(gè)函數(shù),我們當(dāng)前所處的位置為Θ0點(diǎn)玩般,要從這個(gè)點(diǎn)走到J的最小值點(diǎn)银觅,也就是山底。首先我們先確定前進(jìn)的方向坏为,也就是梯度的反向设拟,然后走一段距離的步長(zhǎng),也就是α久脯,走完這個(gè)段步長(zhǎng)纳胧,就到達(dá)了Θ1這個(gè)點(diǎn)!
下面就這個(gè)公式的幾個(gè)常見(jiàn)的疑問(wèn):
- α是什么含義帘撰?
α在梯度下降算法中被稱(chēng)作為學(xué)習(xí)率或者步長(zhǎng)跑慕,意味著我們可以通過(guò)α來(lái)控制每一步走的距離,以保證不要步子跨的太大扯著蛋,哈哈核行,其實(shí)就是不要走太快牢硅,錯(cuò)過(guò)了最低點(diǎn)。同時(shí)也要保證不要走的太慢芝雪,導(dǎo)致太陽(yáng)下山了减余,還沒(méi)有走到山下。所以α的選擇在梯度下降法中往往是很重要的惩系!α不能太大也不能太小位岔,太小的話(huà),可能導(dǎo)致遲遲走不到最低點(diǎn)堡牡,太大的話(huà)抒抬,會(huì)導(dǎo)致錯(cuò)過(guò)最低點(diǎn)!
- 為什么要梯度要乘以一個(gè)負(fù)號(hào)晤柄?
梯度前加一個(gè)負(fù)號(hào)擦剑,就意味著朝著梯度相反的方向前進(jìn)!我們?cè)谇拔奶岬浇婢保荻鹊姆较驅(qū)嶋H就是函數(shù)在此點(diǎn)上升最快的方向惠勒!而我們需要朝著下降最快的方向走,自然就是負(fù)的梯度的方向爬坑,所以此處需要加上負(fù)號(hào)
梯度下降算法的實(shí)例
我們已經(jīng)基本了解了梯度下降算法的計(jì)算過(guò)程纠屋,那么我們就來(lái)看幾個(gè)梯度下降算法的小實(shí)例,首先從單變量的函數(shù)開(kāi)始
單變量函數(shù)的梯度下降
我們假設(shè)有一個(gè)單變量的函數(shù)
函數(shù)的微分
初始化妇垢,起點(diǎn)為
學(xué)習(xí)率為
根據(jù)梯度下降的計(jì)算公式
我們開(kāi)始進(jìn)行梯度下降的迭代計(jì)算過(guò)程:
如圖巾遭,經(jīng)過(guò)四次的運(yùn)算,也就是走了四步闯估,基本就抵達(dá)了函數(shù)的最低點(diǎn)灼舍,也就是山底
多變量函數(shù)的梯度下降
我們假設(shè)有一個(gè)目標(biāo)函數(shù)
現(xiàn)在要通過(guò)梯度下降法計(jì)算這個(gè)函數(shù)的最小值。我們通過(guò)觀(guān)察就能發(fā)現(xiàn)最小值其實(shí)就是 (0涨薪,0)點(diǎn)骑素。但是接下來(lái),我們會(huì)從梯度下降算法開(kāi)始一步步計(jì)算到這個(gè)最小值刚夺!
我們假設(shè)初始的起點(diǎn)為:
初始的學(xué)習(xí)率為:
函數(shù)的梯度為:
進(jìn)行多次迭代:
我們發(fā)現(xiàn)献丑,已經(jīng)基本靠近函數(shù)的最小值點(diǎn)
梯度下降算法的實(shí)現(xiàn)
下面我們將用python實(shí)現(xiàn)一個(gè)簡(jiǎn)單的梯度下降算法。場(chǎng)景是一個(gè)簡(jiǎn)單的線(xiàn)性回歸的例子:假設(shè)現(xiàn)在我們有一系列的點(diǎn)侠姑,如下圖所示
我們將用梯度下降法來(lái)擬合出這條直線(xiàn)创橄!
首先,我們需要定義一個(gè)代價(jià)函數(shù)莽红,在此我們選用均方誤差代價(jià)函數(shù)
此公示中
- m是數(shù)據(jù)集中點(diǎn)的個(gè)數(shù)
- ?是一個(gè)常量妥畏,這樣是為了在求梯度的時(shí)候邦邦,二次方乘下來(lái)就和這里的?抵消了,自然就沒(méi)有多余的常數(shù)系數(shù)醉蚁,方便后續(xù)的計(jì)算燃辖,同時(shí)對(duì)結(jié)果不會(huì)有影響
- y 是數(shù)據(jù)集中每個(gè)點(diǎn)的真實(shí)y坐標(biāo)的值
-
h 是我們的預(yù)測(cè)函數(shù),根據(jù)每一個(gè)輸入x网棍,根據(jù)Θ 計(jì)算得到預(yù)測(cè)的y值黔龟,即
image.png
我們可以根據(jù)代價(jià)函數(shù)看到,代價(jià)函數(shù)中的變量有兩個(gè)滥玷,所以是一個(gè)多變量的梯度下降問(wèn)題氏身,求解出代價(jià)函數(shù)的梯度,也就是分別對(duì)兩個(gè)變量進(jìn)行微分
明確了代價(jià)函數(shù)和梯度罗捎,以及預(yù)測(cè)的函數(shù)形式观谦。我們就可以開(kāi)始編寫(xiě)代碼了拉盾。但在這之前桨菜,需要說(shuō)明一點(diǎn),就是為了方便代碼的編寫(xiě)捉偏,我們會(huì)將所有的公式都轉(zhuǎn)換為矩陣的形式倒得,python中計(jì)算矩陣是非常方便的,同時(shí)代碼也會(huì)變得非常的簡(jiǎn)潔夭禽。
為了轉(zhuǎn)換為矩陣的計(jì)算霞掺,我們觀(guān)察到預(yù)測(cè)函數(shù)的形式
我們有兩個(gè)變量,為了對(duì)這個(gè)公式進(jìn)行矩陣化讹躯,我們可以給每一個(gè)點(diǎn)x增加一維菩彬,這一維的值固定為1,這一維將會(huì)乘到Θ0上潮梯。這樣就方便我們統(tǒng)一矩陣化的計(jì)算
然后我們將代價(jià)函數(shù)和梯度轉(zhuǎn)化為矩陣向量相乘的形式
coding time
首先骗灶,我們需要定義數(shù)據(jù)集和學(xué)習(xí)率
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
接下來(lái)我們以矩陣向量的形式定義代價(jià)函數(shù)和代價(jià)函數(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)
最后就是算法的核心部分,梯度下降迭代計(jì)算
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
當(dāng)梯度小于1e-5時(shí)秉馏,說(shuō)明已經(jīng)進(jìn)入了比較平滑的狀態(tài)耙旦,類(lèi)似于山谷的狀態(tài),這時(shí)候再繼續(xù)迭代效果也不大了萝究,所以這個(gè)時(shí)候可以退出循環(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])
運(yùn)行代碼,計(jì)算得到的結(jié)果如下
所擬合出的直線(xiàn)如下
小結(jié)
至此帆竹,我們就基本介紹完了梯度下降法的基本思想和算法流程绕娘,并且用python實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的梯度下降算法擬合直線(xiàn)的案例!
最后栽连,我們回到文章開(kāi)頭所提出的場(chǎng)景假設(shè):
這個(gè)下山的人實(shí)際上就代表了反向傳播算法险领,下山的路徑其實(shí)就代表著算法中一直在尋找的參數(shù)Θ,山上當(dāng)前點(diǎn)的最陡峭的方向?qū)嶋H上就是代價(jià)函數(shù)在這一點(diǎn)的梯度方向,場(chǎng)景中觀(guān)測(cè)最陡峭方向所用的工具就是微分 舷暮。在下一次觀(guān)測(cè)之前的時(shí)間就是有我們算法中的學(xué)習(xí)率α所定義的态罪。
可以看到場(chǎng)景假設(shè)和梯度下降算法很好的完成了對(duì)應(yīng)!