深度学习-----修改学习率来优化模型的几个方法
在 PyTorch 中,学习率是优化过程中最重要的超参数之一。合适的学习率调整策略能够能够帮助模型更快收敛、避免陷入局部最优解,并最终获得更好的性能。下面详细介绍各类学习率调整方法,包括其原理、适用场景和具体实现:
一、有序调整
这类方法按照预设的固定规则调整学习率,不依赖训练过程中的指标变化,适合在训练前就对学习率衰减趋势有明确规划的场景。
1. 等间隔调整(StepLR
)
- 核心原理:将训练过程划分为等长的阶段,每个阶段结束后按照固定比例衰减学习率。例如每经过
step_size
个 epoch,学习率就乘以衰减因子gamma
。 - 适用场景:适用于训练过程稳定、需要均匀降低学习率的任务,如简单图像分类、线性回归等。
- 优缺点:实现简单、计算高效,但灵活性较低,无法根据任务复杂度动态调整衰减时机。
- 代码示例:
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import StepLR# 定义模型和优化器
model = nn.Linear(10, 2) # 简单线性模型
optimizer = optim.SGD(model.parameters(), lr=0.1) # 初始学习率0.1# 初始化调度器:每3个epoch衰减一次,衰减因子0.1
scheduler = StepLR(optimizer, step_size=3, gamma=0.1)# 模拟10个epoch的训练过程
for epoch in range(10):# 此处省略实际训练步骤(前向传播、计算损失、反向传播、参数更新)print(f'Epoch: {epoch}, 学习率: {scheduler.get_last_lr()[0]}')scheduler.step() # 每个epoch结束后更新学习率
- 输出分析:
- Epoch 0-2:学习率保持初始值 0.1(共 3 个 epoch)。
- Epoch 3-5:第 3 个 epoch 结束后,学习率变为 0.1×0.1=0.01(保持 3 个 epoch)。
- Epoch 6-9:第 6 个 epoch 结束后,学习率变为 0.01×0.1=0.001。
2. 多间隔调整(MultiStepLR
)
- 核心原理:预先指定多个关键 epoch(称为里程碑
milestones
),当训练到达这些 epoch 时,学习率按比例衰减。例如在 epoch 3 和 epoch 7 时将学习率乘以gamma
。 - 适用场景:适合对训练过程有先验认知的任务,例如已知模型在特定 epoch 后容易过拟合,需要针对性衰减学习率。
- 优缺点:比
StepLR
更灵活,可根据任务特点设置非均匀衰减点,但需要手动指定里程碑,对经验要求较高。 - 代码示例:
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import MultiStepLRmodel = nn.Linear(10, 2)
optimizer = optim.SGD(model.parameters(), lr=0.1)# 初始化调度器:在epoch 3和7时衰减,衰减因子0.1
scheduler = MultiStepLR(optimizer, milestones=[3, 7], gamma=0.1)for epoch in range(10):print(f'Epoch: {epoch}, 学习率: {scheduler.get_last_lr()[0]}')scheduler.step()
- 输出分析:
- Epoch 0-2:学习率 0.1(未达第一个里程碑)。
- Epoch 3-6:第 3 个 epoch 结束后,学习率变为 0.1×0.1=0.01(保持到下一个里程碑)。
- Epoch 7-9:第 7 个 epoch 结束后,学习率变为 0.01×0.1=0.001。
3. 指数衰减(ExponentialLR
)
- 核心原理:每个 epoch 都对学习率进行衰减,衰减公式为 lr=初始lr×gammaepoch。即学习率随 epoch 呈指数级下降。
- 适用场景:适合需要学习率快速衰减的任务,例如模型收敛较快、后期需要精细调整参数的场景(如小样本学习)。
- 优缺点:衰减速度快,能快速缩小参数更新幅度,但可能导致学习过早停滞(需谨慎设置
gamma
)。 - 代码示例:
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import ExponentialLRmodel = nn.Linear(10, 2)
optimizer = optim.SGD(model.parameters(), lr=0.1)# 初始化调度器:每个epoch衰减因子0.9
scheduler = ExponentialLR(optimizer, gamma=0.9)for epoch in range(10):print(f'Epoch: {epoch}, 学习率: {scheduler.get_last_lr()[0]:.4f}')scheduler.step()
- 输出分析:
- Epoch 0:学习率 0.1(初始值)。
- Epoch 1:0.1×0.9=0.09。
- Epoch 2:0.09×0.9=0.081。
- 以此类推,每个 epoch 学习率均为上一个的 0.9 倍,呈指数下降。
4. 余弦退火(CosineAnnealingLR
)
- 核心原理:学习率随 epoch 按余弦函数曲线衰减,公式为 \text{lr} = \eta_{\text{min}} + 0.5 \times (\text{初始lr} - \eta_{\text{min}}) \times (1 + \cos(\frac{\text{epoch}}{\text{T_max}} \times \pi)),其中
T_max
为周期,eta_min
为最小学习率。 - 适用场景:适合深度神经网络训练,尤其是需要避免学习率突变的场景(如 ResNet、Transformer 等复杂模型)。余弦曲线的平滑特性可减少参数震荡。
- 优缺点:衰减平滑,有助于模型稳定收敛,但需要手动设置周期
T_max
,对超参数较敏感。 - 代码示例:
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import CosineAnnealingLRmodel = nn.Linear(10, 2)
optimizer = optim.SGD(model.parameters(), lr=0.1)# 初始化调度器:周期5个epoch,最小学习率0.01
scheduler = CosineAnnealingLR(optimizer, T_max=5, eta_min=0.01)for epoch in range(10):print(f'Epoch: {epoch}, 学习率: {scheduler.get_last_lr()[0]:.4f}')scheduler.step()
- 输出分析:
- Epoch 0-4(第一个周期):学习率从 0.1 平滑衰减到 0.01(余弦曲线下降)。
- Epoch 5-9(第二个周期):学习率再次从 0.1 开始,重复第一个周期的衰减过程。
二、自适应调整
这类方法根据训练过程中的指标(如损失、准确率)动态调整学习率,无需预先定义衰减规则,更适合复杂任务。
1. 依训练指标调整(ReduceLROnPlateau
)
- 核心原理:持续监测指定指标(如验证集损失),当指标在
patience
个 epoch 内未改善时,自动降低学习率(乘以factor
)。可设置最小学习率min_lr
避免学习率过低。 - 适用场景:几乎适用于所有任务,尤其是难以预先判断衰减时机的场景(如深度学习、迁移学习)。
- 优缺点:智能化程度高,能根据模型表现动态调整,但需要合理设置
patience
(过小可能过早衰减,过大可能延迟优化)。 - 代码示例:
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import ReduceLROnPlateaumodel = nn.Linear(10, 2)
optimizer = optim.SGD(model.parameters(), lr=0.1)# 初始化调度器:监测损失(mode='min'),容忍2个epoch无改善,衰减因子0.1,最小学习率0.001
scheduler = ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=2, min_lr=0.001)# 模拟损失变化:前3个epoch下降,后续保持不变
losses = [2.0, 1.5, 1.4, 1.4, 1.4, 1.4]for epoch, loss in enumerate(losses):# 此处省略训练步骤(假设已计算出当前epoch的loss)print(f'Epoch: {epoch}, 损失: {loss}, 学习率: {optimizer.param_groups[0]["lr"]}')scheduler.step(loss) # 传入指标(损失)更新学习率
- 输出分析:
- Epoch 0-2:损失持续下降(2.0→1.5→1.4),学习率保持 0.1。
- Epoch 3:损失不变(1.4),未达
patience
(2),学习率仍为 0.1。 - Epoch 4:损失连续 2 个 epoch 不变(触发
patience
),学习率变为 0.1×0.1=0.01。 - 若后续损失仍不变,学习率会继续衰减,直至达到
min_lr
(0.001)。
三、自定义调整
通过自定义函数灵活控制学习率变化,满足特殊场景需求。
1. 自定义 lambda
函数调整(LambdaLR
)
- 核心原理:通过
lambda
函数定义学习率的缩放因子(输入为 epoch,输出为缩放系数),实际学习率为初始lr × 缩放系数
。 - 适用场景:需要高度定制化学习率策略的场景,例如分阶段线性衰减、前期冻结学习率后期衰减等。
- 优缺点:灵活性极高,可实现任意复杂的衰减规则,但需要手动设计
lambda
函数,对用户经验要求高。 - 代码示例:
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import LambdaLRmodel = nn.Linear(10, 2)
optimizer = optim.SGD(model.parameters(), lr=0.1)# 自定义lambda函数:前5个epoch保持学习率,之后线性衰减至0
lambda_func = lambda epoch: 1.0 if epoch < 5 else (1.0 - 0.1*(epoch-5))# 初始化调度器
scheduler = LambdaLR(optimizer, lr_lambda=lambda_func)for epoch in range(10):print(f'Epoch: {epoch}, 学习率: {scheduler.get_last_lr()[0]:.4f}')scheduler.step()
- 输出分析:
- Epoch 0-4:缩放系数为 1.0,学习率保持 0.1×1.0=0.1。
- Epoch 5:缩放系数为 1.0−0.1×0=1.0 → 学习率 0.1。
- Epoch 6:缩放系数为 1.0−0.1×1=0.9 → 学习率 0.1×0.9=0.09。
- 以此类推,每个 epoch 缩放系数递减 0.1,学习率线性下降。
四、其他实用方法
1. 循环学习率(CyclicLR
)
- 核心原理:学习率在预设区间(
base_lr
到max_lr
)内周期性变化,常见策略包括:triangular
:学习率先线性上升到max_lr
,再线性下降到base_lr
。triangular2
:与triangular
类似,但每次循环后最大学习率减半。exp_range
:学习率按指数规律在区间内循环。
- 适用场景:适合难以确定最佳学习率的任务,通过循环探索不同学习率,帮助模型跳出局部最优(如深度学习中的特征学习)。
- 代码示例:
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import CyclicLRmodel = nn.Linear(10, 2)
optimizer = optim.SGD(model.parameters(), lr=0.01)# 初始化调度器:基础学习率0.001,最大学习率0.1,上升阶段5个batch,三角形策略
scheduler = CyclicLR(optimizer, base_lr=0.001, max_lr=0.1, step_size_up=5, mode='triangular')# 模拟训练:每个epoch包含10个batch(实际以batch为单位更新学习率)
for epoch in range(2): # 2个epochfor batch in range(10): # 10个batch# 省略训练步骤print(f'Epoch: {epoch}, Batch: {batch}, 学习率: {scheduler.get_last_lr()[0]:.4f}')scheduler.step() # 每个batch后更新学习率
- 输出分析:
- Batch 0-4(上升阶段):学习率从 0.001 线性增加到 0.1。
- Batch 5-9(下降阶段):学习率从 0.1 线性下降到 0.001,完成一个循环。
2. 预热学习率(LinearLR
,PyTorch 2.0+)
- 核心原理:训练初期(
total_iters
个 epoch 内),学习率从start_factor × 初始lr
线性增加到初始学习率,之后保持不变。 - 适用场景:适合大规模模型(如 Transformer)或使用大学习率的场景,避免初始阶段参数剧烈震荡导致模型不稳定。
- 代码示例:
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import LinearLRmodel = nn.Linear(10, 2)
optimizer = optim.SGD(model.parameters(), lr=0.1)# 初始化调度器:前5个epoch预热,起始因子0.1(初始学习率0.01),逐步增加到0.1
scheduler = LinearLR(optimizer, start_factor=0.1, total_iters=5)for epoch in range(10):print(f'Epoch: {epoch}, 学习率: {scheduler.get_last_lr()[0]:.4f}')scheduler.step()
- 输出分析:
- Epoch 0:学习率 0.1×0.1=0.01(起始值)。
- Epoch 1:学习率 0.1×(0.1+0.18)=0.028(线性增加,每次增加 0.1×(1−0.1)/5=0.018)。
- Epoch 4:学习率达到 0.1,后续保持不变。
总结
学习率调整的核心目标是平衡模型收敛速度和优化效果:
- 简单任务(如线性回归)可选择
StepLR
或MultiStepLR
。 - 复杂模型(如 ResNet)推荐
CosineAnnealingLR
或ReduceLROnPlateau
。 - 探索性训练可尝试
CyclicLR
,大规模模型建议搭配LinearLR
预热。