为什么“Pretrained+Fine-tuning”

Deep Learning或者说CNN在图像识别这一领域取得了巨大的进步,那么自然我们就想将CNN应用到我们自己的数据集上,但这时通常就会面临一个问题:通常我们的dataset都不会特别大,一般不会超过1万张,甚至更少。

这种情况下,直接使用train from scratch的方式在小数据集上容易过拟合,尤其是在数据分布差异化很大的场景下。然后就有了迁移学习了,Transfer Learning关心的问题是:什么是“知识”以及如何更好地运用之前得到的“知识”。这可以有很多方法和手段。而本文所说的pretrained+fine-tuning只是其中的一种手段。

pretrained+fine-tuning有什么好处

至少有以下两方面:
1. 解决了我们小样本下使用GoogLeNet这样复杂的网络上容易过拟合的问题;
2. 节省了训练时间。因为网络前面几层提取的特征具备一定的泛化能力(generic)。

pre-trained+finetuning都具有哪些方式:

pre-trained+finetuning通常有两种方式:

  • ConvNet as fixed feature extractor:拿来pretrained的模型,将最后一层全连接层(分类用)去掉,然后将剩下的部分看做一个特征提取器,后面再加一个线性分类器就可以了。比如:在 AlexNet中会对每张图片输出4096维向量,这些向量是用于分类的,只要我们得到了所有图片的这些向量就可以建立一个线性分类器用于新数据的分类了。
  • Fine-tuning the ConvNet:和第一种方法不同的是,这里不仅对顶层的分类进行重新替换和训练,还对卷积层的一些参数通过反向传播进行微调。可以对所有的参数都进行微调,也可以让前几层的参数固定只对高层部分进行微调(为防止过拟合,因为刚开始几层的特征一般是比较通用的,而后面几层可能会包含更多原始训练集的细节)。

具体实践中如何选择不同的pretrained+fine-tuning方式

pretrained+fine-tuning策略取决于多种因素,但最重要的是新数据集的大小以及新数据集与原数据集的相似度。谨记网络前面几层的 DCNN 特征更加泛型(generic),在后面层中更加具有数据集特定性(dataset-specific)。

  • 数据集很小并且与原数据集相似。由于数据集很小,不适合进行微调(可能会过拟合);由于数据类似于原数据,模型更高层次的特征也与此数据集相关。所以最好是在 CNN 特征上训练一个线性分类器。
  • 新数据集很小且与原数据集不同。由于数据较小,只训练一个线性分类器可能更好;由于数据集不同,从网络顶部就开始训练分类器可能会包含更多的原数据集的特定特征。所以最好用网络前部的层来训练分类器。
  • 数据集很大并且与原数据集相似。由于数据多了,应该不会过拟合,可以通过试图微调网络。
  • 数据集大而且与原数据集不同。由于数据集很大,我们可能会期望从头开始训练一个 DCNN。不过,在实践中从一个预训练模型开始初始化权重仍然是一种有益的方法。所以我们可以使用原模型为初始值然后对整个网络进行微调。
    这里写图片描述

参考:
深度学习系列Part2:迁移学习和微调深度卷积神经网络 (原版英文链接Deep Learning Part 2: Transfer Learning and Fine-tuning Deep Convolutional Neural Networks)这篇文章通过了一个具体案例来介绍Fine-tuning,值得一看;
知乎 fine-tuning:利用已有模型训练其他数据集 ,MXNet下Pretrained+Finetuning的正确姿势这里写链接内容
cs231n transfer learning (翻译版CS231n 卷积神经网络与计算机视觉 11 卷积神经网络的 迁移学习 和微调) ;
迁移学习与fine-tuneing有什么区别?

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Sure! Here are the steps to fine-tune ViT-S on a custom dataset using Google Colab: 1. Open a new Google Colab notebook and select a GPU runtime environment. 2. Install the necessary libraries: ``` !pip install torch torchvision !pip install timm ``` 3. Download and prepare the custom dataset. You can use any dataset of your choice. Make sure to split it into training and validation sets. 4. Define the data loaders: ``` import torch import torchvision.transforms as transforms from torch.utils.data import DataLoader from torchvision.datasets import ImageFolder # Define the transformations transform_train = transforms.Compose([ transforms.RandomResizedCrop(224), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) transform_val = transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) # Define the data loaders train_dataset = ImageFolder('path_to_train_data', transform=transform_train) train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=4) val_dataset = ImageFolder('path_to_val_data', transform=transform_val) val_loader = DataLoader(val_dataset, batch_size=32, shuffle=False, num_workers=4) ``` Replace 'path_to_train_data' and 'path_to_val_data' with the paths to your training and validation data folders, respectively. 5. Load the pre-trained ViT-S model: ``` import timm model = timm.create_model('vit_small_patch16_224', pretrained=True) ``` 6. Modify the last layer of the model to fit your custom dataset: ``` import torch.nn as nn num_classes = len(train_dataset.classes) model.head = nn.Sequential( nn.LayerNorm((768,)), nn.Linear(768, num_classes) ) ``` Replace '768' with the hidden size of the model you are using. For ViT-S, it is 768. 7. Define the optimizer and criterion: ``` import torch.optim as optim optimizer = optim.Adam(model.parameters(), lr=1e-4) criterion = nn.CrossEntropyLoss() ``` 8. Fine-tune the model: ``` device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model.to(device) num_epochs = 10 for epoch in range(num_epochs): train_loss = 0.0 val_loss = 0.0 correct = 0 total = 0 # Train the model model.train() for inputs, labels in train_loader: inputs, labels = inputs.to(device), labels.to(device) optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() train_loss += loss.item() * inputs.size(0) # Evaluate the model on validation set model.eval() with torch.no_grad(): for inputs, labels in val_loader: inputs, labels = inputs.to(device), labels.to(device) outputs = model(inputs) loss = criterion(outputs, labels) val_loss += loss.item() * inputs.size(0) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() train_loss = train_loss / len(train_loader.dataset) val_loss = val_loss / len(val_loader.dataset) accuracy = 100 * correct / total print('Epoch: {} \tTraining Loss: {:.6f} \tValidation Loss: {:.6f} \tAccuracy: {:.2f}'.format( epoch+1, train_loss, val_loss, accuracy)) ``` 9. Save the model: ``` torch.save(model.state_dict(), 'path_to_save_model') ``` Replace 'path_to_save_model' with the path where you want to save the model. That's it! You have fine-tuned ViT-S on your custom dataset using Google Colab.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值