Pytorch实现CNN模型的迁移学习

您所在的位置:网站首页 蜜蜂和蚂蚁是什么变态发育的 Pytorch实现CNN模型的迁移学习

Pytorch实现CNN模型的迁移学习

2024-07-13 23:17| 来源: 网络整理| 查看: 265

很多时候当训练一个新的图像分类任务时,一般不会完全从一个随机的模型开始训练,而是利用预训练的模型来加速训练的过程。经常使用在ImageNet上的预训练模型。

这是一种transfer learning的方法。我们常用以下两种方法做迁移学习。 fine tuning: 从一个预训练模型开始,我们改变一些模型的架构,然后继续训练整个模型的参数。feature extraction: 我们不再改变与训练模型的参数,而是只更新我们改变过的部分模型参数。我们之所以叫它feature extraction是因为我们把预训练的CNN模型当做一个特征提取模型,利用提取出来的特征做来完成我们的训练任务。 以下是构建和训练迁移学习模型的基本步骤: 初始化预训练模型把最后一层的输出层改变成我们想要分的类别总数定义一个optimizer来更新参数模型训练 一、项目介绍:

1、目标:本文尝试采用CNN实现图像蜜蜂和蚂蚁图像分类任务。 2、数据说明:使用hymenoptera_data数据集。包括两类图片, bees 和 ants, 这些数据都被处理成了可以使用ImageFolder来读取的格式。 输入数据维度:;输出数据维度 3、torchvision的datasets.ImageFolder参数说明: (1)data_dir:数据的存储目录。设置成数据的根目录 (2)model_name:训练时使用的模型。设置成自己的训练模型,也可以使用封装好的模型。如,resnet, alexnet, vgg, squeezenet, densenet, inception等 (3)num_classes:表示数据集分类的类别数 (4)batch_size (5)num_epochs (6)feature_extract:表示训练时使用fine tuning还是feature extraction方法。如果feature_extract = False,整个模型都会被同时更新。如果feature_extract = True,只有模型的最后一层被更新。 4、网络框架:

二、设置参数 import numpy as np import torchvision from torchvision import datasets, transforms, models import matplotlib.pyplot as plt import time import os import copy print("Torchvision Version: ",torchvision.__version__) data_dir = './hymenoptera_data' #模型可以选择[resnet, alexnet, vgg, squeezenet, densenet, inception] model_name = 'resnet' #数据的label分类个数 num_classes = 2 #训练的batch_size batch_size=32 #训练的轮数 num_epochs = 15 #整个模型参数都参数训练,进行更新 feature_extract = True 二、代码实现 1、初始化模型 #定义需要更新的参数 def set_parameter_requires_grad(model,feature_extracting): if feature_extracting: for param in model.parameters(): param.requires_grad = False #使用resnet框架进行模型初始化 def initialize_model(model_name,num_class,feature_extract,use_pretrained=True): if model_name == 'renet': model_ft = models.resnet18(pretrained=use_pretrained) #使用resnet18最为初始化模型 set_parameter_requires_grad(model_ft,feature_extract) #模型中所有参数都更新 num_ftrs = model_ft.fc.in_features model_ft.fc = nn.Linear(num_ftrs,num_classes) #根据分类个数重新定义最后一层全连接层 input_size = 224 return model_ft,input_size model_ft,input_size = initialize_model(model_name,num_classes,feature_extract,use_pretrained=True) print(model_ft) 2、导入数据集

根据模型输入的size,将数据预处理称为对应的格式

#定义图片的处理方式 data_transforms = { 'train':transforms.Compose([ transforms.RandomResizedCrop(input_size), transforms.RandomHorizontalFlip(), tranforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) #对三个通道分别从用不同的形式进行标准化 ]), 'val':transforms.Compose([ transforms.Resize(input_size), transforms.CenterCrop(input_size), transforms.ToTensor(), transforms.Normalize([[0.485, 0.456, 0.406], [0.229, 0.224, 0.225]]) ]) } print("Initializing Datasets and Dataloaders...") #生成训练集和测试集 image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir,x),data_transforms[x]) for x in ['train','val']} #生成训练集和测试集的迭代器 dataloaders_dict = {x: torch.utils.data.DataLoader(image_datasets[x],batch_size=batch_size,shuffle=True,num_workers=4) for x in ['train','val']} #判断是否使用gpu device = torch.device('cuda:0' if torch.cuda.is_availabel() else 'cpu') 3、观察原始数据 it = iter(dataloaders_dict["train"]) inputs, labels = next(it) for inputs, labels in dataloaders_dict["train"]: print(labels.size()) print(len(dataloaders_dict["train"].dataset.imgs),len(dataloaders_dict["train"].dataset)) 4、模型训练 torch.manual_seed(53113 use_cuda = torch.cuda.is_available() device = torch.device("cuda" if use_cuda else "cpu") def train_model(model,dataloaders,criterion,optimizer,num_epochs=5): since = time.time() val_acc_history = [] best_model_wts = copy.deepcopy(model.state_dict()) #保存最佳参数;copy.deepcopy一旦复制出来了,就应该是独立的了,原始变量改变其不会变,数值一样,但对象不同的。 best_acc = 0. #保存最高的准确率 for epoch in range(num_epochs): print(f'Epoch {epoch}/{num_epochs-1}') print("-"*10) for phase in ['train','val']: running_loss = 0. running_corrects = 0. if phase == 'train': model.train() else: model.eval() for inputs, labels in dataloaders[phase]: inputs = inputs.to(device) labels = labels.to(device) with torch.autograd.set_grad_enabled(phase=='train'): #当phase=='train'为True是,可以进行自动求梯度计算。 outputs = model(inputs) #将数据输入到模型中进行预测 loss = criterion(outputs,labels) #损失计算 _,preds = torch.max(outputs,1) #在所有输出中选取最大的最为输出概率 if phase == 'train': optimizer.zero_grad() #每一次梯度计算后,所有梯度设置为0 loss.backward() #反向求导 optimizer.step() #参数优化 running_loss += loss.item() * inputs.size(0) #损失*batch,等于每一批的总损失;每一批的总损失相加为所有样本的损失和 running_corrects += torch.sum(preds.view(-1) == labels.view(-1)) #每批的预测正确的样本数量;每批预测正确的样本数量相加为所有样本中预测正确的样本数量 epoch_loss = running_loss / len(dataloaders[phase].dataset) #样本总损失 / 样本总个数 = 平均损失 epoch_acc = running_corrects / len(dataloaders[phase].dataset) #样本预测正确的个数 / 样本总个数 = 平均准确率 print(f'{phase} Loss:{epoch_loss} Acc:{epoch_acc}') #取平均准确率最为当前epoch的准确率,与之前的进行比较,保存最高的 if phase == 'val' and epoch_acc > best_acc: best_acc = epoch_acc #每个epoch更新一次准确率 best_model_wts = copy.deepcopy(model.state_dict()) if phase == 'val': val_acc_history.append(epoch_acc) #将每个epoch的准确率添加到列表中 time_elapsed = time.time() - since print(f'Training compete in {time_elapsed // 60}m {time_elapsed % 60}s') #time_elapsed // 60表示相除后取商。 print(f'Best val Acc: {best_acc}') model.load_state_dict(best_model_wts) return model,val_acc_history #返回模型和评估集,每个epoch的最佳acc

(1)对参数进行训练的训练集、测试集结果

model_ft = model_ft.to(device) params_to_update = model_ft.parameters() #获取模型所有的参数进行更新 print('Params to learn:') if feature_extract: #如果feature_extract为True,表示对参数进行更新 params_to_update = [] for name,param in model_ft.named_parameters(): if param.requirs_grad == True: params_to_update.append(param) print('\t',name) else: for name,param in model_ft.named_parameters(): if param.requires_grad == True: print('\t',name)

训练结果: Training compete in 0.0m 14.700076580047607s Best val Acc: 0.954248366013072 (2)不对参数训练的训练集和测试集结果

scratch_model,_ = initlialize_model(model_name,num_classes,feature_extract=False,use_pretrained=False) scratch_model = scratch_model.to(device) scratch_optimizer = optim.SGD(scratch_model.parameters(), lr=0.001, momentum=0.9) scratch_criterion = nn.CrossEntropyLoss() -,scratch_hist = train_model(scratch_model, dataloaders_dict, scratch_criterion, scratch_optimizer, num_epochs=num_epochs)

训练结果: Training compete in 0.0m 18.418847799301147s Best val Acc: 0.7450980392156863 (3)是否对参数训练,效果对比

plt.title("Validation Accuracy vs. Number of Training Epochs") plt.xlabel("Training Epochs") plt.ylabel("Validation Accuracy") plt.plot(range(1,num_epochs+1),ohist,label="Pretrained") plt.plot(range(1,num_epochs+1),scratch_hist,label="Scratch") plt.ylim((0,1.)) plt.xticks(np.arange(1, num_epochs+1, 1.0)) plt.legend() plt.show()

在这里插入图片描述

参考文献:七月在线Pytorch课程



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3