在高數(shù)中列林,我們求解一個函數(shù)的最小值時,最常用的方法就是求出它的導(dǎo)數(shù)為0的那個點烛愧,進而判斷這個點是否能夠取最小值油宜。但是掂碱,在實際很多情況,我們很難求解出使函數(shù)的導(dǎo)數(shù)為0的方程验庙,這個時候就可以使用梯度下降顶吮。我們知道對于一個函數(shù)沿著梯度的那個方向是下降是最快的社牲。例如為了選取一個θ使J(θ)最小粪薛,我們可以先隨機選擇θ一個初始值,然后不斷的修改θ以減小J(θ)搏恤,直到θ的值不再改變违寿。對于梯度下降法,可以表示為:
θj=θj?α*?J(θ)/?θj
即不斷地向梯度的那個方向(減小最快的方向)更新θ熟空,最終使得J(θ)最小藤巢。其中α稱為學(xué)習(xí)速率(learning rate),取值太小會導(dǎo)致迭代過慢息罗,取值太大可能錯過最值點掂咒。
假設(shè)我們有一堆數(shù)據(jù)集,這些數(shù)據(jù)集用散點圖的方式迈喉,可以用一元線性回歸方程表示绍刮,那么我們表示成如下公式
數(shù)據(jù)集為
假設(shè)我們建立模型 y=h(x)=θ0+θ1x
那么我們的預(yù)期是讓通過對兩個參數(shù)θ0和θ1的調(diào)整,將y的實際值和模型輸出預(yù)測值的偏移量盡量的小挨摸,于是有
θ0和θ1兩個參數(shù)的變化我們用J(θ0孩革,θ1)表示
如何求出J(θ0,θ1)的最小值得运,這里就引入了梯度下降算法膝蜈。主要思想是,J(θ0熔掺,θ1)好比是層巒疊嶂的群山饱搏,任意指定一個θ0和θ1,好比你在群山中的任意一個點置逻,如何下山推沸,一般都會瞭望四周,選擇當(dāng)前下山最陡的方向向下走诽偷。于是你又從A到達B坤学,在B點,同樣的情景报慕,你將會選擇下一步何去何從深浮,同樣的,選擇當(dāng)前最陡的路徑向下走去眠冈。
如此周而復(fù)始飞苇,終將到達一個相對低菌瘫,局部最優(yōu)的位置。
如何將這一思想落實在數(shù)學(xué)上布卡,是機器學(xué)習(xí)的基礎(chǔ)雨让。
首先先復(fù)習(xí)一下幾個基本概念。
1.導(dǎo)數(shù)和微分
導(dǎo)數(shù)的定義如下
導(dǎo)數(shù)反映的是函數(shù)y=f(x)在某一點處沿x軸正方向的變化率忿等。也就是在x軸上某一點處栖忠,如果f’(x)>0,說明f(x)的函數(shù)值在x點沿x軸正方向是趨于增加的贸街;如果f’(x)<0庵寞,說明f(x)的函數(shù)值在x點沿x軸正方向是趨于減少的。
偏導(dǎo)數(shù)的定義
偏導(dǎo)數(shù)的定義和導(dǎo)數(shù)類似薛匪,都是當(dāng)自變量的變化量趨于0時捐川,函數(shù)值的變化量與自變量變化量比值的極限。直觀地說逸尖,偏導(dǎo)數(shù)也就是函數(shù)在某一點上沿坐標軸正方向的的變化古沥。區(qū)別在于導(dǎo)數(shù)為一元變量,偏導(dǎo)數(shù)為多元變量娇跟。
方向?qū)?shù)的定義
即:某一點在某一趨近方向上的導(dǎo)數(shù)值岩齿。 通俗的解釋是: 我們不僅要知道函數(shù)在坐標軸正方向上的變化率(即偏導(dǎo)數(shù)),而且還要設(shè)法求得函數(shù)在其他特定方向上的變化率逞频。而方向?qū)?shù)就是函數(shù)在其他特定方向上的變化率纯衍。
梯度的定義如下
梯度的提出只為回答一個問題:
函數(shù)在變量空間的某一點處,沿著哪一個方向有最大的變化率苗胀? 函數(shù)在某一點的梯度是這樣一個向量襟诸,它的方向與取得最大方向?qū)?shù)的方向一致,而它的模為方向?qū)?shù)的最大值基协。
這里注意三點:
1)梯度是一個向量歌亲,即有方向有大小澜驮;
2)梯度的方向是最大方向?qū)?shù)的方向陷揪;
3)梯度的值是最大方向?qū)?shù)的值。
既然在變量空間的某一點處杂穷,函數(shù)沿梯度方向具有最大的變化率悍缠,那么在優(yōu)化目標函數(shù)的時候,自然是沿著負梯度方向去減小函數(shù)值耐量,以此達到我們的優(yōu)化目標飞蚓。
如何沿著負梯度方向減小函數(shù)值呢?既然梯度是偏導(dǎo)數(shù)的集合廊蜒,如下
同時梯度和偏導(dǎo)數(shù)都是向量趴拧,那么參考向量運算法則溅漾,我們在每個變量軸上減小對應(yīng)變量值即可,梯度下降法可以描述如下:
這就是梯度下降法的數(shù)據(jù)原理著榴。
參考http://blog.csdn.net/walilk/article/details/50978864
為什么從函數(shù)的梯度方向下降可以得到函數(shù)的最小值
梯度下降法添履,基于這樣的觀察:如果實值函數(shù)F(x)在點a 處可微且有定義,那么函數(shù) F(x)在a點沿著梯度相反的方向?▽F(a)?▽F(a)下降最快脑又。
因而暮胧,如果
b=a?α▽F(a)
b=a?α▽F(a)
那么F(b)≤F(a)F(b)≤F(a)。
考慮如下序列x0,x1,x2,...x0,x1,x2,...使得
xn+1=xn?α▽F(xn)
xn+1=xn?α▽F(xn)
因此可以得到: F(x0)≥F(x1)≥F(x2)≥...F(x0)≥F(x1)≥F(x2)≥... 如果順利的話序列最終可以收斂到期望的極值挂谍。
注意:梯度下降得到的結(jié)果可能是局部最優(yōu)值叔壤。如果F(x)F(x)是凸函數(shù)瞎饲,則可以保證梯度下降得到的是全局最優(yōu)值口叙。
批量梯度下降法的算法
批梯度下降法(batch gradient descent)的算法描述如下:
對每一個j重復(fù)以下過程直到收斂 {
}
其中假設(shè)訓(xùn)練樣本數(shù)有m個,每個樣本用zi可以表示為(xi,yi)嗅战⊥铮可以看出,使用批梯度下降法每一次更新θj都需要遍歷訓(xùn)練樣本中的所有樣本驮捍。
批量梯度下降法代碼
#coding=utf-8
##
#Calculate the hypothesis h = X * theta
#Calculate the loss = h - y and maybe the squared cost (loss^2)/2m
#Calculate the gradient = X' * loss / m
#Update the parameters theta = theta - alpha * gradient
###
import numpy as np
from numpy import *
import random
def loadDataSet(filename):
numFeat = len(open(filename).readline().split(','))-1
datMat = []; labelMat = []
fr = open(filename)
for line in fr.readlines():
lineArr = []
curLine = line.strip().split(',')
for i in range(numFeat):
lineArr.append(float(curLine[i]))
datMat.append(lineArr)
labelMat.append(float(curLine[-1]))
return datMat,labelMat
#x為自變量訓(xùn)練集疟呐,y為自變量對應(yīng)的因變量訓(xùn)練集;theta為待求解的權(quán)重值东且,需要事先進行初始化启具;alpha是學(xué)習(xí)率;m為樣本總數(shù)珊泳;maxIterations為最大迭代次數(shù)鲁冯;
def batchGradientDescent(x, y, theta, alpha, m, maxIterations):
xTrains = x.transpose() #x 轉(zhuǎn)置
for i in range(0, maxIterations):
hypothesis = np.dot(x, theta) #矩陣乘法,https://migege.com/post/matrix-multiplication-in-numpy 計算f(x(k))
loss = hypothesis - y
#print(loss)
#print(m)
#print(type(loss))
# avg cost per example (the 2 in 2*m doesn't really matter here.
# But to be consistent with the gradient, I include it)
cost = np.sum(loss ** 2) / (2 * m)
print("Iteration %d | Cost: %f" % (i, cost))
# avg gradient per example
gradient = np.dot(xTrains, loss) / m ##梯度
#print("gradinet is ",gradient)
# update
theta = theta - alpha * gradient #x(k+1)
#print("theta is ",theta)
return theta
xArr,yArr = loadDataSet('gmvusers3.csv')
xArr1 = asarray(xArr)
yArr1 = asarray(yArr)
#print("xArr is ",asarray(xArr))
#print("yArr is ",asarray(yArr))
#print(asarray(xArr).dtype)
#print(asarray(yArr).dtype)
m, n = np.shape(xArr1)
print("m %d | n %d" %(m,n))
numIterations= 10000
alpha = 0.00000001
theta = [1,1] #Return a new array of given shape and type, filled with ones. 初始值色查。
theta = batchGradientDescent(xArr1, yArr1, theta, alpha, m, numIterations)
print(theta)
####
# gen 100 points with a bias of 25 and 10 variance as a bit of noise
#x, y = genData(100, 25, 10)
#print(x)
#print(y)
#print(x.dtype)
#print(y.dtype)
#m, n = np.shape(x)
#numIterations= 100000
#alpha = 0.0001
#theta = np.ones(n)
#theta = batchGradientDescent(x, y, theta, alpha, m, numIterations)
#print(theta)
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(yArr1,'go')
xCopy = xArr1.copy()
xCopy.sort(0)
yHat=xCopy*theta
ax.plot(xCopy[:,1],yHat)
plt.show()
print(yArr1)
print(yHat)
print(corrcoef(yHat.T,yArr1)) ???
'''
其他深度學(xué)習(xí)好的文章http://sebastianruder.com/optimizing-gradient-descent/
'''
學(xué)習(xí)速率的注意條件
參數(shù)α為初始學(xué)習(xí)速率薯演,代表著梯度下降的速率,需要選擇一個合適的參數(shù)秧了。
在學(xué)習(xí)速率為固定值的時候跨扮,這個參數(shù)不能太小,否則學(xué)習(xí)的步數(shù)太多验毡,程序的速度很慢衡创,你可能需要很長一段時間才能收斂;但是也不能選的太大晶通,
否則璃氢,你可能會發(fā)現(xiàn),或許一開始J很快就接近收斂了录择,但是步長太大拔莱,之后并沒有收斂碗降,而是出了點狀況。你會發(fā)現(xiàn)塘秦,代價函數(shù)的值不但遲遲不收斂讼渊,
反而可能會越來越發(fā)散,以至于結(jié)果變得糟糕起來尊剔,甚至?xí)?dǎo)致直接跨過谷底到達另一端爪幻,這就是所謂的“步子太大,邁過山谷”须误。至于這個參數(shù)如何選擇挨稿,
需要有一定的經(jīng)驗,不過可以提前多選幾個值做一下試驗京痢,比如用0.001奶甘,發(fā)現(xiàn)太慢,用0.1祭椰,發(fā)現(xiàn)過一段時間會發(fā)散臭家,0.01既不太慢也不會發(fā)散,那就選擇這個參數(shù)方淤。
或者我們可以根據(jù)梯度下降每一步的實際情況動態(tài)調(diào)整學(xué)習(xí)速率钉赁,使用可變的學(xué)習(xí)速率,這就是上式的由來携茂。我們設(shè)定一個初始的學(xué)習(xí)速率你踩,這個學(xué)習(xí)速率也不能太大,
否則一開始就會發(fā)散讳苦,當(dāng)然也不能太小带膜,否則速度太慢。在優(yōu)化的過程中医吊,學(xué)習(xí)速率應(yīng)該逐步減小钱慢,越接近“山谷”的時候,邁的“步伐”應(yīng)該越小卿堂。我們每走一步束莫,
數(shù)據(jù)分布與直線的誤差越小,而這時梯度也會減小草描,那么步伐也就應(yīng)當(dāng)相應(yīng)的減小览绿,這就是初始學(xué)習(xí)速率乘上代價函數(shù)負梯度的原因。本實例中穗慕,經(jīng)過我的試驗饿敲,學(xué)習(xí)
速率選擇為0.0001比較合適。
值得說明的是逛绵,在進行梯度下降的時候怀各,我們應(yīng)當(dāng)盡量使用限定迭代次數(shù)的循環(huán)倔韭,而不是用判斷是否收斂的循環(huán)。原因很簡單瓢对,一旦出現(xiàn)你的結(jié)果是發(fā)散的寿酌,限定
迭代次數(shù)的循環(huán)可以使你的程序很快停止下來,而因為你的結(jié)果永遠不會收斂硕蛹,所以醇疼,如果你用while進行判斷是否收斂的話,你將很有可能陷入死循環(huán)法焰,因為你的
結(jié)果永遠不可能收斂秧荆。這里我把迭代步數(shù)設(shè)為100步。
https://blog.ailemon.me/2017/02/10/machine-learningregression-statistic-model/
特征量標準化
如果我們能夠?qū)⑤斎敫鱾€特征變量統(tǒng)一在相同范圍內(nèi)埃仪,則會加速梯度下降的效果乙濒。這是應(yīng)為 θ 在小范圍內(nèi)將會下降的很快,在大范圍內(nèi)將會下降的很慢.
為了避免無謂的計算贵试,理想狀態(tài)下琉兜,我們最好能將輸入變量限定在?1 ≤ x(i) ≤ 1或者?0.5 ≤ x(i) ≤ 0.5。由于目的只是為了將梯度下降效果優(yōu)化毙玻,只需將各個輸入X統(tǒng)一在一個較小的范圍內(nèi)即可。
一般選用兩種方法:
- Feature scaling. X(i) 除以最大值和最小值的差,讓X(i)在絕對值區(qū)間1之間.
- Mean normalization廊散,公式為:xi:=xi?μisi 桑滩; μi 為 feature (i) 的均值 and si 為值的范圍 (max - min), or si 為標準差。
除了批梯度下降法之外允睹,還有一種算法稱為——隨機梯度下降法(stochastic gradient descent运准,SGD)。算法描述如下:
每一次更新只使用了一個訓(xùn)練樣本缭受,但更新了m次胁澳。
批梯度下降法每更新一步都需要遍歷所有的樣本數(shù)據(jù),如果樣本數(shù)m很大的話米者,就會非常的耗時韭畸;而對于隨機梯度下降,每一遇到一個樣本數(shù)據(jù)蔓搞,就可以馬上更新胰丁。通常情況下,使用隨機梯度下降法的速度會比批梯度下降法快很多喂分。因此锦庸,當(dāng)樣本數(shù)很大的時候,我們通常都選擇使用隨機梯度下降法蒲祈。
參考
http://www.wengweitao.com/ti-du-xia-jiang-fa.html
另外梯度下降極容易受到異常值的影響甘萧,使用前最好刪掉異常值萝嘁。