东方耀AI技术分享

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 2831|回复: 0
打印 上一主题 下一主题

[PyTorch] 07、如何微调模型?

[复制链接]

1365

主题

1856

帖子

1万

积分

管理员

Rank: 10Rank: 10Rank: 10

积分
14437
QQ
跳转到指定楼层
楼主
发表于 2020-4-15 14:33:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
07、如何微调模型?


对于不同的领域微调的方法也不一样,比如语音识别领域一般微调前几层,图片识别问题微调后面几层,这个原因我这里也只能讲个大概,具体还要大神来解释:


对于图片来说,我们CNN的前几层学习到的都是低级的特征,比如,点、线、面,这些低级的特征对于任何图片来说都是可以抽象出来的,所以我们将他作为通用数据,只微调这些低级特征组合起来的高级特征即可,例如,这些点、线、面,组成的是园还是椭圆,还是正方形,这些代表的含义是我们需要后面训练出来的。


对于语音来说,每个单词表达的意思都是一样的,只不过发音或者是单词的拼写不一样,比如 苹果,apple,apfel(德语),都表示的是同一个东西,只不过发音和单词不一样,但是他具体代表的含义是一样的,就是高级特征是相同的,所以我们只要微调低级的特征就可以了。


下面只介绍下计算机视觉方向的微调,摘自 cs231


ConvNet as fixed feature extractor.: 其实这里有两种做法:
1、使用最后一个fc layer之前的fc layer获得的特征,学习个线性分类器(比如SVM)
重新训练最后一个fc layer 只在最后一个fc层微调
2、Fine-tuning the ConvNet
固定前几层的参数,只对最后几层进行fine-tuning,


对于上面两种方案有一些微调的小技巧,比如先计算出预训练模型的卷积层对所有训练和测试数据的特征向量,然后抛开预训练模型,只训练自己定制的简配版全连接网络。 这个方式的一个好处就是节省计算资源,每次迭代都不会再去跑全部的数据,而只是跑一下简配的全连接


Pretrained models
这个其实和第二种是一个意思,不过比较极端,使用整个pre-trained的model作为初始化,然后fine-tuning整个网络而不是某些层,但是这个的计算量是非常大的,就只相当于做了一个初始化。


注意事项:(针对图像数据)
1、新数据集和原始数据集合类似,那么直接可以微调一个最后的FC层或者重新指定一个新的分类器
2、新数据集比较小和原始数据集合差异性比较大,那么可以使用从模型的中部开始训练,只对最后几层进行fine-tuning
3、新数据集比较小和原始数据集合差异性比较大,如果上面方法还是不行的化那么最好是重新训练,只将预训练的模型作为一个新模型初始化的数据
4、新数据集的大小一定要与原始数据集相同,比如CNN中输入的图片大小一定要相同,才不会报错
5、如果数据集大小不同的话,可以在最后的fc层之前添加卷积或者pool层,使得最后的输出与fc层一致,但这样会导致准确度大幅下降,所以不建议这样做
6、对于不同的层可以设置不同的学习率,一般情况下建议,对于使用的原始数据做初始化的层设置的学习率要小于(一般可设置小于10倍)初始化的学习率,这样保证对于已经初始化的数据不会扭曲的过快,而使用初始化学习率的新层可以快速的收敛。



  1. 开始配置网络,由于ImageNet是识别1000个物体,我们的狗的分类一共只有120,所以需要对模型的最后一层全连接层进行微调,将输出从1000改为120

  2. model_ft = models.resnet50(pretrained=True) # 这里自动下载官方的预训练模型,并且
  3. # 将所有的参数层进行冻结
  4. for param in model_ft.parameters():
  5.     param.requires_grad = False
  6. # 这里打印下全连接层的信息
  7. print(model_ft.fc)
  8. num_fc_ftr = model_ft.fc.in_features #获取到fc层的输入
  9. model_ft.fc = nn.Linear(num_fc_ftr, 120) # 定义一个新的FC层
  10. model_ft=model_ft.to(DEVICE)# 放到设备中
  11. print(model_ft) # 最后再打印一下新的模型


  12. criterion = nn.CrossEntropyLoss()
  13. optimizer = torch.optim.Adam([
  14.     {'params':model_ft.fc.parameters()}
  15. ], lr=0.001)#指定 新加的fc层的学习率




复制代码

但是每次训练都需要将一张图片在全部网络中进行计算,而且计算的结果每次都是一样的,这样浪费了很多计算的资源。
下面我们就将这些不进行反向传播或者说不更新网络权重参数层的计算结果保存下来,
这样我们以后使用的时候就可以直接将这些结果输入到FC层或者以这些结果构建新的网络层,省去了计算的时间,
并且这样如果只训练全连接层,CPU就可以完成了。

固定层的向量导出
采用PyTorch比较高级的API,hook来处理了,我们要先定义一个hook函数

in_list= [] # 这里存放所有的输出
def hook(module, input, output):
    #input是一个tuple代表顺序代表每一个输入项,我们这里只有一项,所以直接获取
    #需要全部的参数信息可以使用这个打印
    #for val in input:
    #    print("input val:",val)
    for i in range(input[0].size(0)):
        in_list.append(input[0].cpu().numpy())

在相应的层注册hook函数,保证函数能够正常工作,我们这里直接hook 全连接层前面的pool层,获取pool层的输入数据,这样会获得更多的特征

model_ft.avgpool.register_forward_hook(hook)

开始获取输出,这里我们因为不需要反向传播,所以直接可以使用no_grad嵌套
%%time
with torch.no_grad():
    for batch_idx, data in enumerate(image_dataloader["train"]):
        x,y= data
        x=x.to(DEVICE)
        y=y.to(DEVICE)
        y_hat = model_ft(x)


features=np.array(in_list)
np.save("features",features)


这样再训练时我们只需将这个数组读出来,然后可以直接使用这个数组再输入到linear或者我们前面讲到的sigmod层就可以了。

我们在这里在pool层前获取了更多的特征,可以将这些特征使用更高级的分类器,例如SVM,树型的分类器进行分类。

以上就是针对于计算机视觉方向的微调介绍






让天下人人学会人工智能!人工智能的前景一片大好!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|人工智能工程师的摇篮 ( 湘ICP备2020019608号-1 )

GMT+8, 2024-5-6 00:52 , Processed in 0.175744 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表