有监督学习——梯度下降
1. 梯度下降
梯度下降(Gradient Descent)是计算机计算能力有限的条件下启用的逐步逼近、迭代求解方法,在理论上不保证下降求得最优解。
e.g. 假设有三维曲面表达函数空间,长(x)、宽(y)轴为子变量,高(z)是因变量,若使用梯度下降法求解因变量最低点的步骤如下:
- 任取一点作为起始点。
- 查看当前点向哪个方向移动得到最小的z值,并向该方向移动。
- 重复上述步骤,直到无法找到更小的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 l2 或elasticnet ,"elasticnet"是"l1"和"l2"的综合 |
loss | 损失函数类型,影响训练速度,取值squared_loss huber epsilon_insensitive 或squared_epsilon_insensitive |
tol | 损失函数变化小于tol时认为获得最优解 |
max_iter | 最大迭代次数,当迭代陷入抖动,无法满足tol时只能利用max_iter作为停止迭代条件 |
shuffle | 完成一轮所有样本迭代后是否洗牌 |
n_jobs | 训练中可利用的CPU数量 |
learning_rate | 步长类型,取值constant optimal 或invscaling ,前者为固定步长。后两者为动态步长有利于在训练初期跳出局部解,同时后期避免抖动。 |
eta0 | learning_rate 为 constant 或 invscaling 时的初始步长 |
fit_intercept | 是否有截距,取值True 或False |
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]
查看模型参数,当前模型应为:
与生成样本时的公式相近。
参考文献
[1]刘长龙. 从机器学习到深度学习[M]. 1. 电子工业出版社, 2019.3.