python實(shí)現(xiàn)線性回歸的梯度下降法

在機(jī)器學(xué)習(xí)中,有時(shí)候需要對(duì)原始的模型構(gòu)造損失函數(shù),然后通過優(yōu)劃算法對(duì)損失函數(shù)進(jìn)行優(yōu)劃,從而找到最優(yōu)的參數(shù)使損失函數(shù)達(dá)到最小值。但損失函數(shù)一般都比較復(fù)雜,難以從函數(shù)本身找到最優(yōu)的參數(shù),因此實(shí)際應(yīng)用過程中使用得較多的就是梯度下降法。通過逐漸改變參數(shù),使損失函數(shù)逐漸收斂,最終確定參數(shù)值使損失函數(shù)的值最小。

梯度下降的方式分為三種:批量梯度下降(Batch Gradient Descent),隨機(jī)梯度下降(stochastic gradient descent),小批量隨機(jī)下降(mini-batch Gradient Descent)。批量梯度下降(BGD)針對(duì)的是整個(gè)數(shù)據(jù)集,通過對(duì)所有的樣本的計(jì)算來求解梯度的方向。但是在實(shí)際應(yīng)用中數(shù)據(jù)量往往會(huì)很大,從而導(dǎo)致使用批量梯度下降的效率變得很低,因此引入了隨機(jī)批量下降法(SGD),隨機(jī)梯度下降法是每次迭代只針對(duì)單個(gè)樣本計(jì)算損失函數(shù)對(duì)參數(shù)的偏導(dǎo)數(shù),從而尋找一個(gè)梯度來更新參數(shù),因此效率高于BGD,但是SGD也有一定的局限性,它的收斂效果不如BGD好,因?yàn)槊看沃皇褂脝蝹€(gè)樣本進(jìn)行計(jì)算。而小批量隨機(jī)下降(MBGD)又針對(duì)SGD進(jìn)行了改進(jìn),一次性針對(duì)一小部分樣本來計(jì)算,因此在提高效率的同時(shí)也比SGD更加穩(wěn)定,降低了隨機(jī)性。

接下來就這三種梯度下降方法針對(duì)線性回歸問題來進(jìn)行python的實(shí)現(xiàn)

批量梯度下降法

import numpy as np
X = 2 * np.random.random(size=20000).reshape(-1, 2)
y = X[:, 0] * 2. + X[:, 1] * 3. + 3. + np.random.normal(size=10000)
temp = np.ones((len(y), 1))
X_b = np.hstack((temp, X))                                              #為了矩陣運(yùn)算方便在X中加上全為1的一列
theta = np.zeros(X_b.shape[1])                                          #theta是參數(shù),梯度下降通過不斷更新theta的值使損失函數(shù)達(dá)到最小值
eta = 0.01                                                              #eta代表是學(xué)習(xí)速率
episilon = 1e-8                                                         #episilon用來判斷損失函數(shù)是否收斂
print(X_b.shape)
print(y.shape)
print(theta.shape)

這是運(yùn)行結(jié)果

(10000, 3)
(10000,)
(3,)

在示例中我們創(chuàng)建了一個(gè)二維數(shù)組,原始的X是只有兩個(gè)特征,為了后續(xù)矩陣計(jì)算的方便,我們給X添加了一個(gè)全為1的特征,添加后的結(jié)果存在X_b中,后續(xù)計(jì)算均使用X_b進(jìn)行。eta代表學(xué)習(xí)速率,如果eta太小的話,theta下降得就會(huì)很慢,但是eta太大的話,參數(shù)可能就會(huì)朝著增大損失函數(shù)的方向移動(dòng)。episilon用來判斷損失函數(shù)是否已經(jīng)收斂。

def J(theta, X_b, y): 
    '''
    損失函數(shù)
    '''
    return np.sum((y - np.dot(X_b, theta))**2) / len(y)

def dJ(theta, X_b, y):
    '''
    損失函數(shù)對(duì)theta的偏導(dǎo)數(shù)
    '''
    gradient = X_b.T.dot(X_b.dot(theta) - y) * 2. / len(y)
    return gradient

這里定義了兩個(gè)函數(shù),J代表?yè)p失函數(shù),dJ代表?yè)p失函數(shù)對(duì)參數(shù)theta的偏導(dǎo)數(shù)。

def gradient_decent(theta, X_b, y):
    '''
    梯度下降過程
    '''
    while True:
        last_theta = theta
        theta = theta - eta * dJ(theta, X_b, y)
        if abs(J(theta, X_b, y) - J(last_theta, X_b, y)) <= episilon:  #判斷損失函數(shù)是否收斂,也可以限定最大迭代次數(shù)
            break
    return theta

這是梯度下降的整個(gè)過程,判斷前后兩次損失函數(shù)的差值是否小于episilon,若小于的話則判斷為收斂中止循環(huán),若大于的話則繼續(xù)梯度下降過程
接下來調(diào)用該函數(shù)

rst = gradient_decent(theta, X_b, y)
print(rst)
[2.97546654 2.00406701 3.0292728 ]

可以看到rst中的三個(gè)數(shù)于我們之前設(shè)置y的那個(gè)方程的三個(gè)系數(shù)大致是一樣的。rst[0]代表的是截距,即原函數(shù)中沒有x的常數(shù)項(xiàng)3.0,rst[1]代表的是X第0個(gè)特征的系數(shù),原函數(shù)中是2.0, rst[2]代表X的第一個(gè)特征的系數(shù),原函數(shù)中是3.0。

隨機(jī)梯度下降法

由于隨機(jī)梯度下降法的兩次迭代的損失函數(shù)的差值隨機(jī)性很強(qiáng),所以一般不使用episilon來判斷收斂,而是設(shè)置一個(gè)最大的迭代次數(shù),迭代完之后就return結(jié)果。
首先還是使用之前的數(shù)據(jù)

X = 2 * np.random.random(size=20000).reshape(-1, 2)
y = X[:, 0] * 2. + X[:, 1] * 3. + 3. + np.random.normal(size=10000)
temp = np.ones((len(y), 1))
X_b = np.hstack((temp, X))                                              #為了矩陣運(yùn)算方便在X中加上全為1的一列
theta = np.zeros(X_b.shape[1])                                          #theta是參數(shù),梯度下降通過不斷更新theta的值使損失函數(shù)達(dá)到最小值
eta = 0.01                                                              #eta代表是學(xué)習(xí)速率
episilon = 1e-8                                                         #episilon用來判斷損失函數(shù)是否收斂
def dJ_sgd(theta, X_b_i, y_i):
    return X_b_i.T.dot(X_b_i.dot(theta) - y_i) * 2

def sgd(X_b_i, y, theta, n_iters):
    t0 = 5
    t1 = 50
    
    def learn_rate(t):
        return t0/(t + t1)
    
    theta = theta
    for cur_iter in range(n_iters):
        rand_i = np.random.randint(len(X_b))
        gradient = dJ_sgd(theta, X_b[rand_i], y[rand_i])
        theta = theta - learn_rate(cur_iter) * gradient
    
    return theta
print(sgd(X_b, y, theta, n_iters=len(X_b)//3))

dJ_sgd是損失函數(shù)對(duì)theta的偏導(dǎo)數(shù),這里傳進(jìn)去的參數(shù)是X_b和y中的某一個(gè)樣本的數(shù)據(jù)。在實(shí)現(xiàn)過程中還定義了一個(gè)learn_rate的函數(shù),因?yàn)樵陔S機(jī)梯度下降過程中學(xué)習(xí)速率應(yīng)該要隨次數(shù)遞減,因?yàn)榇嬖陔S機(jī)性強(qiáng)的特點(diǎn),防止下降到局部最小值附近又發(fā)生較大的改變。
運(yùn)行結(jié)果

[2.99905964 2.06011999 3.01684189]

小批量隨機(jī)下降

小批量隨機(jī)下降與隨即梯度下降思路大致相同,只不過傳參的時(shí)候需要傳入一部分?jǐn)?shù)據(jù)

def dJ_mbgd(theta, X_b_n, y_n, num):
    return X_b_n.T.dot(X_b_n.dot(theta) - y_n) * 2 / num

def mbgd(theta, X_b, y, num, n_iters):
    t0 = 5
    t1 = 50
    theta = theta
    num = num
    
    def learn_rate(t):
        return t0/(t + t1)
    
    for cur_iter in range(n_iters):
        x_index = np.random.randint(0, len(y), num)
        gradient = dJ_mbgd(theta, X_b[x_index,], y[x_index], num)
        theta  = theta -  learn_rate(cur_iter) * gradient
        
    return theta
print(mbgd(theta, X_b, y, num=20, n_iters=len(X_b)//3))

num代表每次下降使用多少個(gè)樣本數(shù)據(jù)。
運(yùn)行結(jié)果

[2.98763611 2.00527425 3.01625422]
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,595評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,560評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,814評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,224評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,444評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,988評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,804評(píng)論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,998評(píng)論 1 370
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評(píng)論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,237評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評(píng)論 1 287
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,706評(píng)論 3 393
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,993評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容