手動實現梯度下降(GD)及優化
梯度下降演算法是機器學習中必不可少的方法,主要包括:批量梯度下降(Batch Gradient Descent,簡稱BGD),隨機梯度下降法(Stochastic Gradient Descent,簡稱SGD)和小批量梯度下降法(Mini-batch Gradient Descent,簡稱MBGD)。針對BGD演算法,通過實現線性回歸,手寫實現。
環境
python環境:Anaconda3
系統環境:windows 7 x64
代碼參考:sk-learn
手動實現BGD:
import numpy as npimport pandas as pdfrom pylab import * if __name__ == "__main__": x = np.arange(0,10) y = map(lambda x : x*3+1, x) y = np.array(list(y)) ########################################################################### # kernel code w = 0 b = 0 CT = 0.001 count = 1000 xtage = list(range(count)) ytage = list(range(count)) for j in range(count): sw = 0 sb = 0 #computer BGD for i in range(len(x)): sb = sb - 2*(y[i] - (w*x[i] + b))* 1 sw = sw - 2*(y[i] - (w*x[i] + b))* x[i] pass #udpate paraments w = w - CT * sw b = b - CT * sb #server for plot xtage[j] = w ytage[j] = b pass################################################################################# #plot the result plt.figure(figsize=(8, 8)) plt.subplot(2, 2, 1) loc = int(count*0.1) xx = xtage[:loc] yy = ytage[:loc] plt.title(cout:+str(loc)) plot(xx, yy, .) plot(3, 1, v) plt.subplot(2, 2, 2) loc = int(count*0.2) xx = xtage[:loc] yy = ytage[:loc] plt.title(cout:+str(loc)) plot(xx, yy, .) plot(3, 1, v) plt.subplot(2, 2, 3) loc = int(count*0.4) xx = xtage[:loc] yy = ytage[:loc] plt.title(cout:+str(loc)) plot(xx, yy, .) plot(3, 1, v) plt.subplot(2, 2, 4) plt.title(cout:+str(count)) plot(xtage, ytage, .) plot(3, 1, v)
結果:
原始的x是:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
原始的y是:[ 1, 4, 7, 10, 13, 16, 19, 22, 25, 28]
y與x滿足:y = 3*x + 1,對應於:y = wx + b
線性回歸的目的是擬合出較好的w和b值,標準值是(3,1)。
GBD原理:
對應的代碼是:
#computer BGD for i in range(len(x)): sb = sb - 2*(y[i] - (w*x[i] + b))* 1 sw = sw - 2*(y[i] - (w*x[i] + b))* x[i] pass
初始設置學習率為 CT = 0.001,迭代次數是count = 1000。
畫圖結果是,分別計算count不同值時對應的(w,b)位置,圖中黃色三角是標準值。可以看到隨著迭代次數增大,越來越逼近標準值。
學習率選擇
BGD演算法中,學習率CT的設置很關鍵,如果設置過大有可能飛出。例如在本代碼中將CT值設置為0.1時,有可能無法得到w值。2010年Duchi et.al 推出AdaGrad,自適應來調整學習率。
修改後代碼
import numpy as npimport pandas as pdfrom pylab import * if __name__ == "__main__": x = np.arange(0,10)## y = map(np.sin(),) y = map(lambda x : x*3+1, x) y = np.array(list(y))############################################################################### w = 0 b = 0 CT = 1 count = 500 CT_w = 0 CT_b = 0 xtage = list(range(count)) ytage = list(range(count)) for j in range(count): sw = 0 sb = 0 for i in range(len(x)): sb = sb - 2*(y[i] - (w*x[i] + b))* 1 sw = sw - 2*(y[i] - (w*x[i] + b))* x[i] pass ############################################################################### #update parameters CT_w = CT_w + sw**2 CT_b = CT_b + sb**2 w = w - CT/(np.sqrt(CT_w)) * sw b = b - CT/(np.sqrt(CT_b))* sb xtage[j] = w ytage[j] = b pass############################################################################### #plot the result plt.figure(figsize=(8, 8)) plt.subplot(2, 2, 1) loc = int(count*0.1) xx = xtage[:loc] yy = ytage[:loc] plt.title(cout:+str(loc)) plot(xx, yy, .) plot(3, 1, v) plt.subplot(2, 2, 2) loc = int(count*0.2) xx = xtage[:loc] yy = ytage[:loc] plt.title(cout:+str(loc)) plot(xx, yy, .) plot(3, 1, v) plt.subplot(2, 2, 3) loc = int(count*0.4) xx = xtage[:loc] yy = ytage[:loc] plt.title(cout:+str(loc)) plot(xx, yy, .) plot(3, 1, v) plt.subplot(2, 2, 4) plt.title(cout:+str(count)) plot(xtage, ytage, .) plot(3, 1, v)
結果:
學習率(CT)直接設置成1即可,相對於設置為較小CT傳統BGD1000次的迭代,加上AdaGrad的BGD500即可達到較好效果。
BGD(批量梯度下降)需要計算所有的統計值:
for i in range(len(x)): sb = sb - 2*(y[i] - (w*x[i] + b))* 1 sw = sw - 2*(y[i] - (w*x[i] + b))* x[i] pass
當數據量很大時,計算結果滿。SGD(隨機梯度下降)提出不統計所有的值,隨便選取「一個」。MBGD(批量梯度下降)相對於SGD(隨機梯度下降)隨機選「一個」,隨機選取一部分做梯度下降。
對應的代碼就是:
for i in range(len(x)):
sb = sb - 2*(y[i] - (w*x[i] + b))* 1
sw = sw - 2*(y[i] - (w*x[i] + b))* x[i]
pass
中的len(x)變成隨機的x。
參考文獻:
[1]Duchi J C, Hazan E, Singer Y, et al. Adaptive Subgradient Methods for Online Learning and Stochastic Optimization[J]. Journal of Machine Learning Research, 2011: 2121-2159.
[2][Machine Learning] 梯度下降法的三種形式BGD、SGD以及MBGD
推薦閱讀:
※一文看懂常用的梯度下降演算法
※如何訓練模型?(2)——梯度下降法
※機器學習:用梯度下降法實現線性回歸
※梯度下降法快速教程 | 第二章:衝量(momentum)的原理與Python實現
※梯度下降、隨機梯度下降(SGD)、mini-batch SGD