python實(shí)現(xiàn)梯度下降算法
梯度下降(Gradient Descent)算法是機(jī)器學(xué)習(xí)中使用非常廣泛的優(yōu)化算法。當(dāng)前流行的機(jī)器學(xué)習(xí)庫(kù)或者深度學(xué)習(xí)庫(kù)都會(huì)包括梯度下降算法的不同變種實(shí)現(xiàn)。
本文主要以線性回歸算法損失函數(shù)求極小值來(lái)說(shuō)明如何使用梯度下降算法并給出python實(shí)現(xiàn)。若有不正確的地方,希望讀者能指出。
梯度下降
梯度下降原理:將函數(shù)比作一座山,我們站在某個(gè)山坡上,往四周看,從哪個(gè)方向向下走一小步,能夠下降的最快。

在線性回歸算法中,損失函數(shù)為
在求極小值時(shí),在數(shù)據(jù)量很小的時(shí)候,可以使用矩陣求逆的方式求最優(yōu)的θ值。但當(dāng)數(shù)據(jù)量和特征值非常大,例如幾萬(wàn)甚至上億時(shí),使用矩陣求逆根本就不現(xiàn)實(shí)。而梯度下降法就是很好的一個(gè)選擇了。
使用梯度下降算法的步驟:
1)對(duì)θ賦初始值,這個(gè)值可以是隨機(jī)的,也可以讓?duì)仁且粋€(gè)全零的向量。
2)改變?chǔ)鹊闹?,使得目?biāo)損失函數(shù)J(θ)按梯度下降的方向進(jìn)行減少。

其中為學(xué)習(xí)率或步長(zhǎng),需要人為指定,若過(guò)大會(huì)導(dǎo)致震蕩即不收斂,若過(guò)小收斂速度會(huì)很慢。
3)當(dāng)下降的高度小于某個(gè)定義的值,則停止下降。
另外,對(duì)上面線性回歸算法損失函數(shù)求梯度,結(jié)果如下:

在實(shí)際應(yīng)用的過(guò)程中,梯度下降算法有三類(lèi),它們不同之處在于每次學(xué)習(xí)(更新模型參數(shù))使用的樣本個(gè)數(shù),每次更新使用不同的樣本會(huì)導(dǎo)致每次學(xué)習(xí)的準(zhǔn)確性和學(xué)習(xí)時(shí)間不同。下面將分別介紹原理及python實(shí)現(xiàn)。
批量梯度下降(Batch gradient descent)
每次使用全量的訓(xùn)練集樣本來(lái)更新模型參數(shù),即給定一個(gè)步長(zhǎng),然后對(duì)所有的樣本的梯度的和進(jìn)行迭代:

梯度下降算法最終得到的是局部極小值。而線性回歸的損失函數(shù)為凸函數(shù),有且只有一個(gè)局部最小,則這個(gè)局部最小一定是全局最小。所以線性回歸中使用批量梯度下降算法,一定可以找到一個(gè)全局最優(yōu)解。
優(yōu)點(diǎn):全局最優(yōu)解;易于并行實(shí)現(xiàn);總體迭代次數(shù)不多
缺點(diǎn):當(dāng)樣本數(shù)目很多時(shí),訓(xùn)練過(guò)程會(huì)很慢,每次迭代需要耗費(fèi)大量的時(shí)間。
隨機(jī)梯度下降(Stochastic gradient descent)
隨機(jī)梯度下降算法每次從訓(xùn)練集中隨機(jī)選擇一個(gè)樣本來(lái)進(jìn)行迭代,即:

隨機(jī)梯度下降算法每次只隨機(jī)選擇一個(gè)樣本來(lái)更新模型參數(shù),因此每次的學(xué)習(xí)是非常快速的,并且可以進(jìn)行在線更新。
隨機(jī)梯度下降最大的缺點(diǎn)在于每次更新可能并不會(huì)按照正確的方向進(jìn)行,因此可以帶來(lái)優(yōu)化波動(dòng)(擾動(dòng))。不過(guò)從另一個(gè)方面來(lái)看,隨機(jī)梯度下降所帶來(lái)的波動(dòng)有個(gè)好處就是,對(duì)于類(lèi)似盆地區(qū)域(即很多局部極小值點(diǎn))那么這個(gè)波動(dòng)的特點(diǎn)可能會(huì)使得優(yōu)化的方向從當(dāng)前的局部極小值點(diǎn)跳到另一個(gè)更好的局部極小值點(diǎn),這樣便可能對(duì)于非凸函數(shù),最終收斂于一個(gè)較好的局部極值點(diǎn),甚至全局極值點(diǎn)。
優(yōu)點(diǎn):訓(xùn)練速度快,每次迭代計(jì)算量不大
缺點(diǎn):準(zhǔn)確度下降,并不是全局最優(yōu);不易于并行實(shí)現(xiàn);總體迭代次數(shù)比較多。
Mini-batch梯度下降算法
Mini-batch梯度下降綜合了batch梯度下降與stochastic梯度下降,在每次更新速度與更新次數(shù)中間取得一個(gè)平衡,其每次更新從訓(xùn)練集中隨機(jī)選擇b,b<m個(gè)樣本進(jìn)行學(xué)習(xí),即:

python代碼實(shí)現(xiàn)
批量梯度下降算法
#!/usr/bin/python #coding=utf-8 import numpy as np from scipy import stats import matplotlib.pyplot as plt # 構(gòu)造訓(xùn)練數(shù)據(jù) x = np.arange(0., 10., 0.2) m = len(x) # 訓(xùn)練數(shù)據(jù)點(diǎn)數(shù)目 print m x0 = np.full(m, 1.0) input_data = np.vstack([x0, x]).T # 將偏置b作為權(quán)向量的第一個(gè)分量 target_data = 2 * x + 5 + np.random.randn(m) # 兩種終止條件 loop_max = 10000 # 最大迭代次數(shù)(防止死循環(huán)) epsilon = 1e-3 # 初始化權(quán)值 np.random.seed(0) theta = np.random.randn(2) alpha = 0.001 # 步長(zhǎng)(注意取值過(guò)大會(huì)導(dǎo)致振蕩即不收斂,過(guò)小收斂速度變慢) diff = 0. error = np.zeros(2) count = 0 # 循環(huán)次數(shù) finish = 0 # 終止標(biāo)志 while count < loop_max: count += 1 # 標(biāo)準(zhǔn)梯度下降是在權(quán)值更新前對(duì)所有樣例匯總誤差,而隨機(jī)梯度下降的權(quán)值是通過(guò)考查某個(gè)訓(xùn)練樣例來(lái)更新的 # 在標(biāo)準(zhǔn)梯度下降中,權(quán)值更新的每一步對(duì)多個(gè)樣例求和,需要更多的計(jì)算 sum_m = np.zeros(2) for i in range(m): dif = (np.dot(theta, input_data[i]) - target_data[i]) * input_data[i] sum_m = sum_m + dif # 當(dāng)alpha取值過(guò)大時(shí),sum_m會(huì)在迭代過(guò)程中會(huì)溢出 theta = theta - alpha * sum_m # 注意步長(zhǎng)alpha的取值,過(guò)大會(huì)導(dǎo)致振蕩 # theta = theta - 0.005 * sum_m # alpha取0.005時(shí)產(chǎn)生振蕩,需要將alpha調(diào)小 # 判斷是否已收斂 if np.linalg.norm(theta - error) < epsilon: finish = 1 break else: error = theta print 'loop count = %d' % count, '\tw:',theta print 'loop count = %d' % count, '\tw:',theta # check with scipy linear regression slope, intercept, r_value, p_value, slope_std_error = stats.linregress(x, target_data) print 'intercept = %s slope = %s' % (intercept, slope) plt.plot(x, target_data, 'g*') plt.plot(x, theta[1] * x + theta[0], 'r') plt.show()
運(yùn)行結(jié)果截圖:

隨機(jī)梯度下降算法
#!/usr/bin/python #coding=utf-8 import numpy as np from scipy import stats import matplotlib.pyplot as plt # 構(gòu)造訓(xùn)練數(shù)據(jù) x = np.arange(0., 10., 0.2) m = len(x) # 訓(xùn)練數(shù)據(jù)點(diǎn)數(shù)目 x0 = np.full(m, 1.0) input_data = np.vstack([x0, x]).T # 將偏置b作為權(quán)向量的第一個(gè)分量 target_data = 2 * x + 5 + np.random.randn(m) # 兩種終止條件 loop_max = 10000 # 最大迭代次數(shù)(防止死循環(huán)) epsilon = 1e-3 # 初始化權(quán)值 np.random.seed(0) theta = np.random.randn(2) # w = np.zeros(2) alpha = 0.001 # 步長(zhǎng)(注意取值過(guò)大會(huì)導(dǎo)致振蕩,過(guò)小收斂速度變慢) diff = 0. error = np.zeros(2) count = 0 # 循環(huán)次數(shù) finish = 0 # 終止標(biāo)志 ######-隨機(jī)梯度下降算法 while count < loop_max: count += 1 # 遍歷訓(xùn)練數(shù)據(jù)集,不斷更新權(quán)值 for i in range(m): diff = np.dot(theta, input_data[i]) - target_data[i] # 訓(xùn)練集代入,計(jì)算誤差值 # 采用隨機(jī)梯度下降算法,更新一次權(quán)值只使用一組訓(xùn)練數(shù)據(jù) theta = theta - alpha * diff * input_data[i] # ------------------------------終止條件判斷----------------------------------------- # 若沒(méi)終止,則繼續(xù)讀取樣本進(jìn)行處理,如果所有樣本都讀取完畢了,則循環(huán)重新從頭開(kāi)始讀取樣本進(jìn)行處理。 # ----------------------------------終止條件判斷----------------------------------------- # 注意:有多種迭代終止條件,和判斷語(yǔ)句的位置。終止判斷可以放在權(quán)值向量更新一次后,也可以放在更新m次后。 if np.linalg.norm(theta - error) < epsilon: # 終止條件:前后兩次計(jì)算出的權(quán)向量的絕對(duì)誤差充分小 finish = 1 break else: error = theta print 'loop count = %d' % count, '\tw:',theta # check with scipy linear regression slope, intercept, r_value, p_value, slope_std_error = stats.linregress(x, target_data) print 'intercept = %s slope = %s' % (intercept, slope) plt.plot(x, target_data, 'g*') plt.plot(x, theta[1] * x + theta[0], 'r') plt.show()
運(yùn)行結(jié)果截圖:

Mini-batch梯度下降
#!/usr/bin/python #coding=utf-8 import numpy as np from scipy importstats import matplotlib.pyplot as plt # 構(gòu)造訓(xùn)練數(shù)據(jù) x = np.arange(0.,10.,0.2) m = len(x) # 訓(xùn)練數(shù)據(jù)點(diǎn)數(shù)目 print m x0 = np.full(m, 1.0) input_data = np.vstack([x0, x]).T # 將偏置b作為權(quán)向量的第一個(gè)分量 target_data = 2 *x + 5 +np.random.randn(m) # 兩種終止條件 loop_max = 10000 #最大迭代次數(shù)(防止死循環(huán)) epsilon = 1e-3 # 初始化權(quán)值 np.random.seed(0) theta = np.random.randn(2) alpha = 0.001 #步長(zhǎng)(注意取值過(guò)大會(huì)導(dǎo)致振蕩即不收斂,過(guò)小收斂速度變慢) diff = 0. error = np.zeros(2) count = 0 #循環(huán)次數(shù) finish = 0 #終止標(biāo)志 minibatch_size = 5 #每次更新的樣本數(shù) while count < loop_max: count += 1 # minibatch梯度下降是在權(quán)值更新前對(duì)所有樣例匯總誤差,而隨機(jī)梯度下降的權(quán)值是通過(guò)考查某個(gè)訓(xùn)練樣例來(lái)更新的 # 在minibatch梯度下降中,權(quán)值更新的每一步對(duì)多個(gè)樣例求和,需要更多的計(jì)算 for i inrange(1,m,minibatch_size): sum_m = np.zeros(2) for k inrange(i-1,i+minibatch_size-1,1): dif = (np.dot(theta, input_data[k]) - target_data[k]) *input_data[k] sum_m = sum_m + dif #當(dāng)alpha取值過(guò)大時(shí),sum_m會(huì)在迭代過(guò)程中會(huì)溢出 theta = theta- alpha * (1.0/minibatch_size) * sum_m #注意步長(zhǎng)alpha的取值,過(guò)大會(huì)導(dǎo)致振蕩 # 判斷是否已收斂 if np.linalg.norm(theta- error) < epsilon: finish = 1 break else: error = theta print 'loopcount = %d'% count, '\tw:',theta print 'loop count = %d'% count, '\tw:',theta # check with scipy linear regression slope, intercept, r_value, p_value,slope_std_error = stats.linregress(x, target_data) print 'intercept = %s slope = %s'% (intercept, slope) plt.plot(x, target_data, 'g*') plt.plot(x, theta[1]* x +theta[0],'r') plt.show()
運(yùn)行結(jié)果:

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python使用asyncio包處理并發(fā)的實(shí)現(xiàn)代碼
這篇文章主要介紹了Python使用asyncio包處理并發(fā),asyncio包使用事件循環(huán)驅(qū)動(dòng)的協(xié)程實(shí)現(xiàn)并發(fā),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì)對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-12-12
Python中數(shù)組,列表:冒號(hào)的靈活用法介紹(np數(shù)組,列表倒序)
下面小編就為大家分享一篇Python中數(shù)組,列表:冒號(hào)的靈活用法介紹(np數(shù)組,列表倒序),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-04-04
使用Python模擬操作windows應(yīng)用窗口詳解
在日常工作中,我們經(jīng)常遇到需要進(jìn)行大量重復(fù)性任務(wù)的情況,這篇文章將介紹如何使用 Python 模擬操作記事本,感興趣的小伙伴可以了解下2025-02-02
python語(yǔ)言線程標(biāo)準(zhǔn)庫(kù)threading.local解讀總結(jié)
在本篇文章里我們給各位整理了一篇關(guān)于python threading.local源碼解讀的相關(guān)文章知識(shí)點(diǎn),有需要的朋友們可以學(xué)習(xí)下。2019-11-11
基于Python實(shí)現(xiàn)蒙特卡洛法計(jì)算圓周率π
蒙特卡羅法也稱(chēng)統(tǒng)計(jì)模擬法、統(tǒng)計(jì)試驗(yàn)法,是把概率現(xiàn)象作為研究對(duì)象的數(shù)值模擬方法,是按抽樣調(diào)查法求取統(tǒng)計(jì)值來(lái)推定未知特性量的計(jì)算方法,本文我們將介紹如何使用Python來(lái)實(shí)現(xiàn)蒙特卡洛法計(jì)算圓周率π,感興趣的朋友可以參考下2023-06-06
Python監(jiān)測(cè)屏幕界面內(nèi)容變化并發(fā)送通知方法詳解
這篇文章主要為大家介紹了Python監(jiān)測(cè)屏幕界面內(nèi)容變化并發(fā)送通知,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
在pycharm中實(shí)現(xiàn)刪除bookmark
今天小編就為大家分享一篇在pycharm中實(shí)現(xiàn)刪除bookmark,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-02-02
Python反爬實(shí)戰(zhàn)掌握酷狗音樂(lè)排行榜加密規(guī)則
最新的酷狗音樂(lè)反爬來(lái)襲,本文介紹如何利用Python掌握酷狗排行榜加密規(guī)則,本章內(nèi)容只限學(xué)習(xí),切勿用作其他用途!?。。?! 有需要的朋友可以借鑒參考下2021-10-10

