在上一篇邏輯回歸中,我們利用批量梯度下降算法BGD求解使損失函數(shù)J(θ)取得最小值的θ裆赵,同時(shí)也提到了SGD和MBGD弛矛,本篇我們實(shí)現(xiàn)下這三個(gè)算法,并進(jìn)行簡(jiǎn)單比較得问。關(guān)于梯度下降算法的原理可以參考https://www.cnblogs.com/pinard/p/5970503.html囤攀。
1. 批量梯度下降法(Batch Gradient Descent)
批量梯度下降算法是梯度下降算法的最常用形式,即在更新參數(shù)時(shí)利用所有的樣本來(lái)進(jìn)行更新宫纬,參數(shù)的更新過(guò)程可寫成:
由于有m個(gè)樣本焚挠,所以求梯度的時(shí)候就用了所有m個(gè)樣本的梯度數(shù)據(jù)。
BGD的Python實(shí)現(xiàn)
def BGD_LR(data_x, data_y, alpha=0.1, maxepochs=10000, epsilon=1e-4):
xMat = np.mat(data_x)
yMat = np.mat(data_y)
m,n = xMat.shape
weights = np.ones((n,1)) #初始化模型參數(shù)
epochs_count = 0
loss_list = []
epochs_list = []
while epochs_count < maxepochs:
loss = cost(xMat,weights,yMat) #上一次損失值
hypothesis = sigmoid(np.dot(xMat,weights)) #預(yù)測(cè)值
error = hypothesis -yMat #預(yù)測(cè)值與實(shí)際值誤差
grad = (1.0/m)*np.dot(xMat.T,error) #損失函數(shù)的梯度
last_weights = weights #上一輪迭代的參數(shù)
weights = weights - alpha*grad #參數(shù)更新
loss_new = cost(xMat,weights,yMat)#當(dāng)前損失值
print(loss_new)
if abs(loss_new-loss)<epsilon:#終止條件
break
loss_list.append(loss_new)
epochs_list.append(epochs_count)
epochs_count += 1
print('迭代到第{}次漓骚,結(jié)束迭代蝌衔!'.format(epochs_count))
plt.plot(epochs_list,loss_list)
plt.xlabel('epochs')
plt.ylabel('loss')
plt.show()
return weights
2. 隨機(jī)梯度下降法(Stochastic Gradient Descent)
批量梯度下降算法每次更新參數(shù)都需要遍歷整個(gè)數(shù)據(jù)集(通過(guò)遍歷整個(gè)數(shù)據(jù)集來(lái)計(jì)算損失函數(shù)的梯度),那么在樣本數(shù)據(jù)量巨大的時(shí)候蝌蹂,計(jì)算復(fù)雜度會(huì)很高噩斟。因此出現(xiàn)了隨機(jī)梯度下降算法:即每次迭代都隨機(jī)選取一個(gè)樣本計(jì)算損失函數(shù)的梯度來(lái)更新參數(shù)。參數(shù)更新公式可變?yōu)椋?/p>
與批量梯度下降算法相比孤个,SGD的區(qū)別在于求梯度時(shí)沒有用所有的m個(gè)樣本數(shù)據(jù)剃允,而是隨機(jī)選取了一個(gè)樣本i來(lái)求梯度。在樣本量很大的時(shí)候,SGD由于僅采用了一個(gè)樣本來(lái)迭代斥废,因此訓(xùn)練速度很快覆享,但很可能導(dǎo)致解不是最優(yōu)的,準(zhǔn)確度下降营袜。
SGD的Python實(shí)現(xiàn)
def SGD_LR(data_x, data_y, alpha=0.1, maxepochs=10000,epsilon=1e-4):
xMat = np.mat(data_x)
yMat = np.mat(data_y)
m, n = xMat.shape
weights = np.ones((n, 1)) # 模型參數(shù)
epochs_count = 0
loss_list = []
epochs_list = []
while epochs_count < maxepochs:
rand_i = np.random.randint(m) # 隨機(jī)取一個(gè)樣本
loss = cost(xMat,weights,yMat) #前一次迭代的損失值
hypothesis = sigmoid(np.dot(xMat[rand_i,:],weights)) #預(yù)測(cè)值
error = hypothesis -yMat[rand_i,:] #預(yù)測(cè)值與實(shí)際值誤差
grad = np.dot(xMat[rand_i,:].T,error) #損失函數(shù)的梯度
weights = weights - alpha*grad #參數(shù)更新
loss_new = cost(xMat,weights,yMat)#當(dāng)前迭代的損失值
print(loss_new)
if abs(loss_new-loss)<epsilon:
break
loss_list.append(loss_new)
epochs_list.append(epochs_count)
epochs_count += 1
print('迭代到第{}次,結(jié)束迭代丑罪!'.format(epochs_count))
plt.plot(epochs_list,loss_list)
plt.xlabel('epochs')
plt.ylabel('loss')
plt.show()
return weights
3. 小批量梯度下降法(Mini-batch Gradient Descent)
小批量梯度下降法是批量梯度下降算法與隨機(jī)梯度下降算法的折中荚板,因?yàn)橛靡粋€(gè)樣本代表全部可能不太準(zhǔn),那么選取其中一部分來(lái)代表全部的樣本會(huì)比只用一個(gè)好很多吩屹。即對(duì)于m個(gè)樣本跪另,每次迭代選取其中x個(gè)樣本進(jìn)行更新參數(shù),其中x稱為小批量大小(1<x<m)煤搜。對(duì)應(yīng)的參數(shù)更新公式為:
MBGD的Python實(shí)現(xiàn)
def MBGD_LR(data_x, data_y, alpha=0.1,batch_size=3, maxepochs=10000,epsilon=1e-4):
xMat = np.mat(data_x)
yMat = np.mat(data_y)
m, n = xMat.shape
weights = np.ones((n, 1)) # 模型參數(shù)
epochs_count = 0
loss_list = []
epochs_list = []
while epochs_count < maxepochs:
randIndex = np.random.choice(range(len(xMat)), batch_size, replace=False)
loss = cost(xMat,weights,yMat) #前一次迭代的損失值
hypothesis = sigmoid(np.dot(xMat[randIndex],weights)) #預(yù)測(cè)值
error = hypothesis -yMat[randIndex] #預(yù)測(cè)值與實(shí)際值誤差
grad = np.dot(xMat[randIndex].T,error) #損失函數(shù)的梯度
weights = weights - alpha*grad #參數(shù)更新
loss_new = cost(xMat,weights,yMat)#當(dāng)前迭代的損失值
print(loss_new)
if abs(loss_new-loss)<epsilon:#終止條件
break
loss_list.append(loss_new)
epochs_list.append(epochs_count)
epochs_count += 1
print('迭代到第{}次免绿,結(jié)束迭代!'.format(epochs_count))
plt.plot(epochs_list,loss_list)
plt.xlabel('epochs')
plt.ylabel('loss')
plt.show()
return weights
運(yùn)行結(jié)果
在小數(shù)據(jù)集上分別跑了這三種方法擦盾,可以看出SGD受噪聲的影響嘲驾,其損失函數(shù)的收斂伴隨的震動(dòng)比較大;而MBGD通過(guò)設(shè)置3個(gè)小批量明顯減弱了收斂的震動(dòng)現(xiàn)象迹卢,且更接近BGD訓(xùn)練得到的最小損失函數(shù)值辽故。
總結(jié)
BGD:每次迭代使用所有樣本來(lái)計(jì)算損失函數(shù)的梯度
SGD:每次迭代隨機(jī)選取1個(gè)樣本來(lái)計(jì)算損失函數(shù)的梯度
MBGD:每次迭代隨機(jī)選取x個(gè)樣本來(lái)計(jì)算損失函數(shù)的梯度
以上只是自己的學(xué)習(xí)反饋,如有錯(cuò)誤腐碱,歡迎指正誊垢。
本文代碼地址:https://github.com/DaHuangTyro/Daily_Machine_Learning