【机器学习】梯度下降算法详解
梯度下降是数学中的一种优化算法,广泛应用在机器学习和深度学习中来寻找最优解。
1 梯度下降
1.1 什么是梯度下降?
梯度下降是数学中的一种优化算法,广泛应用在机器学习和深度学习中来寻找最优解。
1.2 为什么使用梯度下降
我们使用高斯的正规方程W=(XTX)−1XTyW=(X^TX)^{-1}X^TyW=(XTX)−1XTy 求解损失函数最优解时存在问题,就是损失函数必须是凸函数才行。但是,机器学习的损失函数并非都是凸函数,设置导数为0会得到很多个极值,不能确定唯一解,正规方程还有一个问题,当数据量和特征较多时,矩阵计算量太大.
1.假设损失函数是这样的,利用正规方程求解导数为0会得到很多个极值,不能确定唯一解

所以 正规方程求出最优解并不是机器学习和深度学习常用的手段,梯度下降算法更常用。
1.3 梯度下降的具体步骤

1、Random随机数生成初始W,随机生成一组成正太分布的数值w0,w1,w2....wnw_0,w_1,w_2....w_nw0,w1,w2....wn,这个随机是成正太分布的(高斯说的)
2、求梯度g,梯度代表曲线某点上的切线的斜率,沿着切线往下就相当于沿着坡度最陡峭的方向下降.
3、if g < 0,w变大,if g >0,w变小(目标左边是斜率为负右边为正 )
4、判断是否收敛,如果收敛跳出迭代,如果没有达到收敛,回第2步再次执行2~4步收敛的判断标准是:随着迭代进行查看损失函数Loss的值,变化非常微小甚至不再改变,即认为达到收敛
5.上面第4步也可以固定迭代次数
1.4 梯度下降公式

随机给一个w初始值,然后就不停的修改它,直到达到抛物线最下面附近,比如
w=0.2
w=w-0.01*w为0.2时的梯度(导数) 假设算出来是 0.24
w=w-0.01*w为0.24时的梯度(导数) 假设算出来是 0.33
w=w-0.01*w为0.33时的梯度(导数) 假设算出来是 0.51
w=w-0.01*w为0.51时的梯度(导数) 假设算出来是 0.56
w=w-0.01*w为0.56时的梯度(导数) 假设算出来是 0.58
w=w-0.01*w为0.58时的梯度(导数) 假设算出来是 0.62
就这样一直更新下去,会在真实值附近,我们可以控制更新的次数
关于随机的w在左边和右边问题:
因为导数有正负
如果在左边 导数是负数 减去负数就是加 往右移动
如果在右边 导数是正数 减去正数就是减 往左移动
1.5 学习率
学习率是一个超参数,我们可以自己调整它的大小。但是调整学习率的大小是一个学问,因为学习率大小能够影响梯度下降的幅度。当一个学习率设置的过大时,梯度下降的步幅就会很大,可能原本最优解在原始值的右边,但学习率过大,一下子步幅迈过去了,导致最优解在原始值的左边,然后一直左右横跳,算法无法收敛。学习率设置的过小的话,梯度下降又会过慢,使得寻找最优解时迭代次数增加,算法执行效率变慢。

一般来说,学习率取0.1、0.01、0.001、0.0001是常见的设定数值(之后根据实际情况调整)。一般情况下学习率在整体迭代过程中是不变,但是也可以设置成随着迭代次数增多学习率逐渐变小,因为越靠近山谷我们就可以步子迈小点,可以更精准的走入最低点,同时防止走过。还有一些深度学习的优化算法会自己控制调整学习率这个值
1.6 自己实现梯度下降
1.假设损失函数是只有一个w1w_1w1特征的抛物线:
loss(w1)=(w1−3.5)2−4.5w1+10loss(w_1)=(w_1-3.5)^2-4.5w_1+10loss(w1)=(w1−3.5)2−4.5w1+10

我们的目标就是寻找最低点时,横坐标W的值:
#1.列损失函数 画出函数图像
loss=lambda w_1:(w_1-3.5)**2-4.5*w_1+10
w_1=np.linspace(0,11.5,100)
plt.plot(w_1,loss(w_1))
#2.求这个损失函数的最小值:梯度下降
def cb():
g=lambda w_1:2*(w_1-3.5)-4.5#导函数
t0,t1=1,100
alpha=t0/t1#学习率,设置大和过大会导致震荡或者无法收敛
w_1=np.random.randint(0,10,size=1)[0]#随机初始值
#控制更新次数
for i in range(1000):
alpha=t0/(i+t1)#控制学习率 逐步变小
w_1=w_1-alpha*g(w_1)#梯度下降公式
print("更新后的w_1:",w_1)
cb()
1.7 三种常见的梯度下降算法
批量梯度下降BGD(Batch Gradient Descent)
小批量梯度下降MBGD(Mini-BatchGradient Descent)
随机梯度下降SGD(Stochastic Gradient Descent)。

三种梯度下降有什么不同呢?
-
批量梯度下降:每一次迭代更新梯度的过程中,使用全部的数据集进行计算。优点就是计算的梯度更为准确,缺点也很明显,因为使用整个数据集来更新梯度,所以计算速度会很慢
-
小批量梯度下降:每一次迭代更新梯度的过程中,随机抽取一部分数据集来计算。这种方法在准确性和计算效率之间取得了一个平衡。
-
随机梯度下降:每一次迭代更新梯度的过程中,随机抽取一个数据样本来计算。优点就是收敛速度很快,缺点就是梯度更新不太准确。
1.8 批量梯度下降
原理
批量梯度下降的基本思想是在每个迭代步骤中使用所有训练样本来计算损失函数的梯度,并据此更新模型参数。这使得更新方向更加准确,因为它是基于整个数据集的梯度,而不是像随机梯度下降那样仅基于单个样本。
更新规则
假设我们有一个包含 ( m ) 个训练样本的数据集 {(x(i),y(i))}i=1m\{(x^{(i)}, y^{(i)})\}_{i=1}^{m}{(x(i),y(i))}i=1m,其中 $ x^{(i)} 是输入特征,是输入特征,是输入特征, y^{(i)} $ 是对应的标签。我们的目标是最小化损失函数 $J(\theta) $ 相对于模型参数 $ \theta $ 的值。
损失函数可以定义为:
$ J(\theta) = \frac{1}{2m} \sum_{i=1}^{m} (h_\theta(x^{(i)}) - y{(i)})2 $
其中 $ h_\theta(x^{(i)}) $ 是模型对第 $ i $ 个样本的预测输出。
批量梯度下降的更新规则为:
$ \theta_j := \theta_j - \alpha \frac{1}{m} \sum_{i=1}^{m} (h_\theta(x^{(i)}) - y^{(i)}) \cdot x_j^{(i)} $
对于 $ j = 0, 1, \ldots, n $ (其中 $n $ 是特征的数量),并且 $ \alpha $ 是学习率。
特点
- 准确性:由于使用了所有训练样本,所以得到的梯度是最准确的,这有助于找到全局最小值。
- 计算成本:每次更新都需要遍历整个数据集,因此计算量较大,特别是在数据集很大的情况下。
- 收敛速度:虽然每一步的更新都是准确的,但由于计算成本较高,实际收敛到最小值的速度可能不如其他方法快。
- 内存需求:需要在内存中存储整个数据集,对于大型数据集来说可能成为一个问题。
使用场景
- 小数据集:当数据集较小时,批量梯度下降是一个不错的选择,因为它能保证较好的收敛性和准确性。
- 不需要实时更新:如果模型不需要实时更新,例如在离线训练场景下,批量梯度下降是一个合理的选择。
实现注意事项
- 选择合适的学习率:选择合适的学习率对于快速且稳定的收敛至关重要。如果学习率太小,收敛速度会很慢;如果太大,则可能会导致不收敛。
- 数据预处理:对数据进行标准化或归一化,可以提高批量梯度下降的效率。
- 监控损失函数:定期检查损失函数的变化趋势,确保算法正常工作并朝着正确的方向前进。
1.9 随机梯度下降
随机梯度下降(Stochastic Gradient Descent, SGD)是一种常用的优化算法,在机器学习和深度学习领域中广泛应用。与批量梯度下降(BGD)和小批量梯度下降(MBGD)相比,SGD 每一步更新参数时仅使用单个训练样本,这使得它更加灵活且计算效率更高,特别是在处理大规模数据集时。
基本步骤
-
初始化参数:
- 选择一个初始点作为参数向量 θ\thetaθ的初始值。
-
选择样本:
- 随机选取一个训练样本$ (x^{(i)}, y^{(i)})$。
-
计算梯度:
- 使用所选样本 (x(i),y(i))(x^{(i)}, y^{(i)})(x(i),y(i))来近似计算损失函数 $J(\theta) $的梯度 ∇J(θ)\nabla J(\theta)∇J(θ)。
-
更新参数:
- 根据梯度的方向来更新参数 θ\thetaθ。更新公式为:
θ:=θ−α⋅∇J(θ)\theta := \theta - \alpha \cdot \nabla J(\theta)θ:=θ−α⋅∇J(θ) - 其中 α\alphaα 是学习率,决定了每次迭代时参数更新的步长。
- 根据梯度的方向来更新参数 θ\thetaθ。更新公式为:
-
重复步骤 2 到 4:
- 对所有的训练样本重复此过程,直到完成一个完整的 epoch(即所有样本都被访问过一次)。
-
重复多个 epoch:
- 重复上述过程,直到满足某个停止条件,比如达到最大迭代次数或者梯度足够小。
-
输出结果:
- 输出最小化损失函数后的最优参数 θ∗\theta^*θ∗。
数学公式
假设我们有一个包含 (m) 个样本的数据集 {(x(i),y(i))}i=1m\{(x^{(i)}, y^{(i)})\}_{i=1}^m{(x(i),y(i))}i=1m,其中 x(i)x^{(i)}x(i) 是第 iii 个样本的特征向量,y(i)y^{(i)}y(i) 是对应的标签。对于线性回归问题,损失函数 J(θ)J(\theta)J(θ) 可以定义为均方误差 (Mean Squared Error, MSE):
J(θ)=12(hθ(x(i))−y(i))2J(\theta) = \frac{1}{2}(h_\theta(x^{(i)}) - y^{(i)})^2J(θ)=21(hθ(x(i))−y(i))2
其中 hθ(x(i))=θTx(i)h_\theta(x^{(i)}) = \theta^T x^{(i)}hθ(x(i))=θTx(i)是模型对第 iii个样本的预测值。
梯度 ∇J(θ)\nabla J(\theta)∇J(θ) 对于每个参数 θj\theta_jθj 的偏导数可以表示为:
∂J(θ)∂θj=(hθ(x(i))−y(i))xj(i)\frac{\partial J(\theta)}{\partial \theta_j} = (h_\theta(x^{(i)}) - y^{(i)})x_j^{(i)}∂θj∂J(θ)=(hθ(x(i))−y(i))xj(i)
更新规则
参数 θ\thetaθ 的更新规则为:
θj:=θj−α⋅∂J(θ)∂θj\theta_j := \theta_j - \alpha \cdot \frac{\partial J(\theta)}{\partial \theta_j}θj:=θj−α⋅∂θj∂J(θ)
注意事项
- 学习率 α\alphaα: 需要适当设置,太大会导致算法不收敛,太小则收敛速度慢。
- 随机性: 每次迭代都从训练集中随机选择一个样本,这有助于避免陷入局部最小值。
- 停止条件: 可以是达到预定的最大迭代次数,或者梯度的范数小于某个阈值。
随机梯度下降的一个关键优势在于它能够快速地进行迭代并适应较大的数据集。然而,由于每次只使用一个样本进行更新,梯度估计可能较为嘈杂,这可能导致更新过程中出现较大的波动。在实际应用中,可以通过减少学习率(例如采用学习率衰减策略)来解决这个问题。
API
sklearn.linear_model.SGDRegressor()
功能:梯度下降法线性回归
参数:
loss: 损失函数,默认为 ’squared_error’
fit_intercept: 是否计算偏置, default=True
eta0: float, default=0.01学习率初始值
learning_rate: str, default=’invscaling’
The learning rate schedule:
‘constant’: eta = eta0 学习率为eta0设置的值,保持不变
‘optimal’: eta = 1.0 / (alpha * (t + t0))
‘invscaling’: eta = eta0 / pow(t, power_t)
‘adaptive’: eta = eta0, 学习率由eta0开始,逐步变小
max_iter: int, default=1000 经过训练数据的最大次数(又名epoch)
shuffle=True 每批次是否洗牌
penalty: {‘l2’, ‘l1’, ‘elasticnet’, None}, default=’l2’
要使用的惩罚(又称正则化项)。默认为' l2 ',这是线性SVM模型的标准正则化器。' l1 '和'
elasticnet '可能会给模型(特征选择)带来' l2 '无法实现的稀疏性。当设置为None时,不添加惩罚。
属性:
coef_ 回归后的权重系数
intercept_ 偏置
# 线性回归 加载加利福尼亚住房数据集,进行回归预测
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression, SGDRegressor, Ridge
from sklearn.metrics import mean_squared_error
from sklearn.datasets import fetch_california_housing
# 1)加载数据
housing = fetch_california_housing(data_home="./src")
print(housing)
# 2)划分训练集与测试集
x_train, x_test, y_train, y_test = train_test_split(housing.data, housing.target, random_state=22)
# 3)标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
# 4)线性回归预估器
estimator = SGDRegressor(learning_rate="constant", eta0=0.01, max_iter=1000, penalty="l1",loss="squared_error")
estimator.fit(x_train, y_train)
# 5)得出模型
print("权重系数为:\n", estimator.coef_) #权重系数与特征数一定是同样的个数。
print("偏置为:\n", estimator.intercept_)
# 6)模型评估
y_predict = estimator.predict(x_test)
print("预测的数据集:\n", y_predict)
print("得分:\n",estimator.score(x_test, y_test))
error = mean_squared_error(y_test, y_predict)
print("均方误差为:\n", error)
2.0 小批量梯度下降
小批量梯度下降是一种介于批量梯度下降(BGD)与随机梯度下降(SGD)之间的优化算法,它结合了两者的优点,在机器学习和深度学习中被广泛使用。
原理
小批量梯度下降的基本思想是在每个迭代步骤中使用一小部分(即“小批量”)训练样本来计算损失函数的梯度,并据此更新模型参数。这样做的好处在于能够减少计算资源的需求,同时保持一定程度的梯度准确性。
更新规则
假设我们有一个包含 ( m ) 个训练样本的数据集 {(x(i),y(i))}i=1m\{(x^{(i)}, y^{(i)})\}_{i=1}^{m}{(x(i),y(i))}i=1m,其中 $ x^{(i)} $ 是输入特征,$y^{(i)} $ 是对应的标签。我们将数据集划分为多个小批量,每个小批量包含 ( b ) 个样本,其中 ( b ) 称为批量大小(batch size),通常 ( b ) 远小于 ( m )。
损失函数可以定义为:
$ J(\theta) = \frac{1}{2m} \sum_{i=1}^{m} (h_\theta(x^{(i)}) - y{(i)})2 $
其中 $ h_\theta(x^{(i)}) $ 是模型对第 $ i $ 个样本的预测输出。
小批量梯度下降的更新规则为:
$ \theta_j := \theta_j - \alpha \frac{1}{b} \sum_{i \in B} (h_\theta(x^{(i)}) - y^{(i)}) \cdot x_j^{(i)} $
对于 $ j = 0, 1, \ldots, n $ (其中 $n $是特征的数量),并且 $ \alpha $ 是学习率,$ B $ 表示当前小批量中的样本索引集合。
特点
- 计算效率:相比于批量梯度下降,小批量梯度下降每次更新只需要处理一部分数据,减少了计算成本。
- 梯度估计:相比于随机梯度下降,小批量梯度下降提供了更准确的梯度估计,这有助于更稳定地接近最小值。
- 内存需求:相比批量梯度下降,小批量梯度下降降低了内存需求,但仍然比随机梯度下降要高。
- 收敛速度与稳定性:小批量梯度下降能够在保持较快的收敛速度的同时,维持相对较高的稳定性。
使用场景
- 中等规模数据集:当数据集大小适中时,小批量梯度下降是一个很好的折衷方案,既能够高效处理数据,又能够保持良好的收敛性。
- 在线学习:在数据流式到达的场景下,小批量梯度下降可以有效地处理新到来的数据批次。
- 分布式环境:在分布式计算环境中,小批量梯度下降可以更容易地在多台机器上并行执行。
实现注意事项
- 选择合适的批量大小:批量大小的选择对性能有很大影响。较大的批量可以减少迭代次数,但计算成本增加;较小的批量则相反。
- 选择合适的学习率:选择合适的学习率对于快速且稳定的收敛至关重要。如果学习率太小,收敛速度会很慢;如果太大,则可能会导致不收敛。
- 数据预处理:对数据进行标准化或归一化,可以提高小批量梯度下降的效率。
- 监控损失函数:定期检查损失函数的变化趋势,确保算法正常工作并朝着正确的方向前进。
API
还是使用sklearn.linear_model.SGDRegressor()
只是训练时我们分批次地训练模型,调用partial_fit函数训练会直接更新权重,而不需要调fit从头开始训练。通常情况下,我们会将数据分成多个小批量,然后对每个小批量进行训练。
案例
# 线性回归 加载加利福尼亚住房数据集,进行回归预测
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression, SGDRegressor, Ridge
from sklearn.metrics import mean_squared_error
from sklearn.datasets import fetch_california_housing
# 1)加载数据
housing = fetch_california_housing(data_home="./src")
print(housing)
# 2)划分训练集与测试集
x_train, x_test, y_train, y_test = train_test_split(housing.data, housing.target, random_state=22)
# 3)标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
# 4)线性回归预估器
estimator = SGDRegressor(learning_rate="constant", eta0=0.01, max_iter=1000,shuffle=True, penalty="l1")
# 小批量梯度下降
batch_size = 50 # 批量大小
n_batches = len(x_train) // batch_size # 批次数量
for epoch in range(estimator.max_iter):
indices = np.random.permutation(len(x_train)) # 随机打乱样本顺序
for i in range(n_batches):
start_idx = i * batch_size
end_idx = (i + 1) * batch_size
batch_indices = indices[start_idx:end_idx]
X_batch = x_train[batch_indices]
y_batch = y_train[batch_indices]
estimator.partial_fit(X_batch, y_batch) # 更新模型权重
# 5)得出模型
print("权重系数为:\n", estimator.coef_) #权重系数与特征数一定是同样的个数。
print("偏置为:\n", estimator.intercept_)
# 6)模型评估
y_predict = estimator.predict(x_test)
print("得分:\n",estimator.score(x_test, y_test))
print("预测的数据集:\n", y_predict)
error = mean_squared_error(y_test, y_predict)
print("均方误差为:\n", error)
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)