上一篇文章中,線性回歸關(guān)鍵問題之一:求解系數(shù)的方法梯度下降。梯度下降在數(shù)據(jù)挖掘很多算法中都有應(yīng)用, 屬于比較基本的數(shù)學(xué)基礎(chǔ)方法, 本文對此算法進(jìn)行基本的介紹。
梯度下降在機器學(xué)習(xí)中的意義:
機器學(xué)習(xí)算法會利用某個統(tǒng)計量來刻畫目標(biāo)函數(shù)的擬合情況。雖然不同的算法擁有不同的目標(biāo)函數(shù)表示方法和不同的系數(shù)值,但是它們擁有一個共同的目標(biāo)——即通過最優(yōu)化目標(biāo)函數(shù)來獲取最佳參數(shù)值。而梯度下降法就是優(yōu)化目標(biāo)函數(shù)而求得最佳參數(shù)值的方法。
梯度下降數(shù)學(xué)原理
理解梯度概念之前, 先預(yù)習(xí)下幾個基本概念和物理意義:
導(dǎo)數(shù)
導(dǎo)數(shù)定義:設(shè)函數(shù)y=f(x)在點x0的某個鄰域內(nèi)有定義,當(dāng)自變量x在x0處有增量Δx,(x0+Δx)也在該鄰域內(nèi)時,相應(yīng)地函數(shù)取得增量Δy=f(x0+Δx)-f(x0);如果Δy與Δx之比當(dāng)Δx→0時極限存在,則稱函數(shù)y=f(x)在點x0處可導(dǎo),并稱這個極限為函數(shù)y=f(x)在點x0處的導(dǎo)數(shù)記為f'(x0),也記作y'│x=x0或dy/dx│x=x0,即:

導(dǎo)數(shù)的物理意義:表示函數(shù)值在這一點的變化率。
偏導(dǎo)數(shù)
偏導(dǎo)數(shù)定義(以二元函數(shù)X方向偏導(dǎo)數(shù)為例):
設(shè)有二元函數(shù)z=f(x,y),點(x0,y0)是其定義域D內(nèi)一點.把y固定在y0而讓x在x0有增量△x,相應(yīng)地偏導(dǎo)數(shù)函數(shù)z=f(x,y)有增量(稱為對x的偏增量)△z=f(x0+△x,y0)-f(x0,y0)。如果△z與△x之比當(dāng)△x→0時的極限存在,那么此極限值稱為函數(shù)z=f(x,y)在(x0,y0)處對x的偏導(dǎo)數(shù)(partial derivative)。記作f'x(x0,y0)。

如上圖所示:偏導(dǎo)數(shù)表示固定面上一點M0(x0, y0, z0)對x軸的切線斜率;
偏導(dǎo)數(shù)的物理意義:函數(shù)沿坐標(biāo)軸正方向的變化率。
方向?qū)?shù)
多元函數(shù)的偏導(dǎo)數(shù)反映了函數(shù)值沿坐標(biāo)軸方向的變化率,而方向?qū)?shù)則是反應(yīng)的函數(shù)值沿各個方向的變化率。方向?qū)?shù)的定義:

方向?qū)?shù)的求解公式:

說明:其中a1, a2, ..., an指的是向量L與各個坐標(biāo)軸的夾角。
在了解以上幾個概念之后, 正式進(jìn)入本文的正題:梯度。
梯度
數(shù)學(xué)對梯度的定義如下:

通過上面的公式, 很顯然梯度與方向?qū)?shù)存在某種聯(lián)系。通過向量的推導(dǎo),很容易得到如下公式:

其中:L0是方向?qū)?shù)中向量L的單位向量

要這個向量的點積達(dá)到最大, 即方向?qū)?shù)達(dá)到最大, gradf和L0必須同方向,也就是說當(dāng)L0是梯度gradf的方向時, 方向?qū)?shù)到達(dá)最大。因此梯度的物理意義:是函數(shù)各個方向上變化率最大的那個方向,函數(shù)沿著梯度的方向,變化率達(dá)到最大。
梯度下降優(yōu)化目標(biāo)函數(shù)的原理
在理解梯度下降的物理意義之后, 自然就能理解梯度下降在回歸算法(其他機器學(xué)習(xí)算法也會用到)的作用:優(yōu)化損失函數(shù),讓損失函數(shù)一直沿著最大的降低方向變化,最終找到最小損失函數(shù)(也可能是局部最?。?。具體如圖所示:

實現(xiàn)回歸算法損失函數(shù)的思路:每次算出損失函數(shù)的梯度(就是對每個參數(shù)進(jìn)行偏導(dǎo)數(shù)計算),計算出每個參數(shù)的偏導(dǎo)數(shù)后, 在每個參數(shù)上減去相應(yīng)的偏導(dǎo)數(shù),得到一個新的參數(shù)值, 損失函數(shù)就得到函數(shù)值降低最快的效果。迭代過程持續(xù)到參數(shù)收斂,參數(shù)是否收斂的判斷依據(jù)是:
1、θ值變化不再明顯(差值小于某給定值);
2、用損失函數(shù)值變化不明顯,訓(xùn)練值加上迭代的參數(shù)值觀察損失函數(shù)的變化情況,直到變化不再明顯;
3、存在收斂過慢或者死循環(huán)的情況,可以強制限制迭代次數(shù)。
下面用數(shù)學(xué)公式推導(dǎo)下回歸算法損失函數(shù)求解參數(shù)的相關(guān)公式。損失函數(shù)如下:

PS:1/2是為后續(xù)計算偏導(dǎo)數(shù)方便,并不影響求解損失函數(shù)的最小值。
對一個樣本點j,參數(shù)偏導(dǎo)數(shù)的計算公式進(jìn)行推導(dǎo):

對有M個樣本點,第J個參數(shù)就基于上面偏導(dǎo)數(shù)公式進(jìn)行更新,其迭代的過程如下所示:

公式中alpha 是步長。
梯度下降的局限性
通過參數(shù)最終的迭代公式以及梯度下降的實現(xiàn)思路可知,梯度下降公式存在如下幾個問題:
- 計算量很大,因為每次更新theta值時都要將整個訓(xùn)練集的數(shù)據(jù)代入計算,該算法在訓(xùn)練集合非常大的情況下將會非常低效。
- 計算的初始值對結(jié)果影響大。如果該函數(shù)不是凸函數(shù)(凸函數(shù)得到的最終值是全局最小值), 函數(shù)得到的是局部最小值, 初始值不一樣, 最小值也會不一樣。如果函數(shù)沒有最小值,就會陷入無限循環(huán)中。
梯度下降的實現(xiàn)
用代碼實現(xiàn) 簡單的梯度下降程序。
利用y = 2 * x1 + (x2^2) / 2生成x_train, y_train數(shù)據(jù), 具體的實現(xiàn)如下圖:
# y = 2 * x1 + (x2^2) / 2
alpha=0.001
max_count = 1000000
x_train = [(1.0,3.0), (2.0, 4.0), (3.0, 5.0), (5.0,9.0), (8.0, 10.0)]
y_train = [6.6, 12.2, 18.8, 50.5, 66.3]
error_end = 0.5
#h(x)
def h(x, theta0, theta1):
#global theta0, theta1
#print theta0, theta1, x[0], x[1]
hx = theta0 * x[0] + theta1 * (x[1]**2)
return hx
def gradf():
theta0 = 0.5
theta1 = 0.1
data_len = len(y_train)
cn = 0
is_finish = False
while True:
for i in range(data_len):
det_theta = alpha * (h(x_train[i], theta0, theta1) - y_train[i])
theta0 = theta0 - (det_theta) * x_train[i][0]
theta1 = theta1 - (det_theta) * x_train[i][1]
error = 0.0
for i in range(data_len):
error = error + ((y_train[i] - h(x_train[i], theta0, theta1))**2)/2
cn = cn + 1
if error < error_end or cn > max_count:
print error
break;
print "theta:%f, %f" %(theta0, theta1)
if __name__=="__main__":
gradf()
程序運行后得到的參數(shù):
theta:1.682974, 0.528715
對比函數(shù)y = 2 * x1 + (x2^2) / 2的參數(shù): 2, 0.5。有所差異, 但還是比較接近。
以上是最簡單的批量梯度下降方法, 梯度下降還涉及alpha步長, 非凸函數(shù)的初始化參數(shù)選取問題等等, 后續(xù)文章再探討。