有監督學習——梯度下降

zh_jp發表於2023-03-11

1. 梯度下降

梯度下降(Gradient Descent)是計算機計算能力有限的條件下啟用的逐步逼近、迭代求解方法,在理論上不保證下降求得最優解。

e.g. 假設有三維曲面表達函式空間,長(x)、寬(y)軸為子變數,高(z)是因變數,若使用梯度下降法求解因變數最低點的步驟如下:

  1. 任取一點作為起始點。
  2. 檢視當前點向哪個方向移動得到最小的z值,並向該方向移動。
  3. 重複上述步驟,直到無法找到更小的z值,此時認為達到最低點。

受起始點和目標函式的約束,有時該法無法找到全域性最優點,但有著比OLS更快的求解速度,因此被廣泛應用。

根據原理介紹幾個梯度下降求解演演算法概念:

  • 步長(learning rate):每一步梯度下降時向目標方向前行的長度。
  • 假設函式(hypothesis function):由特徵產生目標變數的函式,常用\(h()\)表示。
  • 損失函式(loss function):評估任意引陣列合的函式,常用\(J()\)表示。

損失函式判斷向周圍哪個方向移動的原理是計算損失函式的偏導數向量該向量就是損失函式增長最快的方向,而其反方向則是以最小化損失函式為目標時需要前進的方向。

2. 隨機梯度下降

隨機梯度下降(Stochastic Gradient Descent, SGD),在損失函式計算時不便利所有樣本,只採用單一或小批次樣本的方差和作為損失值。因此,每次迭代計算速度非常快,透過每次隨機選用不同的樣本進行迭代達到對整體資料的擬合。

對比普通梯度下降,隨機梯度下降的主要區別在於:

  • 迭代次數明顯增加,但由於每次計算樣本少,總體時間縮短。
  • 由於樣本資料存在噪聲,每次迭代方向不一定是“正確的”,但由於迭代次數的增加,總體的移動期望任朝著正確方向前進。
  • 能過“不一定正確”的方向越過高點,從而找到最優解。

3. Python中的SGDRegression和SGDClassifier

scikit-learn中提供了隨機梯度下降的線性迴歸器SGDRegressor和線性分類器SGDClassifier,使用它們可學習超大規模樣本(樣本數>\(10^5\)且特徵維度>\(10^5\))。

Python中使用兩者

from sklearn.linear_model import SGDRegressor, SGDClassifier
X = [[0, 0], [2, 1], [5, 4]]    # 樣本特徵
y = [0, 2, 2]                   # 樣本目標分類
reg = SGDRegressor(penalty='l2', max_iter=10000)
reg.fit(X, y)
reg.predict([[4,3]])
# array([1.85046249])

reg.coef_       # 檢視回歸引數
# array([0.30716325, 0.16212611])

reg.intercept_  # 檢視截距
# array([0.13543114])

clf = SGDClassifier(penalty='l2', max_iter=100) # 初始化分類器
clf.fit(X, y)
clf.predict([[4, 3]])   # 預測
# array([2])

兩者最大的不同在於predict()函式的預測結果,SGDClassifier預測的結果一定是訓練資料的目標值之一,SGDRegressor預測值是假設函式直接的計算結果。

而兩者的物件初始化引數類似:

Attribute Introduce
penalty 損失函式懲罰項,取值none l1 l2elasticnet,"elasticnet"是"l1"和"l2"的綜合
loss 損失函式型別,影響訓練速度,取值squared_loss huber epsilon_insensitivesquared_epsilon_insensitive
tol 損失函式變化小於tol時認為獲得最優解
max_iter 最大迭代次數,當迭代陷入抖動,無法滿足tol時只能利用max_iter作為停止迭代條件
shuffle 完成一輪所有樣本迭代後是否洗牌
n_jobs 訓練中可利用的CPU數量
learning_rate 步長型別,取值constant optimalinvscaling,前者為固定步長。後兩者為動態步長有利於在訓練初期跳出區域性解,同時後期避免抖動。
eta0 learning_rate 為 constant 或 invscaling 時的初始步長
fit_intercept 是否有截距,取值TrueFalse

3. 增量學習

增量學習(Incremental Learning)是指一種可以邊讀資料邊訓練的擬合方法。

在scikit-Learn中提供了partial_fit()函式介面,所有支援增量學習的模型都實現了該函式。SGD的增量學習呼叫方法舉例:

from random import randint
import numpy as np
reg2 = SGDRegressor(loss="squared_error", penalty="l1", tol=1e-15)
X = np.linspace(0, 1, 50)  # 50個x值
Y = X/2 + 0.3 + np.random.normal(0, 0.15, len(X))   # 用y=x/2+0.3加隨機數生成樣本
X = X.reshape(-1, 1)

for i in range(10000):
    idx = randint(0, len(Y)-1)  # 隨機選擇一個樣本索引
    reg2.partial_fit(X[idx: idx+10], Y[idx: idx+10])  # 用partial_fit()訓練

print(reg2.coef_)   # 檢視回歸引數
# [0.56874507]
print(reg2.intercept_)  # 檢視截距
# [0.2769033]

檢視模型引數,當前模型應為:

\[y=0.56874507x+0.2769033 \]

與生成樣本時的公式相近。

參考文獻

[1]劉長龍. 從機器學習到深度學習[M]. 1. 電子工業出版社, 2019.3.

相關文章