pytorch--fine-tuning的使用

本文详细介绍了PyTorch中模型微调的概念、重要性和操作步骤,特别是针对图像识别任务。微调预训练模型能有效降低训练成本,减少过拟合风险。文章通过狗品种识别案例展示了如何使用ResNet50进行微调,并探讨了数据集大小、模型层选择和学习率设置等注意事项。同时,文章提到了固定层向量导出的技巧,以提高训练效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

%matplotlib inline
import torch,os,torchvision
import torch.nn as nn
import torch.nn.functional as F
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from torch.utils.data import DataLoader, Dataset
from torchvision import datasets, models, transforms
from PIL import Image
from sklearn.model_selection import StratifiedShuffleSplit
torch.__version__
'1.2.0'

4.1 Fine tuning 模型微调

在前面的介绍卷积神经网络的时候,说到过PyTorch已经为我们训练好了一些经典的网络模型,那么这些预训练好的模型是用来做什么的呢?其实就是为了我们进行微调使用的。

4.1.1 什么是微调

针对于某个任务,自己的训练数据不多,那怎么办? 没关系,我们先找到一个同类的别人训练好的模型,把别人现成的训练好了的模型拿过来,换成自己的数据,调整一下参数,再训练一遍,这就是微调(fine-tune)。 PyTorch里面提供的经典的网络模型都是官方通过Imagenet的数据集与训练好的数据,如果我们的数据训练数据不够,这些数据是可以作为基础模型来使用的。

为什么要微调

  1. 对于数据集本身很小(几千张图片)的情况,从头开始训练具有几千万参数的大型神经网络是不现实的,因为越大的模型对数据量的要求越大,过拟合无法避免。这时候如果还想用上大型神经网络的超强特征提取能力,只能靠微调已经训练好的模型。
  2. 可以降低训练成本:如果使用导出特征向量的方法进行迁移学习,后期的训练成本非常低,用 CPU 都完全无压力,没有深度学习机器也可以做。
  3. 前人花很大精力训练出来的模型在大概率上会比你自己从零开始搭的模型要强悍,没有必要重复造轮子。

迁移学习 Transfer Learning

总是有人把 迁移学习和神经网络的训练联系起来,这两个概念刚开始是无关的。 迁移学习是机器学习的分支,现在之所以 迁移学习和神经网络联系如此紧密,现在图像识别这块发展的太快效果也太好了,所以几乎所有的迁移学习都是图像识别方向的,所以大家看到的迁移学习基本上都是以神经网络相关的计算机视觉为主,本文中也会以这方面来举例子

迁移学习初衷是节省人工标注样本的时间,让模型可以通过一个已有的标记数据的领域向未标记数据领域进行迁移从而训练出适用于该领域的模型,直接对目标域从头开始学习成本太高,我们故而转向运用已有的相关知识来辅助尽快地学习新知识

举一个简单的例子就能很好的说明问题,我们学习编程的时候会学习什么? 语法、特定语言的API、流程处理、面向对象,设计模式,等等

这里面语法和API是每一个语言特有的,但是面向对象和设计模式可是通用的,我们学了JAVA,再去学C#,或者Python,面向对象和设计模式是不用去学的,因为原理都是一样的,甚至在学习C#的时候语法都可以少学很多,这就是迁移学习的概念,把统一的概念抽象出来,只学习不同的内容。

迁移学习按照学习方式可以分为基于样本的迁移,基于特征的迁移,基于模型的迁移,以及基于关系的迁移,这里就不详细介绍了。

二者关系

其实 "Transfer Learning" 和 "Fine-tune" 并没有严格的区分,含义可以相互交换,只不过后者似乎更常用于形容迁移学习的后期微调中。 我个人的理解,微调应该是迁移学习中的一部分。微调只能说是一个trick。

4.1.2 如何微调

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

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

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

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

  • ConvNet as fixed feature extractor.: 其实这里有两种做法:
    1. 使用最后一个fc layer之前的fc layer获得的特征,学习个线性分类器(比如SVM)
    2. 重新训练最后一个fc layer
  • Fine-tuning the ConvNet

固定前几层的参数,只对最后几层进行fine-tuning,

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

  • Pretrained models

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

4.1.3 注意事项

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

4.1.3 微调实例

这里面我们使用官方训练好的resnet50来参加kaggle上面的 dog breed 狗的种类识别来做一个简单微调实例。

首先我们需要下载官方的数据解压,只要保持数据的目录结构即可,这里指定一下目录的位置,并且看下内容

DATA_ROOT = 'data'
all_labels_df = pd.read_csv(os.path.join(DATA_ROOT,'labels.csv'))
all_labels_df.head()
  id breed
0 000bec180eb18c7604dcecc8fe0dba07 boston_bull
1 001513dfcb2ffafc82cccf4d8bbaba97 dingo
2 001cdf01b096e06d78e9e5112d419397 pekinese
3 00214f311d5d2247d5dfe4fe24b2303d bluetick
4 0021f9ceb3235effd7fcde7f7538ed62 golden_retriever
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值