目錄
- 前言
- 1.梯度下降方法
- 1.1 三種梯度下降不同
- 1.2 線性回歸梯度更新公式
- 1.3 批量梯度下降 B G D BGD BGD
- 1.4 隨機梯度下降 S G D SGD SGD
- 1.5 小批量梯度下降 M B G D MBGD MBGD
- 2.代碼實作梯度下降
- 2.1 批量梯度下降 B G D BGD BGD
- 2.1.1 一元一次線性回歸
- 2.1.2 八元一次線性回歸
- 2.2 隨機梯度下降 S G D SGD SGD
- 2.2.1 一元一次線性回歸
- 2.2.2 五元一次線性回歸
- 2.3 小批量梯度下降 M B G D MBGD MBGD
- 2.3.1 一元一次線性回歸
- 2.3.2 三元一次線性回歸
前言
本文屬于 線性回歸演算法【AIoT階段三】(尚未更新),這里截取自其中一段內容,方便讀者理解和根據需求快速閱讀,本文通過公式推導+代碼兩個方面同時進行,因為涉及到代碼的編譯運行,如果你沒有 N u m P y NumPy NumPy, P a n d a s Pandas Pandas, M a t p l o t l i b Matplotlib Matplotlib 的基礎,建議先修文章:資料分析三劍客【AIoT階段一(下)】(十萬字博文 保姆級講解),本文是梯度下降的第二部分,學之前需先修:梯度下降【無約束最優化問題】,后續還會有:梯度下降優化,梯度下降優化進階 (暫未更新)
1.梯度下降方法
1.1 三種梯度下降不同
🚩梯度下降分三類:批量梯度下降 B G D BGD BGD(Batch Gradient Descent)、小批量梯度下降 M B G D MBGD MBGD(Mini-Batch Gradient Descent)、隨機梯度下降 S G D SGD SGD(Stochastic Gradient Descent),

三種梯度下降有什么不同呢?我們從梯度下降步驟開始講起,梯度下降步驟分以下四步:
-
1、隨機賦值, R a n d o m Random Random 亂數生成 θ \theta θ,隨機一組數值 w 0 、 w 1 … … w n w_0、w_1……w_n w0?、w1?……wn?
-
2、求梯度 g g g ,梯度代表曲線某點上的切線的斜率,沿著切線往下就相當于沿著坡度最陡峭的方向下降
-
3、 i f if if g < 0 g < 0 g<0, θ \theta θ 變大, i f if if g > 0 g > 0 g>0, θ \theta θ 變小
-
4、判斷是否收斂 c o n v e r g e n c e convergence convergence,如果收斂跳出迭代,如果沒有達到收斂,回第 2 2 2 步再次執行 2 2 2 ~ 4 4 4 步
收斂的判斷標準是:隨著迭代進行損失函式 L o s s Loss Loss,變化非常微小甚至不再改變,即認為達到收斂
三種梯度下降不同,體現在第二步中:
-
B G D BGD BGD 是指在每次迭代使用所有樣本來進行梯度的更新
-
M B G D MBGD MBGD 是指在每次迭代使用一部分樣本(所有樣本 500 500 500 個,使用其中 32 32 32 個樣本)來進行梯度的更新
-
S G D SGD SGD 是指每次迭代隨機選擇一個樣本來進行梯度更新
1.2 線性回歸梯度更新公式
🚩回顧上一講公式!
最小二乘法公式如下:
J ( θ ) = 1 2 ∑ i = 1 n ( h θ ( x ( i ) ) ? y ( i ) ) 2 J(\theta) = \frac{1}{2}\sum\limits_{i = 1}^n(h_{\theta}(x^{(i)}) - y^{(i)})^2 J(θ)=21?i=1∑n?(hθ?(x(i))?y(i))2
矩陣寫法:
J ( θ ) = 1 2 ( X θ ? y ) T ( X θ ? y ) J(\theta) = \frac{1}{2}(X\theta - y)^T(X\theta - y) J(θ)=21?(Xθ?y)T(Xθ?y)
接著我們來講解如何求解上面梯度下降的第 2 2 2 步,即我們要推匯出損失函式的導函式來,
-
θ j n + 1 = θ j n ? η ? ? J ( θ ) ? θ j \theta_j^{n + 1} = \theta_j^{n} - \eta * \frac{\partial J(\theta)}{\partial \theta_j} θjn+1?=θjn??η??θj??J(θ)? 其中 j j j 表示第 j j j 個系數
-
? J ( θ ) ? θ j = ? ? θ j 1 2 ( h θ ( x ) ? y ) 2 \frac{\partial J(\theta)}{\partial \theta_j} = \frac{\partial}{\partial \theta_j}\frac{1}{2}(h_{\theta}(x) - y)^2 ?θj??J(θ)?=?θj???21?(hθ?(x)?y)2
= 1 2 ? 2 ( h θ ( x ) ? y ) ? ? θ j ( h θ ( x ) ? y ) = \frac{1}{2}*2(h_{\theta}(x) - y)\frac{\partial}{\partial \theta_j}(h_{\theta}(x) - y) =21??2(hθ?(x)?y)?θj???(hθ?(x)?y) ( 1 ) (1) (1)
= ( h θ ( x ) ? y ) ? ? θ j ( ∑ i = 0 n θ i x i ? y ) = (h_{\theta}(x) - y)\frac{\partial}{\partial \theta_j}(\sum\limits_{i = 0}^n\theta_ix_i - y) =(hθ?(x)?y)?θj???(i=0∑n?θi?xi??y) ( 2 ) (2) (2)
= ( h θ ( x ) ? y ) x j = (h_{\theta}(x) - y)x_j =(hθ?(x)?y)xj? ( 3 ) (3) (3)
?? x 2 x^2 x2的導數就是 2 x 2x 2x,根據鏈式求導法則,我們可以推出上面第 ( 1 ) (1) (1) 步,然后是多元線性回歸,所以 h θ ( x ) h_{\theta}(x) hθ?(x) 就 是 θ T x \theta^Tx θTx 即是 w 0 x 0 + w 1 x 1 + … … + w n x n w_0x_0 + w_1x_1 + …… + w_nx_n w0?x0?+w1?x1?+……+wn?xn? 即 ∑ i = 0 n θ i x i \sum\limits_{i = 0}^n\theta_ix_i i=0∑n?θi?xi?,到這里我們是對 θ j \theta_j θj? 來求偏導,那么和 w j w_j wj? 沒有關系的可以忽略不計,所以只剩下 x j x_j xj?,
??我們可以得到結論就是 θ j \theta_j θj? 對應的梯度與預測值 y ^ \hat{y} y^? 和真實值 y y y 有關,這里 y ^ \hat{y} y^? 和 y y y 是列向量(即多個資料),同時還與 θ j \theta_j θj? 對應的特征維度 x j x_j xj? 有關,這里 x j x_j xj? 是原始資料集矩陣的第 j j j 列,如果我們分別去對每個維度 θ 0 、 θ 1 … … θ n \theta_0、\theta_1……\theta_n θ0?、θ1?……θn? 求偏導,即可得到所有維度對應的梯度值,
- g 0 = ( h θ ( x ) ? y ) x 0 g_0 = (h_{\theta}(x) - y)x_0 g0?=(hθ?(x)?y)x0?
- g 1 = ( h θ ( x ) ? y ) x 1 g_1 = (h_{\theta}(x) - y)x_1 g1?=(hθ?(x)?y)x1?
- ……
- g j = ( h θ ( x ) ? y ) x j g_j = (h_{\theta}(x) - y)x_j gj?=(hθ?(x)?y)xj?
總結:
θ j n + 1 = θ j n ? η ? ( h θ ( x ) ? y ) x j \theta_j^{n + 1} = \theta_j^{n} - \eta * (h_{\theta}(x) - y )x_j θjn+1?=θjn??η?(hθ?(x)?y)xj?
1.3 批量梯度下降 B G D BGD BGD
🚩批量梯度下降法是最原始的形式,它是指在每次迭代使用所有樣本來進行梯度的更新,每次迭代引數更新公式如下:
θ j n + 1 = θ j n ? η ? 1 n ∑ i = 1 n ( h θ ( x ( i ) ) ? y ( i ) ) x j ( i ) \theta_j^{n + 1} = \theta_j^{n} - \eta *\frac{1}{n}\sum\limits_{i = 1}^{n} (h_{\theta}(x^{(i)}) - y^{(i)} )x_j^{(i)} θjn+1?=θjn??η?n1?i=1∑n?(hθ?(x(i))?y(i))xj(i)?
去掉 1 n \frac{1}{n} n1? 也可以,因為它是一個常量,可以和 η \eta η 合并
θ j n + 1 = θ j n ? η ? ∑ i = 1 n ( h θ ( x ( i ) ) ? y ( i ) ) x j ( i ) \theta_j^{n + 1} = \theta_j^{n} - \eta *\sum\limits_{i = 1}^{n} (h_{\theta}(x^{(i)}) - y^{(i)} )x_j^{(i)} θjn+1?=θjn??η?i=1∑n?(hθ?(x(i))?y(i))xj(i)?
矩陣寫法:
θ n + 1 = θ n ? η ? X T ( X θ ? y ) \theta^{n + 1} = \theta^{n} - \eta * X^T(X\theta -y) θn+1=θn?η?XT(Xθ?y)
其中 𝑖 = 1 , 2 , . . . , n 𝑖 = 1, 2, ..., n i=1,2,...,n 表示樣本數, 𝑗 = 0 , 1 … … 𝑗 = 0, 1…… j=0,1…… 表示特征數,這里我們使用了偏置項,即解決 x 0 ( i ) = 1 x_0^{(i)} = 1 x0(i)?=1,
注意這里更新時存在一個求和函式,即為對所有樣本進行計算處理!
優點:
??(1)一次迭代是對所有樣本進行計算,此時利用矩陣進行操作,實作了并行,
??(2)由全資料集確定的方向能夠更好地代表樣本總體,從而更準確地朝向極值所在的方向,當目標函式為凸函式時,
B
G
D
BGD
BGD 一定能夠得到全域最優,
缺點:
??(1)當樣本數目
n
n
n 很大時,每迭代一步都需要對所有樣本計算,訓練程序會很慢,
從迭代的次數上來看,
B
G
D
BGD
BGD 迭代的次數相對較少,其迭代的收斂曲線示意圖可以表示如下:

1.4 隨機梯度下降 S G D SGD SGD
🚩隨機梯度下降法不同于批量梯度下降,隨機梯度下降是每次迭代使用一個樣本來對引數進行更新,使得訓練速度加快,每次迭代引數更新公式如下:
θ j n + 1 = θ j n ? η ? ( h θ ( x ( i ) ) ? y ( i ) ) x j ( i ) \theta_j^{n + 1} = \theta_j^{n} - \eta *(h_{\theta}(x^{(i)}) - y^{(i)} )x_j^{(i)} θjn+1?=θjn??η?(hθ?(x(i))?y(i))xj(i)?
批量梯度下降演算法每次都會使用全部訓練樣本,因此這些計算是冗余的,因為每次都使用完全相同的樣本集,而隨機梯度下降演算法每次只隨機選擇一個樣本來更新模型引數,因此每次的學習是非常快速的,
優點:
??(1)由于不是在全部訓練資料上的更新計算,而是在每輪迭代中,隨機選擇一條資料進行更新計算,這樣每一輪引數的更新速度大大加快,
??缺點:
??(1)準確度下降,由于即使在目標函式為強凸函式的情況下,
S
G
D
SGD
SGD 仍舊無法做到線性收斂,
??(2)可能會收斂到區域最優,由于單個樣本并不能代表全體樣本的趨勢,
解釋一下為什么SGD收斂速度比BGD要快:
- 這里我們假設有 30 W 30W 30W 個樣本,對于 B G D BGD BGD 而言,每次迭代需要計算 30 W 30W 30W 個樣本才能對引數進行一次更新,需要求得最小值可能需要多次迭代(假設這里是 10 10 10),
- 而對于 S G D SGD SGD,每次更新引數只需要一個樣本,因此若使用這30W個樣本進行引數更新,則引數會被迭代 30 W 30W 30W 次,而這期間, S G D SGD SGD 就能保證能夠收斂到一個合適的最小值上了,
- 也就是說,在收斂時, B G D BGD BGD 計算了 10 × 30 W 10×30W 10×30W 次,而 S G D SGD SGD 只計算了 1 × 30 W 1×30W 1×30W 次,
從迭代的次數上來看, S G D SGD SGD 迭代的次數較多,在解空間的搜索程序就會盲目一些,其迭代的收斂曲線示意圖可以表示如下:

1.5 小批量梯度下降 M B G D MBGD MBGD
🚩小批量梯度下降,是對批量梯度下降以及隨機梯度下降的一個折中辦法,其思想是:每次迭代使用總樣本中的一部分 ( b a t c h s i z e ) (batch_size) (batchs?ize) 樣本來對引數進行更新,這里我們假設 b a t c h s i z e = 20 batch_size = 20 batchs?ize=20,樣本數 n = 1000 n = 1000 n=1000 ,實作了更新速度與更新次數之間的平衡,每次迭代引數更新公式如下:
θ j n + 1 = θ j n ? η ? 1 b a t c h _ s i z e ∑ i = 1 b a t c h _ s i z e ( h θ ( x ( i ) ) ? y ( i ) ) x j ( i ) \theta_j^{n + 1} = \theta_j^{n} - \eta *\frac{1}{batch\_size}\sum\limits_{i = 1}^{batch\_size} (h_{\theta}(x^{(i)}) - y^{(i)} )x_j^{(i)} θjn+1?=θjn??η?batch_size1?i=1∑batch_size?(hθ?(x(i))?y(i))xj(i)?
相對于隨機梯度下降演算法,小批量梯度下降演算法降低了收斂波動性, 即降低了引數更新的方差,使得更新更加穩定,相對于全量梯度下降,其提高了每次學習的速度,并且其不用擔心記憶體瓶頸從而可以利用矩陣運算進行高效計算,
一般情況下,小批量梯度下降是梯度下降的推薦變體,特別是在深度學習中,每次隨機選擇 2 2 2 的冪數個樣本來進行學習,例如: 8 8 8、 16 16 16、 32 32 32、 64 64 64、 128 128 128、 256 256 256,因為計算機的結構就是二進制的,但是也要根據具體問題而選擇,實踐中可以進行多次試驗, 選擇一個更新速度與更次次數都較適合的樣本數,
M B G D MBGD MBGD 梯度下降迭代的收斂曲線更加溫柔一些:

2.代碼實作梯度下降
2.1 批量梯度下降 B G D BGD BGD
2.1.1 一元一次線性回歸
import numpy as np
# 創建資料
X = np.random.rand(100, 1)
w, b = np.random.randint(1, 10, size = 2)
# 增加噪聲,也被稱為"加鹽"
y = w * X + b + np.random.rand(100, 1)
# 把b作為偏置項,截距對應系數 x_0 = 1, 更新 X
X = np.concatenate([X, np.full(shape = (100, 1),
fill_value = 1)], axis = 1)
# 回圈次數
epoches = 10000
# 學習率
eta = 0.01
# 要求解的系數,"瞎蒙的"
theta = np.random.randn(2, 1)
for i in range(epoches):
# 批量梯度下降,X為矩陣,包含所有的資料
g = X.T.dot(X.dot(theta) - y) # 根據公式計算的梯度
theta = theta - eta * g
print('真實的斜率、截距:', w, b)
print('使用BGD求的斜率、截距:', theta[0], theta[1])

可以看出,我們求出的資料和真實的資料還是有一定的差距的,這就是加了 噪聲(加鹽) 的作用結果,但這樣的計算資料才是更加真實的,因為現實生活中的資料是不可能完美的,
下圖是梯度下降的示意圖:

我們可以看出,對于剛開始進行梯度下降的時候,
L
e
a
r
n
i
n
g
Learning
Learning
s
t
e
p
step
step 比較大,即學習率的值比較大,在越接近正確答案的時候,
L
e
a
r
n
i
n
g
Learning
Learning
s
t
e
p
step
step 就變得越小,這其實給了我們一個思路,即我們的
e
t
a
eta
eta 可以跟著梯度下降的回圈次數動態的進行變化:
import numpy as np
# 創建資料
X = np.random.rand(100, 1)
w, b = np.random.randint(1, 10, size = 2)
# 增加噪聲,也被稱為"加鹽"
y = w * X + b + np.random.rand(100, 1)
# 把b作為偏置項,截距對應系數 x_0 = 1, 更新 X
X = np.concatenate([X, np.full(shape = (100, 1),
fill_value = 1)], axis = 1)
# 回圈次數
epoches = 10000
# 學習率
t0, t1 = 5, 1000
# t 是梯度下降的次數,逆時衰減,隨著梯度下降次數增加,學習率變小
def learning_rate_shedule(t):
return t0 / (t + t1)
# 要求解的系數,"瞎蒙的"
theta = np.random.randn(2, 1)
for i in range(epoches):
# 批量梯度下降,X為矩陣,包含所有的資料
g = X.T.dot(X.dot(theta) - y) # 根據公式計算的梯度
eta = learning_rate_shedule(i)
theta = theta - eta * g
print('真實的斜率、截距:', w, b)
print('使用BGD求的斜率、截距:', theta[0], theta[1])

2.1.2 八元一次線性回歸
import numpy as np
# 創建資料
X = np.random.rand(100, 8)
w = np.random.randint(1, 10, size = (8, 1))
b = np.random.randint(1, 10, size = 1)
# 增加噪聲,也被稱為"加鹽"
y = X.dot(w) + b + np.random.rand(100, 1)
# 把b作為偏置項,截距對應系數 x_0 = 1, 更新 X
X = np.concatenate([X, np.full(shape = (100, 1),
fill_value = 1)], axis = 1)
# 回圈次數
epoches = 10000
# 學習率
t0, t1 = 5, 1000
# t 是梯度下降的次數,逆時衰減,隨著梯度下降次數增加,學習率變小
def learning_rate_shedule(t):
return t0 / (t + t1)
# 要求解的系數,"瞎蒙的"
theta = np.random.randn(9, 1)
for i in range(epoches):
# 批量梯度下降,X為矩陣,包含所有的資料
g = X.T.dot(X.dot(theta) - y) # 根據公式計算的梯度
eta = learning_rate_shedule(i)
theta = theta - eta * g
print('真實的斜率、截距:', w, b)
print('使用BGD求的斜率、截距:', theta)

2.2 隨機梯度下降 S G D SGD SGD
2.2.1 一元一次線性回歸
import numpy as np
# 創建資料
X = np.random.rand(100, 1)
w, b = np.random.randint(1, 10, size = 2)
# 增加噪聲,也被稱為"加鹽"
y = w * X + b + np.random.rand(100, 1)
# 把b作為偏置項,截距對應系數 x_0 = 1, 更新 X
X = np.concatenate([X, np.full_like(X, fill_value = 1)], axis = 1)
# 回圈次數
epoches = 100
# 學習率
t0, t1 = 5, 1000
# t 是梯度下降的次數,逆時衰減,隨著梯度下降次數增加,學習率變小
def learning_rate_shedule(t):
return t0 / (t + t1)
theta = np.random.randn(2, 1)
cnt = 0 # 表示訓練的次數
for t in range(epoches):
index = np.arange(100)
np.random.shuffle(index) # 洗牌,打亂順序
# NumPy 花式索引
X = X[index]
y = y[index]
for i in range(100):
X_i = X[[i]]
y_i = y[[i]]
# 根據這一個樣本,進行計算梯度
g = X_i.T.dot(X_i.dot(theta) - y_i)
eta = learning_rate_shedule(cnt)
cnt += 1
theta -= eta * g
print('真實的斜率、截距:', w, b)
print('使用SGD求的斜率、截距:', theta[0], theta[1])

2.2.2 五元一次線性回歸
import numpy as np
# 創建資料
X = np.random.rand(100, 5)
w = np.random.randint(1, 10, size = (5, 1))
b = np.random.randint(1, 10, size = 1)
# 增加噪聲,也被稱為"加鹽"
y = X.dot(w) + b + np.random.rand(100, 1)
# 把b作為偏置項,截距對應系數 x_0 = 1, 更新 X
X = np.concatenate([X, np.full(shape = (100, 1), fill_value = 1)], axis = 1)
# 回圈次數
epoches = 100
# 學習率
t0, t1 = 5, 1000
# t 是梯度下降的次數,逆時衰減,隨著梯度下降次數增加,學習率變小
def learning_rate_shedule(t):
return t0 / (t + t1)
theta = np.random.randn(6, 1)
cnt = 0 # 表示訓練的次數
for t in range(epoches):
index = np.arange(100)
np.random.shuffle(index) # 洗牌,打亂順序
# NumPy 花式索引
X = X[index]
y = y[index]
for i in range(100):
X_i = X[[i]] # 兩個[]:可以進行矩陣運算
y_i = y[[i]]
# 根據這一個樣本,進行計算梯度
g = X_i.T.dot(X_i.dot(theta) - y_i)
eta = learning_rate_shedule(cnt)
cnt += 1
theta -= eta * g
print('真實的斜率、截距:', w, b)
print('使用SGD求的斜率、截距:', theta)

2.3 小批量梯度下降 M B G D MBGD MBGD
2.3.1 一元一次線性回歸
import numpy as np
# 1、創建資料集X,y
X = np.random.rand(100, 1)
w,b = np.random.randint(1, 10,size = 2)
y = w * X + b + np.random.randn(100, 1)
# 2、使用偏置項x_0 = 1,更新X
X = np.c_[X, np.ones((100, 1))]
# 3、定義一個函式來調整學習率
t0, t1 = 5, 500
def learning_rate_schedule(t):
return t0/(t + t1)
# 4、創建超引數輪次、樣本數量、小批量數量
epochs = 100
n = 100
batch_size = 16
num_batches = int(n / batch_size)
# 5、初始化 W0...Wn,標準正太分布創建W
θ = np.random.randn(2, 1)
# 6、多次for回圈實作梯度下降,最終結果收斂
for epoch in range(epochs):
# 在雙層for回圈之間,每個輪次開始分批次迭代之前打亂資料索引順序
index = np.arange(n)
np.random.shuffle(index)
X = X[index]
y = y[index]
for i in range(num_batches):
# 一次取一批資料16個樣本
X_batch = X[i * batch_size : (i + 1) * batch_size]
y_batch = y[i * batch_size : (i + 1) * batch_size]
g = X_batch.T.dot(X_batch.dot(θ) - y_batch)
learning_rate = learning_rate_schedule(epoch * n + i)
θ = θ - learning_rate * g
print('真實斜率和截距是:', w, b)
print('梯度下降計算斜率和截距是:',θ)

2.3.2 三元一次線性回歸
import numpy as np
# 1、創建資料集X,y
X = np.random.rand(100, 3)
w = np.random.randint(1,10,size = (3, 1))
b = np.random.randint(1,10,size = 1)
y = X.dot(w) + b + np.random.randn(100, 1)
# 2、使用偏置項 X_0 = 1,更新X
X = np.c_[X, np.ones((100, 1))]
# 3、定義一個函式來調整學習率
t0, t1 = 5, 500
def learning_rate_schedule(t):
return t0/(t + t1)
# 4、創建超引數輪次、樣本數量、小批量數量
epochs = 10000
n = 100
batch_size = 16
num_batches = int(n / batch_size)
# 5、初始化 W0...Wn,標準正太分布創建W
θ = np.random.randn(4, 1)
# 6、多次for回圈實作梯度下降,最終結果收斂
for epoch in range(epochs):
# 在雙層for回圈之間,每個輪次開始分批次迭代之前打亂資料索引順序
index = np.arange(n)
np.random.shuffle(index)
X = X[index]
y = y[index]
for i in range(num_batches):
# 一次取一批資料16個樣本
X_batch = X[i * batch_size : (i + 1) * batch_size]
y_batch = y[i * batch_size : (i + 1) * batch_size]
g = X_batch.T.dot(X_batch.dot(θ) - y_batch)
learning_rate = learning_rate_schedule(epoch * n + i)
θ = θ - learning_rate * g
print('真實斜率和截距是:', w, b)
print('梯度下降計算斜率和截距是:',θ)

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/423863.html
標籤:AI
上一篇:深度學習C語言——結構體
