为什么要冻结,a、因为加载的预训练模型参数一般是效果较好的,如果我们不冻结还是从头开始训练浪费资源(本来可以较快收敛的,结果从头开始训练浪费训练资源)甚至降低原模型精度;b、冻结训练需要的显存较小,显卡非常差的情况下,可以冻结backbone等部分,剩余的进行微调
初始化模型参数
torch.init.normal_
给tensor初始化,一般是给网络中参数weight初始化,初始化参数值符合正态分布。
torch.init.normal_(tensor,mean=,std=)
mean:均值,std:正态分布的标准差
torch.init.constant_
初始化参数使其为常值,即每个参数值都相同。一般是给网络中bias进行初始化。
torch.nn.init.constant_(tensor,val)
给不同层使用不同的初始化策略
pytorch的初始化方式总结 - 知乎
for m in self.children():
if isinstance(m, nn.Linear):
nn.init.constant_(m.weight, 1)
nn.init.constant_(m.bias, -100)
# 也可以判断是否为conv2d,使用相应的初始化方式
elif isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
elif isinstance(m, nn.BatchNorm2d):
nn.init.constant_(m.weight.item(), 1)
nn.init.constant_(m.bias.item(), 0)
参考https://blog.csdn.net/weixin_44791964?type=blog 博主的博客及视频及代码仓库。
模型的 预训练权重 比较重要的部分是 主干特征提取网络的权值部分,用于进行特征提取。预训练权重对于99%的情况都必须要用,不用的话主干部分的权值太过随机,特征提取效果不明显,网络训练的结果也不会好。训练自己的数据集时提示维度不匹配正常,预测的东西都不一样了自然维度不匹配
torch.load()加载模型及其map_location参数_eecspan的博客-CSDN博客_torch加载模型
函数格式为:torch.load(f, map_location=None, pickle_module=pickle, **pickle_load_args)
,一般我们使用的时候,基本只使用前两个参数。
模型保存有两种形式,一种是保存模型的state_dict(),只是保存模型的参数。那么加载时需要先创建一个模型的实例model,之后通过torch.load()将保存的模型参数加载进来,得到dict,再通过model.load_state_dict(dict)将模型的参数更新。
另一种是将整个模型保存下来,之后加载的时候只需要通过torch.load()将模型加载,即可返回一个加载好的模型。
具体可参考:PyTorch模型的保存与加载。
具体来说,map_location
参数是用于重定向,比如此前模型的参数是在cpu
中的,我们希望将其加载到cuda:0
中。或者我们有多张卡,那么我们就可以将卡1中训练好的模型加载到卡2中,这在数据并行的分布式深度学习中可能会用到。
如果预训练模型与定义模型层数不匹配,使用如下代码,剥出你需要的层的参数
pretrained_dict = torch.load(pretrained_model)
model_dict = model.state_dict()
pretrained_dict = {
k: v for k, v in pretrained_dict.items()
if (k in model_dict and 'Prediction' not in k)
}
model_dict.update(pretrained_dict)
model.load_state_dict(model_dict)
深度学习基本功2:网络训练小技巧之使用预训练权重、冻结训练和断点恢复 - 知乎
# 冻结阶段训练参数,learning_rate和batch_size可以设置大一点
Init_Epoch = 0
Freeze_Epoch = 50
Freeze_batch_size = 8
Freeze_lr = 1e-3
# 解冻阶段训练参数,learning_rate和batch_size设置小一点
UnFreeze_Epoch = 100
Unfreeze_batch_size = 4
Unfreeze_lr = 1e-4
# 可以加一个变量控制是否进行冻结训练
Freeze_Train = True
# 冻结一部分进行训练
batch_size = Freeze_batch_size
lr = Freeze_lr
start_epoch = Init_Epoch
end_epoch = Freeze_Epoch
if Freeze_Train:
for param in model.backbone.parameters():
param.requires_grad = False
# 解冻后训练
batch_size = Unfreeze_batch_size
lr = Unfreeze_lr
start_epoch = Freeze_Epoch
end_epoch = UnFreeze_Epoch
if Freeze_Train:
for param in model.backbone.parameters():
param.requires_grad = True
如果不进行冻结训练,一定要注意参数设置,注意上述代码中冻结阶段和解冻阶段的learning_rate和batch_size是不一样的,另外起始epoch和结束epoch也要重新调整一下。如果是从0开始训练模型(不使用预训练权重),那么一定不能进行冻结训练。
在冻结部分,重新设置了学习率,batchsize。
冻结阶段:为了快速收敛,可以加大学习率及batchsize(此时由于部分参数冻结不需要计算梯度所以可以加大这些)
解冻阶段:所有层都需要计算梯度等加大开销,所以学习率及batchsize的设置不能再像冻结阶段设置的那么大
因为冻结阶段涉及到学习率的设计,所以也写一下学习率的介绍
PyTorch 源码解读之 torch.optim:优化算法接口详解 - 知乎
这个博主写的非常详细,看完就悟了
lr
,momentum
等optimizer.zero_grad()
清空梯度,再调用 loss.backward()
反向传播,最后调用 optimizer.step()
更新模型参数optimizer = torch.optim.RMSprop(model.parameters(), lr=learning_rate)
所有优化器都是继承父类 Optimizer
,如下列表是 PyTorch 提供的优化器:
Optimizer
是所有优化器的父类,它主要有如下公共方法:
参考文章同优化器的那篇
有了优化器,还需要根据 epoch 来调整学习率,lr_schedluer
提供了在训练模型时学习率的调整策略。
目前 PyTorch 提供了如下学习率调整策略:
基类: _LRScheduler
学习率调整类主要的逻辑功能就是每个 epoch 计算参数组的学习率,更新 optimizer
对应参数组中的lr
值,从而应用在optimizer
里可学习参数的梯度更新。所有的学习率调整策略类的父类是torch.optim.lr_scheduler._LRScheduler
,基类 _LRScheduler
定义了如下方法:
剩余部分见原博客