优化器 (torch.optim) 与学习率调度器 (lr_scheduler)
文章目录
- 一、优化器 (Optimizer)
- 1. SGD (随机梯度下降)
- 2. Adam (自适应矩估计)
- 3. RMSprop
- 4. Adagrad (自适应梯度)
- 5. AdamW (Adam + 权重衰减)
- 二、学习率调度器 (lr_scheduler)
- 1. StepLR (步长衰减)
- 2. MultiStepLR (多步衰减)
- 3. ExponentialLR (指数衰减)
- 4. ReduceLROnPlateau (基于指标衰减)
- 5. CosineAnnealingLR (余弦退火)
- 6. OneCycleLR (单周期策略)
- 三、优化器与调度器应用
- 典型训练循环
- 优化器选择
- 调度器选择
- 四、进阶技巧
- 五、如何选择初始学习率
一、优化器 (Optimizer)
优化器负责根据损失函数的梯度更新模型参数,以最小化损失值。所有优化器都继承自基类 torch.optim.Optimizer
。
1. SGD (随机梯度下降)
最基础的优化算法,适用于各种场景。
核心参数:
torch.optim.SGD(params, # 待优化的参数 (model.parameters())lr=0.01, # 学习率 (默认0.01)momentum=0, # 动量因子 (加速收敛,减少震荡)dampening=0, # 动量抑制因子 (默认0)weight_decay=0, # L2正则化系数 (权重衰减)nesterov=False # 是否使用Nesterov动量
)
参数解释:
- 动量因子 (Momentum):模拟了物体运动的惯性特性,帮助优化器在正确方向加速,减少震荡:
v_t = β * v_{t-1} + (1 - β) * g_t
θ_t = θ_{t-1} - η * v_t
其中:
- v_t:当前动量
- β:动量因子 (0 < β < 1),典型取值:
- SGD:β = 0.9 (常用)
- Adam:β1 = 0.9 (一阶动量)
- g_t:当前梯度
- θ_t:更新后的参数
- η:学习率
- 权重衰减 (Weight Decay):权重衰减本质是L2正则化,在损失函数中添加参数范数惩罚项:
L_reg = L_orig + λ/2 * ||θ||^2
优化器更新时:
θ_t = θ_{t-1} - η * (g_t + λ * θ_{t-1})
使用场景:
- 基础训练任务
- 配合动量(momentum>0)可加速收敛
- 需要精细调优的场景
示例:
optimizer = torch.optim.SGD(model.parameters(),lr=0.1,momentum=0.9,weight_decay=1e-4
)
2. Adam (自适应矩估计)
结合了动量法和RMSProp的优点,是当前最常用的优化器。
核心参数:
torch.optim.Adam(params,lr=0.001, # 学习率 (默认0.001)betas=(0.9, 0.999), # 一阶和二阶矩估计的指数衰减率eps=1e-8, # 数值稳定常数 (防止除零)weight_decay=0, # L2正则化amsgrad=False # 是否使用AMSGrad变体
)
使用场景:
- 大多数深度学习任务的首选
- 对超参数相对不敏感
- 训练收敛速度快
示例:
optimizer = torch.optim.Adam(model.parameters(),lr=0.001,betas=(0.9, 0.99),weight_decay=1e-5
)
3. RMSprop
适用于非平稳目标,对循环神经网络效果较好。
核心参数:
torch.optim.RMSprop(params,lr=0.01, # 学习率alpha=0.99, # 平滑常数eps=1e-8, # 数值稳定常数weight_decay=0, # L2正则化momentum=0, # 动量因子centered=False # 是否计算中心化的方差
)
使用场景:
- RNN/LSTM等序列模型
- 非平稳目标函数
- 当Adam效果不佳时可尝试
示例:
optimizer = torch.optim.RMSprop(model.parameters(),lr=0.01,alpha=0.98
)
4. Adagrad (自适应梯度)
为每个参数分配不同的学习率,适合稀疏数据。
核心参数:
torch.optim.Adagrad(params,lr=0.01, # 初始学习率lr_decay=0, # 学习率衰减系数weight_decay=0, # L2正则化initial_accumulator_value=0 # 累加器初始值
)
使用场景:
- 自然语言处理
- 推荐系统
- 稀疏特征数据
示例:
optimizer = torch.optim.Adagrad(model.parameters(),lr=0.01,weight_decay=1e-4
)
5. AdamW (Adam + 权重衰减)
Adam的改进版本,正确处理权重衰减。
核心参数:
torch.optim.AdamW(params,lr=0.001,betas=(0.9, 0.999),eps=1e-8,weight_decay=0.01, # 权重衰减系数 (比Adam更有效)amsgrad=False
)
使用场景:
- 需要正则化的复杂模型
- 计算机视觉任务 (ViT, ConvNext等)
- 当标准Adam出现过拟合时
示例:
optimizer = torch.optim.AdamW(model.parameters(),lr=0.0001,weight_decay=0.05
)
二、学习率调度器 (lr_scheduler)
动态调整学习率可以显著提高模型性能和收敛速度。所有调度器都通过 step()
方法更新学习率。
1. StepLR (步长衰减)
torch.optim.lr_scheduler.StepLR(optimizer, # 绑定的优化器step_size, # 衰减周期 (epoch数)gamma=0.1, # 衰减系数last_epoch=-1 # 上一个epoch索引
)
使用场景:
- 稳定收敛后降低学习率
- 简单训练策略
示例:
scheduler = StepLR(optimizer, step_size=30, gamma=0.1)for epoch in range(100):train(...)validate(...)scheduler.step() # 每个epoch后更新
2. MultiStepLR (多步衰减)
torch.optim.lr_scheduler.MultiStepLR(optimizer,milestones, # 衰减点列表 [30, 80]gamma=0.1,last_epoch=-1
)
使用场景:
- 在特定epoch调整学习率
- 复杂训练计划
示例:
scheduler = MultiStepLR(optimizer, milestones=[30, 80], gamma=0.1)
3. ExponentialLR (指数衰减)
torch.optim.lr_scheduler.ExponentialLR(optimizer,gamma, # 指数衰减因子last_epoch=-1
)
使用场景:
- 平滑连续的学习率衰减
- 需要缓慢调整学习率的任务
示例:
scheduler = ExponentialLR(optimizer, gamma=0.95) # 每个epoch衰减5%
4. ReduceLROnPlateau (基于指标衰减)
torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer,mode='min', # 'min'或'max' (指标优化方向)factor=0.1, # 衰减系数patience=10, # 等待epoch数无改善verbose=True, # 打印信息threshold=1e-4, # 显著变化阈值cooldown=0, # 衰减后等待epoch数min_lr=0 # 学习率下限
)
使用场景:
- 验证指标停滞时自动降低学习率
- 避免手动调整学习率
示例:
scheduler = ReduceLROnPlateau(optimizer, 'max', patience=5) # 准确率最大for epoch in range(100):train(...)val_acc = validate(...)scheduler.step(val_acc) # 传入监控指标
5. CosineAnnealingLR (余弦退火)
torch.optim.lr_scheduler.CosineAnnealingLR(optimizer,T_max, # 半周期长度 (epoch数)eta_min=0 # 最小学习率
)
使用场景:
- 重启优化 (SimCLR, SWAV等)
- 跳出局部最优解
示例:
scheduler = CosineAnnealingLR(optimizer, T_max=50, eta_min=1e-6)
6. OneCycleLR (单周期策略)
torch.optim.lr_scheduler.OneCycleLR(optimizer,max_lr, # 峰值学习率total_steps=None, # 总迭代次数epochs=None, # 总epoch数steps_per_epoch=None,# 每epoch迭代次数pct_start=0.3, # 上升阶段比例anneal_strategy='cos', # 'cos'或'linear'cycle_momentum=True, # 是否调整动量base_momentum=0.85, # 基础动量max_momentum=0.95, # 最大动量div_factor=25.0, # max_lr = initial_lr * div_factorfinal_div_factor=1e4 # min_lr = initial_lr / final_div_factor
)
使用场景:
- 快速收敛
- 小批量数据训练
- 无需复杂调参
示例:
scheduler = OneCycleLR(optimizer,max_lr=0.01,epochs=50,steps_per_epoch=len(train_loader),pct_start=0.25
)for epoch in range(50):for batch in train_loader:optimizer.zero_grad()loss = ...loss.backward()optimizer.step()scheduler.step() # 每个batch后更新
三、优化器与调度器应用
典型训练循环
# 1. 初始化模型和优化器
model = MyModel()
optimizer = torch.optim.AdamW(model.parameters(), lr=0.001)# 2. 创建学习率调度器
scheduler = torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr=0.01,epochs=50,steps_per_epoch=len(train_loader)
)# 3. 训练循环
for epoch in range(50):model.train()for batch_idx, (data, target) in enumerate(train_loader):optimizer.zero_grad()output = model(data)loss = F.cross_entropy(output, target)loss.backward()# 梯度裁剪 (防止梯度爆炸)torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)optimizer.step()scheduler.step() # 每个batch更新学习率# 4. 验证和保存最佳模型model.eval()val_loss = validate(model, val_loader)if val_loss < best_loss:torch.save(model.state_dict(), 'best_model.pth')best_loss = val_loss
优化器选择
场景 | 推荐优化器 | 说明 |
---|---|---|
通用任务 | Adam/AdamW | 快速收敛,超参数鲁棒 |
计算机视觉 | SGD w/momentum | 配合学习率调度可获最佳结果 |
NLP任务 | Adam/Adagrad | 适应稀疏特征 |
强化学习 | RMSprop | 经典DQN算法使用 |
GAN训练 | Adam + SGD | 生成器和判别器使用不同优化器 |
大模型训练 | AdamW | 更好的权重衰减处理 |
调度器选择
需求 | 推荐调度器 | 特点 |
---|---|---|
简单衰减 | StepLR/MultiStepLR | 手动控制衰减点 |
自动调整 | ReduceLROnPlateau | 根据验证指标自动调整 |
快速收敛 | OneCycleLR | 单周期策略,训练速度快 |
跳出局部最优 | CosineAnnealingLR | 周期性重启学习率 |
精细控制 | LambdaLR | 自定义衰减函数 |
热身阶段 | ChainedScheduler | 组合多个调度器 |
四、进阶技巧
-
参数组不同学习率:
optimizer = AdamW([{'params': model.backbone.parameters(), 'lr': 1e-5},{'params': model.head.parameters(), 'lr': 1e-3} ])
-
梯度裁剪:
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
-
监控学习率:
# 在训练循环中记录学习率 current_lr = optimizer.param_groups[0]['lr'] writer.add_scalar('lr', current_lr, global_step)
五、如何选择初始学习率
- 使用学习率范围测试:指数增加lr,观察损失变化
- 经验法则:
- SGD:0.01 ~ 0.1
- Adam:0.0001 ~ 0.001
- 大模型:1e-5 ~ 1e-4
- OneCycleLR:设置为最大学习率