目录
一.调整学习率
1.调整学习率的原因和重要性
- 固定的学习率(如0.1)可能导致模型难以收敛到最优解。
- 深度学习模型因数据集巨大,对学习率的微小调整都需耗费较多时间进行验证,传统的“暴力枚举”方法效率低下。
- 推荐采用动态调整学习率,模拟登山者在上山时步伐大、接近山谷时步伐小的场景,使模型在粗略下降后能精确寻优。
2.调整学习率
①有序调整
- 多间隔调整 (Multi-step LR):在用户自定义的特定轮次节点进行学习率调整,比等间隔调整更具灵活性。
- 指数衰减 (Exponential Decay):学习率随训练轮次呈指数形式衰减。
- 余弦退火 (Cosine Annealing):一种周期性变化学习率的方法,应用相对较少。
②自适应调整
- 自适应调整方法的效果最好,该方法会监测损失值(Loss)或准确率(ACC),当相关指标变化趋小时自动调整学习率。
③自定义调整学习率
自定义调整则允许用户编写Lambda函数实现,但需用户自行实现。通过自定义关于epoch的lambda函数调整学习率(LambdaLR)
3.食物分类案例优化
我们需要在创建优化器之后再用库函数调整学习率,并在每次训练后都进行scheduler.step()来进行学习率的更新
①等间隔调整学习率
每5个epoch更新学习率等于lr*gamma,gamma学习率衰减因子
loss_fn=nn.CrossEntropyLoss()
optimizer=torch.optim.Adam(model.parameters(),lr=0.1)
scheduler=torch.optim.lr_scheduler.StepLR(optimizer=optimizer,step_size=5,gamma=0.5)#每5个epoch更新学习率lr*gamma,gamma学习率衰减因子
在每个epoch的训练中,使用scheduler.step()进行学习率的更新,没达到step_size则更新值为原来的学习率
epochs=50
for i in range(epochs):
print(f'==========第{i + 1}轮训练==============')
train(train_loader, model, loss_fn, optimizer)
scheduler.step()#在每个epoch的训练中,使用scheduler.step()进行学习率的更新,没达到step_size则更新值为原来的学习率
print(f'第{i + 1}轮训练结束')
test(test_loader,model,loss_fn)
②自适应调整学习率
optimizer=torch.optim.Adam(model.parameters(),lr=0.1)
scheduler=torch.optim.lr_scheduler.ReduceLROnPlateau(
optimizer=optimizer,mode='min',factor=0.1,patience=2,verbose=False,threshold=0.0001,
threshold_mode='rel',cooldown=0,min_lr=0,eps=1e-08)
参数介绍:
mode='min'
指标的优化方向:
'min'
:当指标停止下降(如损失值不再减小)时触发学习率调整
'max'
:当指标停止上升(如准确率不再提高)时触发调整
factor=0.1
学习率调整倍数,新学习率 = 当前学习率 × factor(此处为乘以 0.1,即降低 10 倍)。
patience=10
触发调整前的 “容忍次数”:若指标连续 patience
个 epoch 未改善,则调整学习率。
verbose=False
是否打印学习率调整信息:True
时会在调整时输出日志(如 “Epoch XXX: reducing learning rate...”)。
threshold=0.0001
判定指标是否 “改善” 的阈值:只有当指标变化超过该阈值时,才认为是有效改善。
threshold_mode='rel'
阈值的计算方式:
'rel'
:相对变化(如 current = best * (1 + threshold)
或 (1 - threshold)
,取决于 mode)
'abs'
:绝对变化(如 current = best + threshold
或 best - threshold
)
cooldown=0
调整学习率后,暂停监控指标的 “冷却期”(单位:epoch),避免短时间内频繁调整。
min_lr=0
学习率的下限:无论如何调整,学习率不会低于此值(可传入与参数组对应的列表,如 [1e-5, 1e-6]
)。
eps=1e-08
学习率的最小变化量:若新旧学习率的差值小于 eps,则忽略此次调整。
epochs=50
for i in range(epochs):
print(f'==========第{i + 1}轮训练==============')
loss=train(train_loader, model, loss_fn, optimizer)
scheduler.step(loss)
# ReduceLROnPlateau调度器的step()方法必须传入一个指标值(如验证损失或准确率),它需要根据这个指标来判断是否需要调整学习率。
print(f'第{i + 1}轮训练结束')
test(test_loader,model,loss_fn)
需要注意 ReduceLROnPlateau调度器的step()方法必须传入一个指标值(如验证损失或准确率),它需要根据这个指标来判断是否需要调整学习率。所以我们再train()方法中增加一个平均损失值作为返回值
二.迁移学习
1.迁移学习的概念和价值
- 定义: 指利用已经训练好的模型,在新的任务上进行微调。
- 价值: 可以大幅缩短模型的训练时间,使模型在数据量较少的新任务上也能取得较好的性能。
2.迁移学习实施步骤
选择预训练模型与适当层数: 选择预训练的模型和适当的层:选择在大规模数据集上训练的顶尖模型,通常,我们会选择在大规模图像数据集(如ImageNet)上预训练的模型,如VGG、ResNet等。然后,根据新数据集的特点,选择需要微调的模型层。对于低级特征的任务(如边缘检测),最好使用浅层模型的层,而对于高级特征的任务(如分类),则应选择更深层次的模型。
- 冻结预训练模型参数: 保持预训练模型的权重不变,只训练新增加的层或者微调一些层,避免因为在数据集中过拟合导致预训练模型过度拟合。
- 训练新增加的层: 在冻结预训练模型的参数情况下,训练新增加的层。这样,可以使新模型适应新的任务,从而获得更高的性能。
- 微调预训练模型层: 在新层上进行训练后,可以解冻一些已经训练过的层,并且将它们作为微调的目标。这样做可以提高模型在新数据集上的性能。
- 评估和测试:训练完成之后,使用测试集对模型进行评估。如果模型的性能仍然不够好,可以尝试调整超参数或者更改微调层。
下一节我们讲解CNN中优秀的已经训练好的模型残差网络ResNet