機器學習之梯度下降法

Lois發表於2020-06-12

機器學習

梯度下降法

參考連結

基本概念

梯度下降法(gradient descent),又名最速下降法(steepest descent)是求解無約束最優化問題最常用的方法,它是一種迭代方法,每一步主要的操作是求解目標函式的梯度向量,將當前位置的負梯度方向作為搜尋方向(因為在該方向上目標函式下降最快,這也是最速下降法名稱的由來)。

梯度下降,其實就是一個公式:1594463588290

公式推導

![img](file:///E:\qq聊天記錄\1713176942\Image\C2C\2D65DC80FB67F846BD86FE94D6FF8215.jpg)

基本梯度下降步驟

步驟1594380571542

η為學習率,ε為收斂條件。梯度下降法屬於機器學習,本質為:不斷迭代判斷是否滿足條件,會用到迴圈語句。

st=>start: 首先設定一個較小的正數m,n;
op=>operation: 求當前位置處的各個偏導數;
修改當前函式的引數值;
cond=>condition: 引數變化量小於n
sub1=>subroutine: 回退迭代
io=>inputoutput: 求得極小值
e=>end: 結束框
st->op->cond
cond(yes)->io->e
cond(no)->sub1(right)->op

1594382365355

1594382407187

批量梯度下降(BGD)

Batch gradient descent::批量梯度下降演算法(BGD),其需要計算整個訓練集的梯度,即:

bgd.png

其中η為學習率,用來控制更新的“力度”/"步長"。

  • 優點:

對於凸目標函式,可以保證全域性最優; 對於非凸目標函式,可以保證一個區域性最優。

  • 缺點:

速度慢; 資料量大時不可行; 無法線上優化(即無法處理動態產生的新樣本)。

程式碼實現

#引庫
#引入matplotlib庫,用於畫圖
import matplotlib.pyplot as plt
from math import pow
#圖片嵌入jupyter
#matplotlib inline

#為了便於取用資料,我們將資料分為x,y,在直角座標系中(x,y)是點
x = [1,2,3,4,5,6]
y = [13,14,20,21,25,30]
print("列印初始資料圖...")
plt.scatter(x,y)
plt.xlabel("X")
plt.ylabel("Y")
plt.show()

#超引數設定
alpha = 0.01#學習率/步長
theta0 = 0#θ0
theta1 = 0#θ1
epsilon = 0.001#誤差
m = len(x)

count = 0
loss = []

for time in range(1000):
    count += 1
    #求偏導theta0和theta1的結果
    temp0 = 0#J(θ)對θ0求導的結果
    temp1 = 0#J(θ)對θ1求導的結果
    diss = 0
    for i in range(m):
        temp0 += (theta0+theta1*x[i]-y[i])/m
        temp1 += ((theta0+theta1*x[i]-y[i])/m)*x[i]

    #更新theta0和theta1
    for i in range(m):
        theta0 = theta0 - alpha*((theta0+theta1*x[i]-y[i])/m) 
        theta1 = theta1 - alpha*((theta0+theta1*x[i]-y[i])/m)*x[i]

    #求損失函式J(θ)
    for i in range(m):
        diss = diss + 0.5*(1/m)*pow((theta0+theta1*x[i]-y[i]),2)
    loss.append(diss)

    #看是否滿足條件
    '''
    if diss<=epsilon:
        break
    else:
        continue
    '''
print("最終的結果為:")
print("此次迭代次數為:{}次,最終theta0的結果為:{},最終theta1的結果為:{}".format(count,theta0,theta1))
print("預測的最終迴歸函式為:y={}+{}x\n".format(theta0,theta1))
print("迭代影像繪製...")
plt.scatter(range(count),loss)
plt.show()

執行結果

1594475742309

隨機梯度下降(SGD)

Stochastic gradient descent:隨機梯度下降演算法(SGD),僅計算某個樣本的梯度,即針對某一個訓練樣本 xi及其label yi更新引數:

sgd.png

逐步減小學習率,SGD表現得同BGD很相似,最後都可以有不錯的收斂。

  • 優點:

更新頻次快,優化速度更快; 可以線上優化(可以無法處理動態產生的新樣本);一定的隨機性導致有機率跳出區域性最優(隨機性來自於用一個樣本的梯度去代替整體樣本的梯度)。

  • 缺點:

隨機性可能導致收斂複雜化,即使到達最優點仍然會進行過度優化,因此SGD得優化過程相比BGD充滿動盪。

程式碼實現

#引庫
#引入matplotlib庫,用於畫圖
import matplotlib.pyplot as plt
from math import pow
import numpy as np
#圖片嵌入jupyter
#matplotlib inline

#為了便於取用資料,我們將資料分為x,y,在直角座標系中(x,y)是點
x = [1,2,3,4,5,6]
y = [13,14,20,21,25,30]
print("列印初始資料圖...")
plt.scatter(x,y)
plt.xlabel("X")
plt.ylabel("Y")
plt.show()

#超引數設定
alpha = 0.01#學習率/步長
theta0 = 0#θ0
theta1 = 0#θ1
epsilon = 0.001#誤差
m = len(x)

count = 0
loss = []

for time in range(1000):
    count += 1
    diss = 0
    #求偏導theta0和theta1的結果
    temp0 = 0#J(θ)對θ0求導的結果
    temp1 = 0#J(θ)對θ1求導的結果
    for i in range(m):
        temp0 += (theta0+theta1*x[i]-y[i])/m
        temp1 += ((theta0+theta1*x[i]-y[i])/m)*x[i]

    #更新theta0和theta1
    for i in range(m):
        theta0 = theta0 - alpha*((theta0+theta1*x[i]-y[i])/m) 
        theta1 = theta1 - alpha*((theta0+theta1*x[i]-y[i])/m)*x[i]

    #求損失函式J(θ)
    rand_i = np.random.randint(0,m)
    diss += 0.5*(1/m)*pow((theta0+theta1*x[rand_i]-y[rand_i]),2)
    loss.append(diss)

    #看是否滿足條件
    '''
    if diss<=epsilon:
        break
    else:
        continue
    '''
print("最終的結果為:")
print("此次迭代次數為:{}次,最終theta0的結果為:{},最終theta1的結果為:{}".format(count,theta0,theta1))
print("預測的最終迴歸函式為:y={}+{}x\n".format(theta0,theta1))
print("迭代影像繪製...")
plt.scatter(range(count),loss)
plt.show()

執行結果

1594476028430

小批量梯度下降(MBGD)

Mini-batch gradient descent:小批量梯度下降演算法(MBGD),計算包含n個樣本的mini-batch的梯度

mbgd.png

MBGD是訓練神經網路最常用的優化方法。

  • 優點:

引數更新時的動盪變小,收斂過程更穩定,降低收斂難度;可以利用現有的線性代數庫高效的計算多個樣本的梯度。

程式碼實現

#引庫
#引入matplotlib庫,用於畫圖
import matplotlib.pyplot as plt
from math import pow
import numpy as np
#圖片嵌入jupyter
#matplotlib inline

#為了便於取用資料,我們將資料分為x,y,在直角座標系中(x,y)是點
x = [1,2,3,4,5,6]
y = [13,14,20,21,25,30]
print("列印初始資料圖...")
plt.scatter(x,y)
plt.xlabel("X")
plt.ylabel("Y")
plt.show()

#超引數設定
alpha = 0.01#學習率/步長
theta0 = 0#θ0
theta1 = 0#θ1
epsilon = 0.001#誤差
diss = 0#損失函式
m = len(x)

count = 0
loss = []

for time in range(1000):
    count += 1
    diss = 0
    #求偏導theta0和theta1的結果
    temp0 = 0#J(θ)對θ0求導的結果
    temp1 = 0#J(θ)對θ1求導的結果
    for i in range(m):
        temp0 += (theta0+theta1*x[i]-y[i])/m
        temp1 += ((theta0+theta1*x[i]-y[i])/m)*x[i]

    #更新theta0和theta1
    for i in range(m):
        theta0 = theta0 - alpha*((theta0+theta1*x[i]-y[i])/m) 
        theta1 = theta1 - alpha*((theta0+theta1*x[i]-y[i])/m)*x[i]

    #求損失函式J(θ)
    result = []
    for i in range(3):
        rand_i = np.random.randint(0,m)
        result.append(rand_i)
    for j in result:
        diss += 0.5*(1/m)*pow((theta0+theta1*x[j]-y[j]),2)
    loss.append(diss)

    #看是否滿足條件
    '''
    if diss<=epsilon:
        break
    else:
        continue
    '''
print("最終的結果為:")
print("此次迭代次數為:{}次,最終theta0的結果為:{},最終theta1的結果為:{}".format(count,theta0,theta1))
print("預測的最終迴歸函式為:y={}+{}x\n".format(theta0,theta1))
print("迭代影像繪製...")
plt.scatter(range(count),loss)
plt.show()

執行結果

1594476309210

相關文章