深度学习——梯度下降优化方法
一、梯度下降相关介绍:
概述:
梯度下降是结合 本次损失函数的导数(作为梯度) 基于学习率 来更新权重
公式:
W新 = W旧 - 学习率 * 梯度
存在的问题:
1. 遇到平缓区域,梯度下降(权重更新)可能会慢
2.可能会遇到鞍点(梯度为0)
3.可能会遇到 局部最小值
解决思路:
从上述的学习率 或者 梯度入手,进行优化,于是有了:动量法Momentum,自适应学习率AdaGrad,RMSProp,综合衡量ADam
1.梯度下降的优化方法-动量算法Momentum
梯度计算公式:
参数更新公式:
- \(s_t\) 是当前时刻指数加权平均梯度值
- \(s_{t-1}\) 是历史指数加权平均梯度值
- \(g_t\) 是当前时刻的梯度值
- \(\beta\) 是调节权重系数,通常取 0.9 或 0.99
- \(\eta\) 是学习率
- \(w_t\) 是当前时刻模型权重参数
2.梯度下降的优化方法-adaGrad
AdaGrad 通过对不同的参数分量使用不同的学习率,AdaGrad 的学习率总体会逐渐减小。
其计算步骤如下:
- 初始化学习率 \(\eta\)、初始化参数\(w\)、小常数 \(\sigma = 1\mathrm{e}{-10}\)
- 初始化梯度累计变量 \(s = 0\)
- 从训练集中采样 \(m\) 个样本的小批量,计算梯度\(g_t\)
- 累积平方梯度: \(s_t = s_{t-1} + g_t \odot g_t\),\(\odot\) 表示各个分量相乘
- 学习率 \(\eta\) 的计算公式如下:
- 权重参数更新公式如下:
- 重复 3-7 步骤
AdaGrad 缺点是可能会使得学习率过早、过量的降低,导致模型训练后期学习率太小,较难找到最优解。
3.梯度下降的优化方法RMSProp
RMSProp 优化算法是对 AdaGrad 的优化. 最主要的不同是,其使用指数加权平均梯度替换历史梯度的平方和。其计算过程如下:
- 初始化学习率 \(\eta\)、初始化权重参数\(w\)、小常数 \(\sigma = 1\mathrm{e}{-10}\)
- 初始化梯度累计变量 \(s = 0\)
- 从训练集中采样 \(m\) 个样本的小批量,计算梯度 \(g_t\)
- 使用指数加权平均累计历史梯度,\(\odot\) 表示各个分量相乘,公式如下:
- 学习率 \(\eta\) 的计算公式如下:
- 权重参数更新公式如下:
- 重复 3-7 步骤
4.梯度下降的优化方法-Adam
-
Momentum 使用指数加权平均计算当前的梯度值
-
AdaGrad、RMSProp 使用自适应的学习率
-
Adam优化算法(Adaptive Moment Estimation,自适应矩估计)将Momentum 和 RMSProp 算法结合在一起
- 修正梯度:使用梯度的指数加权平均
- 修正学习率:使用梯度平方的指数加权平均
-
原理:Adam 是结合了 Momentum 和 RMSProp 优化算法的优点的自适应学习率算法。它计算了梯度的一阶矩(平均值)和二阶矩(梯度的方差)的自适应估计,从而动态调整学习率。
-
梯度计算公式:
- 权重参数更新公式:
其中,\(m_t\) 是梯度的一阶矩估计,\(s_t\) 是梯度的二阶矩估计,\(\hat{m}_t\)、\(\hat{s}_t\) 偏差校正后的估计。
二、梯度下降方法的代码演示
导包
import torch
import torch.nn as nn
1. 定义函数,演示:梯度下降优化方法 ——> 动量法(Momentum)
def dm01_momentum():
# 1. 初始化权重参数
w = torch.tensor([0,1], requires_grad=True, dtype=torch.float)
# 2. 定义损失函数
criterion = ((w ** 2) / 2.0)
# 3. 创建优化器(函数对象),基于SGD(随机梯度下降),加入参数 momentum,就是动量法
# 参1:(待)优化的参数列表;参2:学习率;参3:动量参数
optimizer = torch.optim.SGD(params=[w], lr=0.01, momentum=0.9) # 细节:momentum=0(默认),只考虑本此梯度
# 4. 计算梯度值:梯度清零+反向传播+参数更新
optimizer.zero_grad()
criterion.sum().backward() # 执行这段代码后,会自动求导,把梯度写到 w 的 grad 里,只算梯度,不改权重
optimizer.step() # 优化器读取已经算好的 w.grad,按照算法公式(SGD / 动量 / Adam 等)直接修改 w 的数值。
print(f'动量法:\nw:{w},w.grad:{w.grad}')
# 5. 重复上述的步骤,第2次 更新权重
# 5.1 定义损失函数
criterion = ((w ** 2) / 2.0)
# 5.2 计算梯度值:梯度清理 + 反向传播 + 参数更新
optimizer.zero_grad()
criterion.sum().backward() # 执行这段代码后,会自动求导,把梯度写到 w 的 grad 里,只算梯度,不改权重
optimizer.step() # 优化器读取已经算好的 w.grad,按照算法公式(SGD / 动量 / Adam 等)直接修改 w 的数值。
# 5.3 打印结果
print(f'动量法:\nw:{w},w.grad:{w.grad}')
2. 定义函数,演示:梯度下降优化方法 ——> AdaGrad自适应学习率
def dm02_adagrad():
# 1. 初始化权重参数
w = torch.tensor([0,1], requires_grad=True, dtype=torch.float)
# 2. 定义损失函数
criterion = ((w ** 2) / 2.0)
# 3. 创建优化器(函数对象),
#思路1:基于SGD(随机梯度下降),加入参数 momentum,就是动量法
# 参1:(待)优化的参数列表;参2:学习率;参3:动量参数
# optimizer = torch.optim.SGD(params=[w], lr=0.01, momentum=0.9) # 细节:momentum=0(默认),只考虑本此梯度
#思路2:基于AdaGrad(自适应学习率),加入参数 momentum,就是动量法
optimizer = torch.optim.Adagrad(params=[w], lr=0.01)
# 4. 计算梯度值:梯度清零+反向传播+参数更新
optimizer.zero_grad()
criterion.sum().backward() # 执行这段代码后,会自动求导,把梯度写到 w 的 grad 里,只算梯度,不改权重
optimizer.step() # 优化器读取已经算好的 w.grad,按照算法公式(SGD / 动量 / Adam 等)直接修改 w 的数值。
print(f'AdaGrad:\nw:{w},w.grad:{w.grad}')
# 5. 重复上述的步骤,第2次 更新权重
# 5.1 定义损失函数
criterion = ((w ** 2) / 2.0)
# 5.2 计算梯度值:梯度清理 + 反向传播 + 参数更新
optimizer.zero_grad()
criterion.sum().backward() # 执行这段代码后,会自动求导,把梯度写到 w 的 grad 里,只算梯度,不改权重
optimizer.step() # 优化器读取已经算好的 w.grad,按照算法公式(SGD / 动量 / Adam 等)直接修改 w 的数值。
# 5.3 打印结果
print(f'AdaGrad:\nw:{w},w.grad:{w.grad}')
3. 定义函数,演示:梯度下降优化方法 ——> RMSProp自适应学习率
def dm03_rmsprop():
# 1. 初始化权重参数
w = torch.tensor([0,1], requires_grad=True, dtype=torch.float)
# 2. 定义损失函数
criterion = ((w ** 2) / 2.0)
# 3. 创建优化器(函数对象),
#思路1:基于SGD(随机梯度下降),加入参数 momentum,就是动量法
# 参1:(待)优化的参数列表;参2:学习率;参3:动量参数
# optimizer = torch.optim.SGD(params=[w], lr=0.01, momentum=0.9) # 细节:momentum=0(默认),只考虑本此梯度
#思路2:基于AdaGrad(自适应学习率),加入参数 momentum,就是动量法
# optimizer = torch.optim.Adagrad(params=[w], lr=0.01)
#思路3:基于RMSProp
optimizer = torch.optim.RMSprop(params=[w], lr=0.01,alpha=0.99)
# 4. 计算梯度值:梯度清零+反向传播+参数更新
optimizer.zero_grad()
criterion.sum().backward() # 执行这段代码后,会自动求导,把梯度写到 w 的 grad 里,只算梯度,不改权重
optimizer.step() # 优化器读取已经算好的 w.grad,按照算法公式(SGD / 动量 / Adam 等)直接修改 w 的数值。
print(f'RMSProp:\nw:{w},w.grad:{w.grad}')
# 5. 重复上述的步骤,第2次 更新权重
# 5.1 定义损失函数
criterion = ((w ** 2) / 2.0)
# 5.2 计算梯度值:梯度清理 + 反向传播 + 参数更新
optimizer.zero_grad()
criterion.sum().backward() # 执行这段代码后,会自动求导,把梯度写到 w 的 grad 里,只算梯度,不改权重
optimizer.step() # 优化器读取已经算好的 w.grad,按照算法公式(SGD / 动量 / Adam 等)直接修改 w 的数值。
# 5.3 打印结果
print(f'RMSProp:\nw:{w},w.grad:{w.grad}')
4. 定义函数,演示:梯度下降优化方法 ——> 自适应矩估计
def dm04_adam():
# 1. 初始化权重参数
w = torch.tensor([0,1], requires_grad=True, dtype=torch.float)
# 2. 定义损失函数
criterion = ((w ** 2) / 2.0)
# 3. 创建优化器(函数对象),
#思路1:基于SGD(随机梯度下降),加入参数 momentum,就是动量法
# 参1:(待)优化的参数列表;参2:学习率;参3:动量参数
# optimizer = torch.optim.SGD(params=[w], lr=0.01, momentum=0.9) # 细节:momentum=0(默认),只考虑本此梯度
#思路2:基于AdaGrad(自适应学习率),加入参数 momentum,就是动量法
# optimizer = torch.optim.Adagrad(params=[w], lr=0.01)
#思路3:基于RMSProp
# optimizer = torch.optim.RMSprop(params=[w], lr=0.01,alpha=0.99)
#思路4:基于Adam
optimizer = torch.optim.Adam(params=[w], lr=0.01,betas=(0.9,0.999)) # betas = (梯度用的衰减系数,学习率用的衰减系数)
# 4. 计算梯度值:梯度清零+反向传播+参数更新
optimizer.zero_grad()
criterion.sum().backward() # 执行这段代码后,会自动求导,把梯度写到 w 的 grad 里,只算梯度,不改权重
optimizer.step() # 优化器读取已经算好的 w.grad,按照算法公式(SGD / 动量 / Adam 等)直接修改 w 的数值。
print(f'RMSProp:\nw:{w},w.grad:{w.grad}')
# 5. 重复上述的步骤,第2次 更新权重
# 5.1 定义损失函数
criterion = ((w ** 2) / 2.0)
# 5.2 计算梯度值:梯度清理 + 反向传播 + 参数更新
optimizer.zero_grad()
criterion.sum().backward() # 执行这段代码后,会自动求导,把梯度写到 w 的 grad 里,只算梯度,不改权重
optimizer.step() # 优化器读取已经算好的 w.grad,按照算法公式(SGD / 动量 / Adam 等)直接修改 w 的数值。
# 5.3 打印结果
print(f'RMSProp:\nw:{w},w.grad:{w.grad}')
5.测试
if __name__ == '__main__':
# dm01_momentum()
# dm02_adagrad()
dm03_rmsprop()
小结
| 优化算法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| SGD | 简单、容易实现。 | 收敛速度较慢,容易震荡,特别是在复杂问题中。 | 用于简单任务,或者当数据特征分布相对稳定时。 |
| Momentum | 可以加速收敛,减少震荡,特别是在高曲率区域。 | 需要手动调整动量超参数,可能会在小步长训练中过度更新。 | 用于非平稳优化问题,尤其是深度学习中的应用。 |
| AdaGrad | 自适应调整学习率,适用于稀疏数据。 | 学习率会在训练过程中逐渐衰减,可能导致早期停滞。 | 适合稀疏数据,如 NLP 或推荐系统中的特征。 |
| RMSProp | 解决了 AdaGrad 学习率过早衰减的问题,适应性强。 | 需要选择合适的超参数,更新可能会过于激进。 | 适用于动态问题、非平稳目标函数,如深度学习训练。 |
| Adam | 结合了 Momentum 和 RMSProp 的优点,适应性强且稳定。 | 需要调节更多的超参数,训练过程中可能会产生较大波动。 | 广泛适用于各种深度学习任务,特别是非平稳和复杂问题。 |
-
简单任务和较小的模型:SGD 或 Momentum
-
复杂任务或有大量数据:Adam 是最常用的选择,因其在大部分任务上都表现优秀
-
需要处理稀疏数据或文本数据:Adagrad 或 RMSProp

浙公网安备 33010602011771号