机器学习:随机梯度下降法(线性回归中的应用)
一、指導(dǎo)思想
# 只針對線性回歸中的使用
算法的最優(yōu)模型的功能:預(yù)測新的樣本對應(yīng)的值;
什么是最優(yōu)的模型:能最大程度的擬合住數(shù)據(jù)集中的樣本數(shù)據(jù);
怎么才算最大程度的擬合:讓數(shù)據(jù)集中的所有樣本點,在特征空間中距離線性模型的距離的和最小;(以線性模型為例說明)
怎么得到最優(yōu)模型:求出最優(yōu)模型對應(yīng)的參數(shù);
怎么求解最優(yōu)模型的參數(shù):通過數(shù)學(xué)方法,得到目標函數(shù)(此函數(shù)計算數(shù)據(jù)集中的所有樣本點,在特征空間中到該線性模型的距離,也就是損失函數(shù)),通過批量梯度下降法和隨機梯度下降法對目標函數(shù)進行優(yōu)化,得到目標函數(shù)最小值時對應(yīng)的參數(shù);
梯度下降法的目的:求解最優(yōu)模型對應(yīng)的參數(shù);(并不是為了求目標函數(shù)的最小值,這一點有助于理解隨機梯度下降法)
二、批量梯度下降法基礎(chǔ)
1)批量梯度下降法的特點
運算量大:批量梯度下降法中的每一項計算:,要計算所有樣本(共 m 個);
批量梯度下降法的梯度是損失函數(shù)減小最快的方向,也就是說,對應(yīng)相同的 theta 變化量,損失函數(shù)在梯度方向上的變化量最大;
2)批量梯度下降法的思路
思路:計算損失函數(shù)的梯度,按梯度的方向,逐步減小損失函數(shù)的變量 theta,對應(yīng)的損失函數(shù)也不斷減小,直到損失函數(shù)的的變化量滿足精度要求;
梯度計算:變形公式如下
梯度是優(yōu)化的方向,損失函數(shù)的變量 theta 的變化量 = 學(xué)習(xí)率 X 當前梯度值
三、隨機梯度下降法(Batch Gradient Descent)
1)基礎(chǔ)理解
思路:隨機抽取 n (一般 n = 總樣本數(shù) / 3)個樣本,在每個樣本的梯度方向上逐步優(yōu)化(每隨機抽取一個樣本就對 theta 做一次遞減優(yōu)化)變量 theta;
分析:批量梯度下降法的優(yōu)化,是整體數(shù)據(jù)集的梯度方向逐步循環(huán)遞減變量 theta ,隨機梯度下降法,是數(shù)據(jù)集中的一個隨機的樣本的梯度方向,優(yōu)化變量 theta;
特點一:直接優(yōu)化變量 theta,而不需要計算 theta 對應(yīng)的目標函數(shù)值;
特點二:不是按整體數(shù)據(jù)集的梯度方向優(yōu)化,而是按隨機抽取的某個樣本的梯度方向進行優(yōu)化;
2)優(yōu)化方向的公式
新的搜索方向計算公式(也即是優(yōu)化的方向):;
此處稱為搜索方向,而不是梯度的計算公式,因為此公式已經(jīng)不是梯度公式,而表示優(yōu)化損失函數(shù)的方向;
隨機梯度下降法的搜索路徑:
特點:
每一次搜索的方向,不能保證是損失函數(shù)減小的方向;
每一次搜索的方向,不能保證是損失函數(shù)減小最快的方向;
其優(yōu)化方向具有不可預(yù)知性;
意義:
實驗結(jié)論表明,即使隨機梯度下降法的優(yōu)化方向具有不可預(yù)知性,通過此方法依然可以差不多來到損失函數(shù)最小值的附近,雖然不像批量梯度下降法那樣,一定可以來到損失函數(shù)最小值位置,但是,如果樣本數(shù)量很大時,有時可以用一定的模型精度,換取優(yōu)化模型所用的時間;
實現(xiàn)技巧:確定學(xué)習(xí)率(η:eta)的取值,很重要;
原因:在隨機梯度下降法優(yōu)化損失函數(shù)的過程中,如果η 一直取固定值,可能會出現(xiàn),已經(jīng)優(yōu)化到損失函數(shù)最小值位置了,但由于隨機的過程不夠好,η 又是各固定值,導(dǎo)致優(yōu)化時慢慢的又跳出最小值位置;
方案:優(yōu)化過程中讓η 逐漸遞減(隨著梯度下降法循環(huán)次數(shù)的增加,η 值越來越小);
3)η 的確定過程
一:如果 η = 1 / i_iters;(i_iters:當前循環(huán)次數(shù))
問題:隨著循環(huán)次數(shù)(i_iters)的增加,η 的變化率差別太大;
二:如果 η = 1 / (i_iters + b);(b:為常量)
解決了η 的變化率差異過大
再次變形:η = a / (i_iters + b);(a、b:為常量)
分子改為 a ,增加η 取值的靈活度;
a、b:為隨機梯度下降法的超參數(shù);
本次學(xué)習(xí)不對 a、b 調(diào)參,選用經(jīng)驗上比較適合的值:a = 5、b = 50;
學(xué)習(xí)率的特點
# 學(xué)習(xí)率隨著循環(huán)次數(shù)的增加,逐漸遞減;
# 這種逐漸遞減的思想,是模擬在搜索領(lǐng)域的重要思路:模擬退火思想;
# 模擬退火思想:在退火過程中的冷卻函數(shù),溫度與冷卻時間的關(guān)系;
一般根據(jù)模擬退火思想,學(xué)習(xí)率還可以表示:η = t0 / (i_iters + t1)
4)循環(huán)次數(shù)的確定
原則
將每個樣本都隨機抽取到;
將每個樣本至少抽取 n 次,也就是總的循環(huán)次數(shù)一般為:len(X_b) * n;
具體操作
將變形后的數(shù)據(jù)集 X_b 的 index 做隨機亂序處理,得到新的數(shù)據(jù)集 X_b_new ;
根據(jù)亂序后的 index 逐個抽取 X_b_new 中的樣本,循環(huán)n 遍;
四、實現(xiàn)隨機梯度下降法
優(yōu)化方向:,結(jié)果是一個列向量;
# array . dot(m) == array . m
eta 取值:η = a/ (i_iters + b)
優(yōu)化結(jié)束條件
批量梯度下降法:1)達到設(shè)定的循環(huán)次數(shù);2)找到損失函數(shù)的最小值
隨機梯度下降法:達到設(shè)定的循環(huán)次數(shù)
隨機梯度下降法中不能使用精度來結(jié)束優(yōu)化:因為隨機梯度下降法的優(yōu)化方向,不一定全都是損失函數(shù)減小的方向;
1)代碼實現(xiàn)隨機梯度下降法
模擬數(shù)據(jù)
import numpy as np import matplotlib.pyplot as plt m = 100000 x = np.random.normal(size=m) X = x.reshape(-1, 1) y = 4. * x + 3. + np.random.normal(0, 3, size=m)
批量梯度下降法
def J(theta, X_b, y):
try:
return np.sum((y - X_b.dot(theta)) ** 2) / len(y)
except:
return float('inf')
def dJ(theta, X_b, y):
return X_b.T.dot(X_b.dot(theta) - y) * 2. / len(y)
def gradient_descent(X_b, y, initial_theta, eta, n_iters=10**4, epsilon=10**-8):
theta = initial_theta
cur_iter = 0
while cur_iter < n_iters:
gradient = dJ(theta, X_b, y)
last_theta = theta
theta = theta - eta * gradient
if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):
break
cur_iter += 1
return theta
# cur_iter:循環(huán)次數(shù)
# initial_theta:theta的初始化值
%%time X_b = np.hstack([np.ones((len(X), 1)), X]) initial_theta = np.zeros(X_b.shape[1]) eta = 0.01 theta = gradient_descent(X_b, y, initial_theta, eta) # 輸出:Wall time: 898 ms
theta # 輸出:array([3.00280663, 3.9936598 ])
隨機梯度下降法
1) 通過每一次隨機抽取的樣本,計算 theta 的優(yōu)化方向def dJ_sgd(theta, X_b_i, y_i):
return X_b_i.T.dot(X_b_i.dot(theta) - y_i) * 2
# X_b_i:是 X_b 中的一行數(shù)據(jù),也就是一個隨機樣本,不在是全部的數(shù)據(jù)集
# y_i:對應(yīng)的隨機抽取的樣本的真值
2) 隨機優(yōu)化過程
def sgd(X_b, y, initial_theta, n_iters):
# 計算學(xué)習(xí)率 eta
t0 = 5
t1 = 50
# 定義求解學(xué)習(xí)率的函數(shù)
def learning_rate(t):
return t0 / (t + t1)
theta = initial_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 - learning_rate(cur_iter) * gradient
return theta
# 此處的形參中不需要設(shè)置 eta 值了,eta 值隨著循環(huán)的進行,在函數(shù)內(nèi)部求取
# cur_iter:當前循環(huán)次數(shù)
# rand_i:從 [0, len(X_b)) 中隨機抽取的一個數(shù)
# gradient:一次循環(huán)中,隨機樣本的優(yōu)化方向
# learning_rate(cur_iter) * gradient:一次循環(huán)的 theta 的變化量
3)給初始化數(shù)值,預(yù)測數(shù)據(jù) %%time X_b = np.hstack([np.ones((len(X), 1)), X]) initial_theta = np.zeros(X_b.shape[1]) theta = sgd(X_b, y, initial_theta, n_iters=len(X_b)//3) # 輸出:Wall time: 287 ms
4)查看最終優(yōu)化結(jié)果 theta # 輸出:array([2.9648937 , 3.94467405])
2)封裝與調(diào)用自己的代碼
封裝:已規(guī)范循環(huán)次數(shù)(代碼中的紅色字樣)
1 def fit_sgd(self, X_train, y_train, n_iters=5, t0=5, t1=50): 2 """根據(jù)訓(xùn)練數(shù)據(jù)集X_train, y_train, 使用梯度下降法訓(xùn)練Linear Regression模型""" 3 assert X_train.shape[0] == y_train.shape[0], 4 "the size of X_train must be equal to the size of y_train" 5 assert n_iters >= 1 6 7 def dJ_sgd(theta, X_b_i, y_i): 8 return X_b_i * (X_b_i.dot(theta) - y_i) * 2. 9 10 def sgd(X_b, y, initial_theta, n_iters, t0=5, t1=50): 11 12 def learning_rate(t): 13 return t0 / (t + t1) 14 15 theta = initial_theta 16 m = len(X_b) 17 18 for cur_iter in range(n_iters): 19 indexes = np.random.permutation(m) 20 X_b_new = X_b[indexes] 21 y_new = y[indexes] 22 for i in range(m): 23 gradient = dJ_sgd(theta, X_b_new[i], y_new[i]) 24 theta = theta - learning_rate(cur_iter * m + i) * gradient 25 26 return theta 27 28 X_b = np.hstack([np.ones((len(X_train), 1)), X_train]) 29 initial_theta = np.random.randn(X_b.shape[1]) 30 self._theta = sgd(X_b, y_train, initial_theta, n_iters, t0, t1) 31 32 self.intercept_ = self._theta[0] 33 self.coef_ = self._theta[1:] 34 35 return self
# n_iters:對所有數(shù)據(jù)集循環(huán)的遍數(shù);
調(diào)用自己封裝的代碼
獲取原始數(shù)據(jù)
import numpy as np import matplotlib.pyplot as plt from sklearn import datasets boston = datasets.load_boston() X = boston.data y = boston.target X = X[y < 50.0] y = y[y < 50.0]
數(shù)據(jù)分割
from ALG.data_split import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, seed=666)
數(shù)據(jù)歸一化
from sklearn.preprocessing import StandardScaler standardScaler = StandardScaler() standardScaler.fit(X_train) X_train_standard = standardScaler.transform(X_train) X_test_standard = standardScaler.transform(X_test)
#數(shù)據(jù)歸一化,主要是將訓(xùn)練數(shù)據(jù)集(X_train)和測試數(shù)據(jù)集(X_test)歸一化;
使用線性回歸算法:LinearRegression
from LR.LinearRegression import LinearRegression
lin_reg = LinearRegression()
%time lin_reg.fit_sgd(X_train_standard, y_train, n_iters=2)
lin_reg.score(X_test_standard, y_test)
# 輸出:Wall time: 10 ms
0.7865171620468298
# 問題:通過score()函數(shù)得到的 R^2 值,也就是準確度過小
# 原因:對所有的 X_train_standard 循環(huán)優(yōu)化的遍數(shù)太少:n_iters=2
循環(huán)遍數(shù)改為 50:n_iters=50
%time lin_reg.fit_sgd(X_train_standard, y_train, n_iters=50)
lin_reg.score(X_test_standard, y_test)
# 輸出:Wall time: 143 ms
0.8085728716573835
循環(huán)遍數(shù)改為 100:n_iters = 100
%time lin_reg.fit_sgd(X_train_standard, y_train, n_iters=100)
lin_reg.score(X_test_standard, y_test)
# 輸出:Wall time: 502 ms
0.8125954368325295
總結(jié):隨著循環(huán)遍數(shù)的增加,模型的準確度也隨著增加;
3)調(diào)用 scikit-learn 中的算法模型
SGDRegressor:該算法雖是名為隨機梯度下降法的回歸器,但其只能解決線性模型,因為,其被封裝在了 linear_model 線性回歸模塊中;
學(xué)習(xí)scikit-learn中的算法的過程:掉包 - 構(gòu)建實例對象 - 擬合 - 驗證訓(xùn)練模型的效果(查看準確度)
實現(xiàn)過程:前期的數(shù)據(jù)處理與步驟(2)相同
from sklearn.linear_model import SGDRegressor
sgd_reg = SGDRegressor()
%time sgd_reg.fit(X_train_standard, y_train)
sgd_reg.score(X_test_standard, y_test)
# 輸出:Wall time: 16 ms
0.8065416815240762
# 準確度為0.8065 左右,此時循環(huán)遍數(shù)使用默認的 5 遍:max_iter = 5
修改循環(huán)遍數(shù):max_iter = 100
sgd_reg = SGDRegressor(max_iter=100)
%time sgd_reg.fit(X_train_standard, y_train)
sgd_reg.score(X_test_standard, y_test)
# 輸出:Wall time: 8 ms
0.813372455938393
4)總結(jié)
與自己寫的算法相比,scikit-learn中的算法的實現(xiàn)過程更加復(fù)雜,性能更優(yōu):
通過計算時間就可以看出:n_iters=100時,自己的算法需要 502ms,scikit-learn中的算法需要 8ms;
自己所學(xué)的封裝好的算法,只是為了幫助理解算法的原來,而scikit-learn中使用了很多優(yōu)化的方案
總結(jié)
以上是生活随笔為你收集整理的机器学习:随机梯度下降法(线性回归中的应用)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SAP WebClient UI和bus
- 下一篇: IxChariot:网络吞吐量及延迟)测