在模型训练过程中,学习率(learning rate)可能是最关键的超级参数之一。它决定了每次参数更新的步长大小,直接影响着模型收敛的速度和最终性能。PyTorch作为当前最流行的深度学习框架之一,提供了丰富而灵活的学习率调整机制。
新手常见误区:很多初学者会固定使用一个学习率从头训练到尾,这往往导致模型要么收敛缓慢,要么在后期震荡无法达到最优。
PyTorch的torch.optim.lr_scheduler模块包含了多种学习率调整策略,每种策略都有其适用的场景和背后的数学原理。理解这些策略的工作原理,能够帮助我们在不同训练阶段动态调整学习率,显著提升模型性能。
StepLR是最简单的分段常数调度器。它按照固定的步长(step_size)将学习率乘以gamma系数:
python复制scheduler = torch.optim.lr_scheduler.StepLR(optimizer,
step_size=30,
gamma=0.1)
这种调度器适合那些我们知道在特定epoch后需要降低学习率的场景。例如在训练ResNet时,通常在30和60个epoch后将学习率降低10倍。
MultiStepLR是StepLR的扩展版本,允许在多个不同的epoch点调整学习率:
python复制scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer,
milestones=[30,80],
gamma=0.1)
ExponentialLR实现了学习率的指数衰减:
python复制scheduler = torch.optim.lr_scheduler.ExponentialLR(optimizer,
gamma=0.95)
这种调度器会使学习率随着训练过程平滑下降,适用于那些我们希望学习率持续缓慢降低的场景。
ReduceLROnPlateau是最实用的自适应调度器之一。它不是在固定epoch调整学习率,而是监控某个指标(如验证集loss),当指标停止改善时降低学习率:
python复制scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer,
mode='min',
factor=0.1,
patience=10)
关键参数解析:
我在实际项目中发现,配合Early Stopping使用ReduceLROnPlateau可以节省大量训练时间,通常在验证loss停滞2-3次降低后,模型就已经达到了最佳性能。
CosineAnnealingLR采用余弦退火策略,让学习率像余弦函数一样周期性变化:
python复制scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer,
T_max=50)
这种调度器在图像分类任务中表现优异,特别是当配合warmup使用时。T_max参数控制余弦周期的长度。
在训练初期直接使用较大的学习率可能导致数值不稳定。warmup策略通过在训练初期逐步增加学习率来解决这个问题:
python复制def warmup(current_step, warmup_steps, initial_lr):
if current_step < warmup_steps:
return initial_lr * (current_step/warmup_steps)
return initial_lr
PyTorch虽然没有内置warmup调度器,但我们可以通过LambdaLR自定义:
python复制scheduler = torch.optim.lr_scheduler.LambdaLR(
optimizer,
lr_lambda=lambda step: warmup(step, warmup_steps=1000, initial_lr=0.1)
)
在Transformer等模型训练中,warmup几乎是标配。我的经验是,warmup步数设为总训练步数的5-10%效果最佳。
迁移学习(Transfer Learning)是深度学习中最实用的技术之一,它允许我们将预训练模型的知识迁移到新任务上,显著减少训练时间和数据需求。
python复制for param in model.parameters():
param.requires_grad = False
python复制# 只解冻最后两个残差块
for name, param in model.named_parameters():
if 'layer4' in name or 'layer3' in name:
param.requires_grad = True
else:
param.requires_grad = False
小数据集(<1000样本):
中等规模数据集(1000-10000样本):
大数据集(>10000样本):
迁移学习中最大的挑战之一是不同层需要不同的学习率。PyTorch的param_groups可以轻松实现这一点:
python复制optimizer = torch.optim.SGD([
{'params': model.backbone.parameters(), 'lr': 0.001},
{'params': model.classifier.parameters(), 'lr': 0.01}
], momentum=0.9)
我在实践中发现,对于ImageNet预训练模型:
下面是一个结合学习率调度和迁移学习的完整训练示例:
python复制# 初始化模型
model = torchvision.models.resnet50(pretrained=True)
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, num_classes)
# 分层设置优化器参数
optimizer = torch.optim.SGD([
{'params': model.layer4.parameters(), 'lr': 0.001},
{'params': model.layer3.parameters(), 'lr': 0.0005},
{'params': model.fc.parameters(), 'lr': 0.01}
], momentum=0.9)
# 组合调度器
scheduler1 = torch.optim.lr_scheduler.LambdaLR(
optimizer,
lr_lambda=lambda epoch: warmup(epoch, warmup_epochs=5, initial_lr=1)
)
scheduler2 = torch.optim.lr_scheduler.CosineAnnealingLR(
optimizer,
T_max=50
)
scheduler = torch.optim.lr_scheduler.SequentialLR(
optimizer,
schedulers=[scheduler1, scheduler2],
milestones=[5]
)
# 训练循环
for epoch in range(num_epochs):
train_one_epoch(model, train_loader, optimizer)
val_loss = validate(model, val_loader)
scheduler.step(val_loss)
迁移学习过程中需要密切监控:
常见问题排查:
更精细的分层学习率控制可以进一步提升性能:
python复制def set_diff_lr(model, lr_mult_dict):
params = []
for name, param in model.named_parameters():
for key in lr_mult_dict:
if key in name:
lr = base_lr * lr_mult_dict[key]
params.append({'params': param, 'lr': lr})
break
else:
params.append({'params': param})
return params
lr_mult_dict = {'conv1': 0.1, 'layer1': 0.2, 'layer2': 0.5}
optimizer = torch.optim.SGD(set_diff_lr(model, lr_mult_dict), lr=0.01)
在最近的一个医学图像分类项目中,通过组合余弦退火调度和渐进式解冻策略,我们使用仅1000张标注图像就达到了95%的准确率,而从头训练需要至少10倍的数据量才能达到相似性能。关键在于初始阶段严格控制学习率和解冻范围,随着训练进展逐步放开约束。