pytorch模型权重与模型微调

目录

一、模型微调的流程

二、使用已经有的模型结构

2.1 实例化网络

2.2 传递pretrained参数

注意事项:

三、训练特定层

四、实例


        随着深度学习的发展,在大模型的训练上都是在一些较大数据集上进行训练的,比如Imagenet-1k,Imagenet-11k,甚至是ImageNet-21k等。但我们在实际应用中,我们的数据集可能比较小,只有几千张照片,这时从头训练具有几千万参数的大型神经网络是不现实的,因为越大的模型对数据量的要求越高,过拟合无法避免
        因为试用于ImageNet数据集的复杂模型,在一些小的数据集上可能会过拟合,同时因为数据量有限,最终训练得到的模型的精度也可能达不到实用要求。

解决上述问题的方法:
1. 收集更多数据集,当然这对于研究成本会大大增加。
2. 应用迁移学习,从源数据集中学到知识迁移到目标数据集上。迁移学习的一大应用场景就是模型微调,简单的来说就是把在别人训练好的基础上,换成自己的数据集继续训练,来调整参数。Pytorch中提供很多预训练模型,学习如何进行模型微调,可以大大提升自己任务的质量和速度。

一、模型微调的流程

1.1  在源数据集上预训练一个神经网络模型,即源模型
1.2  创建一个新的神经网络模型,即目标模型。他复制了源模型上除了输出层外的所有模型设计及其参数。我们假设这些模型参数包含了源数据集上学习到的知识,且这些知识同样试用于目标数据集,我们还假设源模型的输出层跟源数据集的标签紧密相关,因此输出层在目标模型上可以采用。
1.3  为目标模型添加一个输出大小为目标数据集类别个数的输出层,并随机初始化该层的模型参数。
1.4  在目标数据集上训练目标模型,我们将从头训练输出层,而其余层的参数都是基于源模型的参数微调得到的。

二、使用已经有的模型结构

2.1 实例化网络

1 import torchvision.models as models
2 resnet18 = models.resnet18()
3 # resnet18 = models.resnet18(pretrained=False) 等价于与上面的表达式
4 alexnet = models.alexnet()
5 vgg16 = models.vgg16()
6 squeezenet = models.squeezenet1_0()
7 densenet = models.densenet161()
8 inception = models.inception_v3()
9 googlenet = models.googlenet()
10 shufflenet = models.shufflenet_v2_x1_0()
11 mobilenet_v2 = models.mobilenet_v2()
12 mobilenet_v3_large = models.mobilenet_v3_large()
13 mobilenet_v3_small = models.mobilenet_v3_small()
14 resnext50_32x4d = models.resnext50_32x4d()
15 wide_resnet50_2 = models.wide_resnet50_2()
16 mnasnet = models.mnasnet1_0()

2.2 传递pretrained参数

通过True或者False来决定是否使用预训练好的权重,在默认情况下(不写参数的情况下)pretrained = False,意味着我们不适用预训练得到的权重,当pretrained = True ,意味着我们将使用一些数据集上预训练得到的权重。

1 import torchvision.models as models
2 resnet18 = models.resnet18(pretrained=True)
3 alexnet = models.alexnet(pretrained=True)
4 squeezenet = models.squeezenet1_0(pretrained=True)
5 vgg16 = models.vgg16(pretrained=True)
6 densenet = models.densenet161(pretrained=True)
7 inception = models.inception_v3(pretrained=True)
8 googlenet = models.googlenet(pretrained=True)
9 shufflenet = models.shufflenet_v2_x1_0(pretrained=True)
10 mobilenet_v2 = models.mobilenet_v2(pretrained=True)
11 mobilenet_v3_large = models.mobilenet_v3_large(pretrained=True)
12 mobilenet_v3_small = models.mobilenet_v3_small(pretrained=True)
13 resnext50_32x4d = models.resnext50_32x4d(pretrained=True)
14 wide_resnet50_2 = models.wide_resnet50_2(pretrained=True)
15 mnasnet = models.mnasnet1_0(pretrained=True)

注意事项:

1. 通常Pytorch模型的扩展为.pt或.pth,程序运行时会首先检查默认路径种是否有已经下载的模型权重,如果权重被下载了,下次加载就不需要下载了。
2. 一般情况下预训练模型的下载会比较慢,我们可以直接通过迅雷或者其他方式去查看自己的模型里面model_urls,然后手动下载,预训练模型的权重在LInux和Mac的默认下载路径是用户根目录下的.cache文件夹。在windows下就是在C:\Users<username>.cache\torch\hub\checkpoint。我们可以通过使用 torch.utils.model_zoo.load_url()设置权重的下载地址。
3. 觉得麻烦的话,还可以将自己的权重下载下来放到同文件夹下,然后再将参数加载网络。

1 self.model = models.resnet50(pretrained=False)
2 self.model.load_state_dict(torch.load('./model/resnet50-19c8e357.pth'))

4. 如果中途强行停止下载的话,一定要把对应路径下的权重文件删除干净,要不然可能会报错。

三、训练特定层

        在默认情况下,参数的属性.requires_grad - True,如果我们从头开始训练或微调不需要注意这里。但如果我们正在提取特征并且只想为新初始化的层计算梯度,其他参数不进行改变。那我们就需要通过设置一个requires_grad = False来冻结部分层。
官方例程

def set_parameter_requires_grad(model, feature_extracting):
    if feature_extracting:
        for param in model.parameters():
            param.requires_grad = False

四、实例

        在下面我们仍旧使用resnet18为例的将1000类改为4类,但是仅改变最后一层的模型参数,不改变特征提取的模型参数;注意我们先冻结模型参数的梯度,再对模型输出部分的全连接层进行修改,这样修改后的全连接层的参数就是可计算梯度的。

import torchvision.models as models
# 冻结参数的梯度
feature_extract = True
model = models.resnet18(pretrained=True)
set_parameter_requires_grad(model, feature_extract)
# 修改模型
num_ftrs = model.fc.in_features

model.fc = nn.Linear(in_features=512, out_features=4, bias=True)

之后在训练过程中,model仍会进行梯度回传,但是参数更新只发生在fc层。通过设定参数的required_grad属性,我们可以实现只对特定层训练的目标,这对实现模型微调很重要。

参考:https://www.cnblogs.com/tccjx/articles/16026663.html 

猜你喜欢

转载自blog.csdn.net/baidu_41774120/article/details/129992982
今日推荐