深度学习——学习率衰减方法
一、学习率衰减的基本思想
学习率衰减(Learning Rate Scheduling)是在训练过程中逐步降低学习率的策略。训练初期使用较大学习率实现快速收敛,训练后期减小学习率使模型在最优解附近精细调整,避免震荡。
二、等间隔学习率衰减(StepLR)
策略说明
每隔固定数量的 epoch,学习率乘以一个衰减系数。衰减节奏均匀,简单直观。
公式
\[lr_{epoch} = lr_{initial} \times \gamma^{\lfloor \frac{epoch}{step\_size} \rfloor}
\]
其中:
- \(lr_{initial}\):初始学习率
- \(\gamma\):衰减系数
- \(step\_size\):衰减间隔(多少个 epoch 衰减一次)
- \(\lfloor \cdot \rfloor\):向下取整
三、指定间隔学习率衰减(MultiStepLR)
策略说明
在预先指定的几个特定 epoch 节点进行学习率衰减,而非固定间隔。可根据任务难度灵活设置衰减时机。
公式
\[lr_{epoch} = lr_{initial} \times \gamma^{count}
\]
其中 \(count\) 是当前 epoch 之前已经跨越的 milestone(指定节点)数量。
四、指数学习率衰减(ExponentialLR)
策略说明
每一个 epoch 都对学习率进行一次指数衰减,学习率呈平滑的指数下降曲线,没有阶梯式突变。
公式
\[lr_{epoch} = lr_{initial} \times \gamma^{epoch}
\]
其中:
- \(lr_{initial}\):初始学习率
- \(\gamma\):每轮的衰减底数
- \(epoch\):当前轮数
五、三种策略对比
| 对比维度 | StepLR(等间隔) | MultiStepLR(指定间隔) | ExponentialLR(指数) |
|---|---|---|---|
| 衰减时机 | 固定间隔 | 自定义节点 | 每轮都衰减 |
| 衰减曲线 | 阶梯式下降 | 阶梯式下降(不均匀) | 平滑指数下降 |
| 灵活度 | 中等 | 最高 | 较低 |
| 调参难度 | 简单 | 较难 | 中等 |
六、代码实现
导包
import torch
from torch import optim
import matplotlib
1. 定义函数,演示:等间隔学习率衰减
def dm01():
# 1. 定义变量,记录初始的学习率,训练轮数,每轮训练的批次数
lr,epochs,iteration = 0.1,200,10
# 2. 创建数据集,y_true,x,w
# 真实值
y_true = torch.tensor([0])
# 输入特征
x = torch.tensor(data=[1.0],dtype=torch.float32)
# 权重参数w,需要自动微分
w = torch.tensor([1.0],dtype=torch.float32,requires_grad=True)
# 3. 创建优化器对象,动量法:加速模型收敛,减少震荡
# 参1:待优化的参数;参2:学习率;参3:动量系数
optimizer = torch.optim.SGD([w],lr=lr,momentum=0.9)
# 4. 创建学习率衰减对象
# 思路1:创建等间隔学习率衰减对象.
# 参1:优化器对象,参2:间隔的轮数(多少轮衰减一次学习率);参3:学习率衰减对象
scheduler = optim.lr_scheduler.StepLR(optimizer,step_size=50,gamma=0.5)
# 5.创建两个列表,分别表示:训练的轮数,每轮训练用的学习率
# epoch_list = [1,2,3,...,50,51,52,...,...,200]
# lr_list = [0.1,0.1,0.1,...,0.05,.....,0.025,...,0.0125]
lr_list,epoch_list = [],[]
# 6. 循环遍历训练轮数,进行具体的训练
for epoch in range(epochs): # epoch: 0~199
# 7. 获取当前轮数和学习率,并保存到列表中
epoch_list.append(epoch)
lr_list.append(scheduler.get_last_lr()) # 获取最后的lr
# 8. 循环遍历,每轮每批次进行训练
for batch in range(iteration):
# 9. 先计算预测值,然后基于损失函数计算损失
y_pred = w * x
# 10. 计算损失
loss = (y_pred - y_true).pow(2)
# 11. 梯度清零 + 反向传播 + 优化器更新参数
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 12.更新学习率.
scheduler.step()
# 13. 打印结果
print(f'lr_list:{lr_list},epoch_list:{epoch_list}')
# 14. 可视化
# x轴:训练的轮数,y轴:每轮训练用的学习率
plt.plot(epoch_list,lr_list)
plt.xlabel('Epoch')
plt.ylabel('Learning Rate')
plt.legend(['lr'])
plt.show()
2. 定义函数,演示:指定间隔学习率衰减
def dm02():
# 1. 定义变量,记录初始的学习率,训练轮数,每轮训练的批次数
lr,epochs,iteration = 0.1,200,10
# 2. 创建数据集,y_true,x,w
# 真实值
y_true = torch.tensor([0])
# 输入特征
x = torch.tensor(data=[1.0],dtype=torch.float32)
# 权重参数w,需要自动微分
w = torch.tensor([1.0],dtype=torch.float32,requires_grad=True)
# 3. 创建优化器对象,动量法:加速模型收敛,减少震荡
# 参1:待优化的参数;参2:学习率;参3:动量系数
optimizer = torch.optim.SGD([w],lr=lr,momentum=0.9)
# 4. 创建学习率衰减对象
# 思路1:创建等间隔学习率衰减对象.
# 参1:优化器对象,参2:间隔的轮数(多少轮衰减一次学习率);参3:学习率衰减对象
# scheduler = optim.lr_scheduler.StepLR(optimizer,step_size=50,gamma=0.5)
# 思路2:创建指定间隔学习率衰减对象.
# 定义变量,记录要修改学习率的轮数
milestones = [50,125,160]
# 参1:优化器对象,参2:间隔的轮数(多少轮衰减一次学习率);参3:学习率衰减对象
scheduler = optim.lr_scheduler.MultiStepLR(optimizer,milestones = milestones,gamma=0.5)
# 5.创建两个列表,分别表示:训练的轮数,每轮训练用的学习率
# epoch_list = [1,2,3,...,50,51,52,...,...,200]
# lr_list = [0.1,0.1,0.1,...,0.05,.....,0.025,...,0.0125]
lr_list,epoch_list = [],[]
# 6. 循环遍历训练轮数,进行具体的训练
for epoch in range(epochs): # epoch: 0~199
# 7. 获取当前轮数和学习率,并保存到列表中
epoch_list.append(epoch)
lr_list.append(scheduler.get_last_lr()) # 获取最后的lr
# 8. 循环遍历,每轮每批次进行训练
for batch in range(iteration):
# 9. 先计算预测值,然后基于损失函数计算损失
y_pred = w * x
# 10. 计算损失
loss = (y_pred - y_true).pow(2)
# 11. 梯度清零 + 反向传播 + 优化器更新参数
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 12.更新学习率.
scheduler.step()
# 13. 打印结果
print(f'lr_list:{lr_list},epoch_list:{epoch_list}')
# 14. 可视化
# x轴:训练的轮数,y轴:每轮训练用的学习率
plt.plot(epoch_list,lr_list)
plt.xlabel('Epoch')
plt.ylabel('Learning Rate')
plt.legend(['lr'])
plt.show()
3.定义函数,演示:创建指数间隔衰减
def dm03():
# 1. 定义变量,记录初始的学习率,训练轮数,每轮训练的批次数
lr,epochs,iteration = 0.1,200,10
# 2. 创建数据集,y_true,x,w
# 真实值
y_true = torch.tensor([0])
# 输入特征
x = torch.tensor(data=[1.0],dtype=torch.float32)
# 权重参数w,需要自动微分
w = torch.tensor([1.0],dtype=torch.float32,requires_grad=True)
# 3. 创建优化器对象,动量法:加速模型收敛,减少震荡
# 参1:待优化的参数;参2:学习率;参3:动量系数
optimizer = torch.optim.SGD([w],lr=lr,momentum=0.9)
# 4. 创建学习率衰减对象
# 思路3:创建指数间隔衰减对象
scheduler = optim.lr_scheduler.ExponentialLR(optimizer,gamma=0.95)
# 5.创建两个列表,分别表示:训练的轮数,每轮训练用的学习率
# epoch_list = [1,2,3,...,50,51,52,...,...,200]
# lr_list = [0.1,0.1,0.1,...,0.05,.....,0.025,...,0.0125]
lr_list,epoch_list = [],[]
# 6. 循环遍历训练轮数,进行具体的训练
for epoch in range(epochs): # epoch: 0~199
# 7. 获取当前轮数和学习率,并保存到列表中
epoch_list.append(epoch)
lr_list.append(scheduler.get_last_lr()) # 获取最后的lr
# 8. 循环遍历,每轮每批次进行训练
for batch in range(iteration):
# 9. 先计算预测值,然后基于损失函数计算损失
y_pred = w * x
# 10. 计算损失
loss = (y_pred - y_true).pow(2)
# 11. 梯度清零 + 反向传播 + 优化器更新参数
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 12.更新学习率.
scheduler.step()
# 13. 打印结果
print(f'lr_list:{lr_list},epoch_list:{epoch_list}')
# 14. 可视化
# x轴:训练的轮数,y轴:每轮训练用的学习率
plt.plot(epoch_list,lr_list)
plt.xlabel('Epoch')
plt.ylabel('Learning Rate')
plt.legend(['lr'])
plt.show()
4.测试
dm01()
dm02()
dm03()

浙公网安备 33010602011771号