广告
返回顶部
首页 > 资讯 > 后端开发 > Python >PyTorch迁移学习实战
  • 353
分享到

PyTorch迁移学习实战

PyTorch迁移 2023-01-15 18:01:35 353人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录1. 实验环境2. 实验目的3. 相关原理4. 实验步骤4.1 数据收集4.2 数据预处理4.3 创建模型4.4 结论1. 实验环境 Jupyter Notebookpython

1. 实验环境

2. 实验目的

迁移学习,让机器拥有能够“举一反三”的能力。
本次实验就以“是蚂蚁还是蜜蜂”为例,探索如何将已训练好的大网络迁移到小数据集上,并经过少量数据集的训练就让它获得非常出众的效果。

3. 相关原理

使用 PyTorch 的数据集套件从本地加载数据的方法
迁移训练好的大型神经网络模型到自己模型中的方法
迁移学习与普通深度学习方法的效果区别
两种迁移学习方法的区别

4. 实验步骤

# 下载实验所需数据并解压
!wget Http://labfile.oss.aliyuncs.com/courses/1073/transfer-data.zip
!unzip transfer-data.zip

4.1 数据收集

实验中的数据是已经准备好的,训练数据集在 ./data/train 中,校验数据集在 ./data/val 中。(推荐直接到蓝桥云课上进行实验)。如果使用自己的环境只需要自己准备相关图片数据,并将代码中的路径改成你自己的数据集路径。

#引入实验所需要的包
import torch
import torch.nn as nn
import torch.optim as optim
from torch.autograd import Variable
import torch.nn.functional as F
import numpy as np
import torchvision
from torchvision import datasets, models, transfORMs
import matplotlib.pyplot as plt
import time
import copy
import os

4.1.1加载数据

使用 datasets 的 ImageFolder 方法就可以实现自动加载数据,因为数据集中的数据可能分别在不同的文件夹中,要让所有的数据一起加载。

# 数据存储总路径
data_dir = 'transfer-data'
# 图像的大小为224*224
image_size = 224
# 从data_dir/train加载文件
# 加载的过程将会对图像自动作如下的图像增强操作:
# 1. 随机从原始图像中切下来一块224*224大小的区域
# 2. 随机水平翻转图像
# 3. 将图像的色彩数值标准化
train_dataset = datasets.ImageFolder(os.path.join(data_dir, 'train'),
                                    transforms.Compose([
                                        transforms.RandomResizedCrop(image_size),
                                        transforms.RandomHorizontalFlip(),
                                        transforms.ToTensor(),
                                        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
                                    ])
                                    )

# 加载校验数据集,对每个加载的数据进行如下处理:
# 1. 放大到256*256像素
# 2. 从中心区域切割下224*224大小的图像区域
# 3. 将图像的色彩数值标准化
val_dataset = datasets.ImageFolder(os.path.join(data_dir, 'val'),
                                    transforms.Compose([
                                        transforms.Resize(256),
                                        transforms.CenterCrop(image_size),
                                        transforms.ToTensor(),
                                        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
                                    ])
                                    )

下面要为每个数据集创建数据加载器。

# 创建相应的数据加载器
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size = 4, shuffle = True, num_workers=4)
val_loader = torch.utils.data.DataLoader(val_dataset, batch_size = 4, shuffle = True, num_workers=4)

# 读取得出数据中的分类类别数
# 如果只有蜜蜂和蚂蚁,那么是2
num_classes = len(train_dataset.classes)
num_classes

输出:2

4.1.2 GPU运算

第一次了解GPU运算是在第一篇博客PyTorch,简单的了解了一下。

深度学习可以通过 GPU 并行运算加速模型的训练。
PyTorch 是支持使用 GPU 并行运算的。但是能不能使用 GPU 加速运算还取决于硬件,支持 GPU 的硬件(显卡)一般是比较昂贵的。
如果你想让自己的程序能够自动识别 GPU 计算环境,并且在 GPU 不具备的情况下也能自动使用 CPU 正常运行,可以这么做:
这三个变量,之后会用来灵活判断是否需要采用 GPU 运算。

# 检测本机器是否安装GPU,将检测结果记录在布尔变量use_cuda中
use_cuda = torch.cuda.is_available()

# 当可用GPU的时候,将新建立的张量自动加载到GPU中
dtype = torch.cuda.FloatTensor if use_cuda else torch.FloatTensor
itype = torch.cuda.LongTensor if use_cuda else torch.LongTensor

4.2 数据预处理

该函数作用:将数据集中的某张图片打印出来。

def imshow(inp, title=None):
    # 将一张图打印显示出来,inp为一个张量,title为显示在图像上的文字

    # 一般的张量格式为:channels * image_width * image_height
    # 而一般的图像为 image_width * image_height * channels 
    # 所以,需要将张量中的 channels 转换到最后一个维度
    inp = inp.numpy().transpose((1, 2, 0)) 

    #由于在读入图像的时候所有图像的色彩都标准化了,因此我们需要先调回去
    mean = np.array([0.485, 0.456, 0.406])
    std = np.array([0.229, 0.224, 0.225])
    inp = std * inp + mean
    inp = np.clip(inp, 0, 1) 

    #将图像绘制出来
    plt.imshow(inp)
    if title is not None:
        plt.title(title)
    plt.pause(0.001)  # 暂停一会是为了能够将图像显示出来。

将训练数据集的第一个 batch 绘制出来:

#获取第一个图像batch和标签
images, labels = next(iter(train_loader))

# 将这个batch中的图像制成表格绘制出来
out = torchvision.utils.make_grid(images)

imshow(out, title=[train_dataset.classes[x] for x in labels])

4.3 创建模型

该实验先训练一个普通的卷积神经网络,但正确率勉强达到50%上下。模型预测的效果很差。因为该实验选用的是蚂蚁和蜜蜂的图像数据,本身就很难识别,简单的卷积神经网络应付不了这种复杂的情况。其次,该实验的图片训练样本只有244个,数量级太小。

代码略

简单卷积神经网络取得的效果:(黄色曲线是测试数据集错误率,蓝色曲线是训练数据集错误率。)

因此,这里提到使用“加载已训练好的 ResNet 进行迁移学习”。
ResNet 是微软亚洲研究院何凯明团队开发的一种极深的特殊的卷积神经网络。该网络的原始版本曾号称是“史上最深的网络”,有 152 层,在物体分类等任务上具有较高的准确度。

考虑到原始的 ResNet 具有较大的复杂性,在本次实验中,实际迁移的是一个具有 18 层的精简版的 ResNet。该网络由 18 个串联在一起的卷积模块构成,其中每一个卷积模块都包括一层卷积一层池化。下面将加载 ResNet 模型,并观察模型的组成部分。如果是第一次运行,那么模型会被下载到 ~/.torch/models/ 文件夹中。

torch.utils.model_zoo.load_url('http://labfile.oss.aliyuncs.com/courses/1073/resnet18-5c106cde.pth')
# 加载模型库中的residual network,并设置pretrained为true,这样便可加载相应的权重
net = models.resnet18(pretrained=True)
#如果存在GPU,就将网络加载到GPU上
net = net.cuda() if use_cuda else net
# 将网络的架构打印出来
net

从模型的组成部分中,可以看到最后有一层全连接层,也就是 (fc): Linear(in_features=512, out_features=1000)。

4.3.1 构建迁移模型

下面把 ResNet18 中的卷积模块作为特征提取层迁移过来,用于提取局部特征。同时,将 ResNet18 中最后的全连接层(fc)替换,构建一个包含 512 个隐含节点的全连接层,后接两个结点的输出层,用于最后的分类输出。
整个模型的前面大部分的结构都是 ResNet,最后两层被替换成了自定义的全连接层。

# 读取最后线性层的输入单元数,这是前面各层卷积提取到的特征数量
num_ftrs = net.fc.in_features

# 重新定义一个全新的线性层,它的输出为2,原本是1000
net.fc = nn.Linear(num_ftrs, 2)

#如果存在GPU则将网络加载到GPU中
net.fc = net.fc.cuda() if use_cuda else net.fc

criterion = nn.CrossEntropyLoss() #Loss函数的定义
# 将网络的所有参数放入优化器中
optimizer = optim.SGD(net.parameters(), lr = 0.0001, momentum=0.9)

4.3.2 训练模型+测试+绘制图表

在训练阶段,迁移过来的 ResNet 模块的结构和所有超参数都可以保持不变,但是权重参数则有可能被新的数据重新训练。是否要更新这些旧模块的权重参数完全取决于我们采取的迁移学习方式。
迁移学习主要有两种模式:预训练模式固定值模式
接下来会分别介绍

4.3.2.1 预训练模式

record = [] #记录准确率等数值的容器

#开始训练循环
num_epochs = 20
net.train(True) # 给网络模型做标记,标志说模型在训练集上训练
best_model = net
best_r = 0.0
for epoch in range(num_epochs):
    #optimizer = exp_lr_scheduler(optimizer, epoch)
    train_rights = [] #记录训练数据集准确率的容器
    train_losses = []
    for batch_idx, (data, target) in enumerate(train_loader):  #针对容器中的每一个批进行循环
        data, target = Variable(data), Variable(target) #将Tensor转化为Variable,data为图像,target为标签
        #如果存在GPU则将变量加载到GPU中
        if use_cuda:
            data, target = data.cuda(), target.cuda()
        output = net(data) #完成一次预测
        loss = criterion(output, target) #计算误差
        optimizer.zero_grad() #清空梯度
        loss.backward() #反向传播
        optimizer.step() #一步随机梯度下降
        right = rightness(output, target) #计算准确率所需数值,返回正确的数值为(正确样例数,总样本数)
        train_rights.append(right) #将计算结果装到列表容器中
        loss = loss.cpu() if use_cuda else loss
        train_losses.append(loss.data.numpy())


        #if batch_idx % 20 == 0: #每间隔100个batch执行一次
     #train_r为一个二元组,分别记录训练集中分类正确的数量和该集合中总的样本数
    train_r = (sum([tup[0] for tup in train_rights]), sum([tup[1] for tup in train_rights]))

    #在测试集上分批运行,并计算总的正确率
    net.eval() #标志模型当前为运行阶段
    test_loss = 0
    correct = 0
    vals = []
    #对测试数据集进行循环
    for data, target in val_loader:
        #如果存在GPU则将变量加载到GPU中
        if use_cuda:
            data, target = data.cuda(), target.cuda()
        data, target = Variable(data, requires_grad=True), Variable(target)
        output = net(data) #将特征数据喂入网络,得到分类的输出
        val = rightness(output, target) #获得正确样本数以及总样本数
        vals.append(val) #记录结果

    #计算准确率
    val_r = (sum([tup[0] for tup in vals]), sum([tup[1] for tup in vals]))
    val_ratio = 1.0*val_r[0].numpy()/val_r[1]

    if val_ratio > best_r:
        best_r = val_ratio
        best_model = copy.deepcopy(net)
    #打印准确率等数值,其中正确率为本训练周期Epoch开始后到目前撮的正确率的平均值
    print('训练周期: {} \tLoss: {:.6f}\t训练正确率: {:.2f}%, 校验正确率: {:.2f}%'.format(
        epoch, np.mean(train_losses), 100. * train_r[0].numpy() / train_r[1], 100. * val_r[0].numpy()/val_r[1]))       
    record.append([np.mean(train_losses), 1. * train_r[0].data.numpy() / train_r[1], 1. * val_r[0].data.numpy() / val_r[1]])

#绘制训练误差曲线
x = [x[0] for x in record]
y = [1 - x[1] for x in record]
z = [1 - x[2] for x in record]
#plt.plot(x)
plt.figure(figsize = (10, 7))
plt.plot(y)
plt.plot(z)
plt.xlabel('Epoch')
plt.ylabel('Error Rate')

测试模型,绘制分类效果

def visualize_model(model, num_images=6):
    images_so_far = 0
    fig = plt.figure(figsize=(15,10))

    for i, data in enumerate(val_loader):
        inputs, labels = data
        inputs, labels = Variable(inputs), Variable(labels)
        if use_cuda:
            inputs, labels = inputs.cuda(), labels.cuda()
        outputs = model(inputs)
        _, preds = torch.max(outputs.data, 1)
        preds = preds.cpu().numpy() if use_cuda else preds.numpy()
        for j in range(inputs.size()[0]):
            images_so_far += 1
            ax = plt.subplot( 2,num_images//2, images_so_far)
            ax.axis('off')

            ax.set_title('predicted: {}'.format(val_dataset.classes[preds[j]]))
            imshow(data[0][j])

            if images_so_far == num_images:
                return
visualize_model(net)

plt.ioff()
plt.show()

4.3.2.2 固定值模式

迁移过来的部分网络在结构和权重上都保持固定的数值不会改变。
要想让模型在固定值模式下训练,需要先定网络模型相关位置的参数。锁定的方法非常简单,只要把网络的梯度反传标志 requires_grad 设置为 False 就可以了。

# 加载residual网络模型
net = torchvision.models.resnet18(pretrained=True)
# 将模型放入GPU中
net = net.cuda() if use_cuda else net

# 循环网络,将所有参数设为不更新梯度信息
for param in net.parameters():
    param.requires_grad = False

# 将网络最后一层线性层换掉
num_ftrs = net.fc.in_features
net.fc = nn.Linear(num_ftrs, 2)
net.fc = net.fc.cuda() if use_cuda else net.fc

criterion = nn.CrossEntropyLoss() #Loss函数的定义
# 仅将线性层的参数放入优化器中
optimizer = optim.SGD(net.fc.parameters(), lr = 0.001, momentum=0.9)


#训练模型
record = [] #记录准确率等数值的容器

#开始训练循环
num_epochs = 4
net.train(True) # 给网络模型做标记,标志说模型在训练集上训练
best_model = net
best_r = 0.0
for epoch in range(num_epochs):
    #optimizer = exp_lr_scheduler(optimizer, epoch)
    train_rights = [] #记录训练数据集准确率的容器
    train_losses = []
    for batch_idx, (data, target) in enumerate(train_loader):  #针对容器中的每一个批进行循环
        data, target = Variable(data), Variable(target) #将Tensor转化为Variable,data为图像,target为标签
        if use_cuda:
            data, target = data.cuda(), target.cuda()
        output = net(data) #完成一次预测
        loss = criterion(output, target) #计算误差
        optimizer.zero_grad() #清空梯度
        loss.backward() #反向传播
        optimizer.step() #一步随机梯度下降
        right = rightness(output, target) #计算准确率所需数值,返回正确的数值为(正确样例数,总样本数)
        train_rights.append(right) #将计算结果装到列表容器中
        loss = loss.cpu() if use_cuda else loss
        train_losses.append(loss.data.numpy())


     #train_r为一个二元组,分别记录训练集中分类正确的数量和该集合中总的样本数
    train_r = (sum([tup[0] for tup in train_rights]), sum([tup[1] for tup in train_rights]))

    #在测试集上分批运行,并计算总的正确率
    net.eval() #标志模型当前为运行阶段
    test_loss = 0
    correct = 0
    vals = []
    #对测试数据集进行循环
    for data, target in val_loader:
        data, target = Variable(data, requires_grad=True), Variable(target)
        if use_cuda:
            data, target = data.cuda(), target.cuda()
        output = net(data) #将特征数据喂入网络,得到分类的输出
        val = rightness(output, target) #获得正确样本数以及总样本数
        vals.append(val) #记录结果

    #计算准确率
    val_r = (sum([tup[0] for tup in vals]), sum([tup[1] for tup in vals]))
    val_ratio = 1.0*val_r[0].numpy()/val_r[1]

    if val_ratio > best_r:
        best_r = val_ratio
        best_model = copy.deepcopy(net)
    #打印准确率等数值,其中正确率为本训练周期Epoch开始后到目前撮的正确率的平均值
    print('训练周期: {} \tLoss: {:.6f}\t训练正确率: {:.2f}%, 校验正确率: {:.2f}%'.format(
        epoch, np.mean(train_losses), 100. * train_r[0].numpy() / train_r[1], 100. * val_r[0].numpy()/val_r[1]))       
    record.append([np.mean(train_losses), 1. * train_r[0].data.numpy() / train_r[1], 1. * val_r[0].data.numpy() / val_r[1]])


# 绘制误差曲线
x = [x[0] for x in record]
y = [1 - x[1] for x in record]
z = [1 - x[2] for x in record]
#plt.plot(x)
plt.figure(figsize = (10, 7))
plt.plot(y)
plt.plot(z)
plt.xlabel('Epoch')
plt.ylabel('Error Rate')


#展示分类结果
visualize_model(best_model)

plt.ioff()
plt.show()

4.4 结论

该实验中,预训练迁移模型取得的效果整体的错误率比简单卷积神经网络低了很多。训练错误率可以稳定在 0.02 之下,测试错误率大约在 0.07 左右。因为在预训练模式下,模型对训练数据的拟合性比较强,所以训练错误率与测试错误率差别较大。
固定值迁移模式下,训练错误率可以在 0.02 ~ 0.04 之间,比预训练模式稍高。测试错误率大约在 0.07 左右,与预训练模式差不多。
因为固定值模式锁定了大部分权重,模型对训练数据的拟合性没那么强,所以训练错误率与测试错误率的差别也没那么大。

到此这篇关于PyTorch 迁移学习实战的文章就介绍到这了,更多相关PyTorch 迁移内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: PyTorch迁移学习实战

本文链接: https://www.lsjlt.com/news/177826.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • PyTorch迁移学习实战
    目录1. 实验环境2. 实验目的3. 相关原理4. 实验步骤4.1 数据收集4.2 数据预处理4.3 创建模型4.4 结论1. 实验环境 Jupyter NotebookPython...
    99+
    2023-01-15
    PyTorch 迁移
  • PyTorch深度学习实战(2)——PyTorch基础
    PyTorch深度学习实战(2)——PyTorch基础 0. 前言 1. 搭建 PyTorch 环境 2. PyTorch 张量 2....
    99+
    2023-09-04
    深度学习 pytorch python 原力计划
  • PyTorch一小时掌握之迁移学习篇
    目录概述为什么使用迁移学习更好的结果节省时间加载模型ResNet152冻层实现模型初始化获取需更新参数训练模型获取数据完整代码概述 迁移学习 (Transfer Learning) ...
    99+
    2022-11-12
  • 浅谈迁移学习
    目录一、背景二、定义及分类2.1、目标2.2、主要思想2.3、迁移学习的形式定义及一种分类方式三、关键点四、基于实例的迁移五、基于特征的迁移5.1、特征选择5.2、特征映射六、基于共...
    99+
    2022-11-12
  • oracle学习-数据迁移
    如果只是迁移表空间或者数据文件,可以先将表空间或者数据文件offline之后移动位置,并通过alert database rename 和 alter tablespace rename 将位置变化写入控制...
    99+
    2022-10-18
  • Pytorch卷积神经网络迁移学习的目标及好处
    目录前言一、经典的卷积神经网络二、迁移学习的目标三、好处四、步骤五、代码前言 在深度学习训练的过程中,随着网络层数的提升,我们训练的次数,参数都会提高,训练时间相应就会增加,我们今天...
    99+
    2022-11-11
  • PyTorch 迁移学习实践(几分钟即可训练好自己的模型)
    前言 如果你认为深度学习非常的吃GPU,或者说非常的耗时间,训练一个模型要非常久,但是你如果了解了迁移学习那你的模型可能只需要几分钟,而且准确率不比你自己训练的模型准确率低,本节我们...
    99+
    2022-11-12
  • 学习数据迁移之imp
    查询数据库语言及字符集select userenv('language') from dual;select * from nls_database_parameters...
    99+
    2022-10-18
  • PHP中如何进行迁移学习和模型迁移?
    随着机器学习在各个领域中的广泛应用,迁移学习和模型迁移已经成为了热门话题。在使用PHP进行机器学习时,如何进行迁移学习和模型迁移也成为了一个必须要考虑的问题。本文将介绍PHP中如何进行迁移学习和模型迁移,并提供一些实用的技巧和建议。什么是迁...
    99+
    2023-05-21
    迁移学习 PHP 模型迁移
  • 《PyTorch高级机器学习实战》包邮送书三本
    目录 前言书籍目录抽奖方式 前言 随着人工智能和机器学习的蓬勃发展,相关算法和技术已经广泛运用到诸多行业,大量的研究者和各行业人员也投入机器学习的研究与开发中。 掌握高级机器学习算法原理,...
    99+
    2023-09-07
    机器学习 pytorch 人工智能 python 原力计划
  • PyTorch深度学习实战(5)——计算机视觉基础
    PyTorch深度学习实战(5)——计算机视觉基础 0. 前言 1. 图像表示 2. 将图像转换为结构化数组 2.1 灰度图像表示 ...
    99+
    2023-09-07
    深度学习 pytorch 计算机视觉 原力计划
  • 深度学习Tensorflow 2.4 完成迁移学习和模型微调
    目录前言实现过程1. 获取数据2. 数据扩充与数据缩放3. 迁移学习4. 微调5. 预测前言 本文使用 cpu 的 tensorflow 2.4 完成迁移学习和模型微调,并使用训练...
    99+
    2023-01-06
    Tensorflow 迁移学习模型微调 Tensorflow 深度学习
  • python机器学习实战(一)
    原文链接:www.cnblogs.com/fydeblog/p/7140974.html 前言 这篇notebook是关于机器学习中监督学习的k近邻算法,将介绍2个实例,分别是使用k-近邻算法改进约会网站的效果和手写识别系统.操作系统:u...
    99+
    2023-01-31
    实战 机器 python
  • python机器学习实战(三)
    原文链接:www.cnblogs.com/fydeblog/p/7277205.html 前言 这篇博客是关于机器学习中基于概率论的分类方法--朴素贝叶斯,内容包括朴素贝叶斯分类器,垃圾邮件的分类,解析RSS源数据以及用朴素贝叶斯来分析不...
    99+
    2023-01-31
    实战 机器 python
  • PyTorch实现FedProx联邦学习算法
    目录I. 前言III. FedProx1. 模型定义2. 服务器端3. 客户端更新IV. 完整代码I. 前言 FedProx的原理请见:FedAvg联邦学习FedProx异质网络优化...
    99+
    2022-11-11
  • Pytorch实现LSTM案例总结学习
    目录前言模型构建部分主要工作1、构建网络层、前向传播forward()2、实例化网络,定义损失函数和优化器3、训练模型、反向传播backward()4、测试模型前言 关键步骤主要分为...
    99+
    2022-11-11
  • pyTorch深度学习softmax实现解析
    目录用PyTorch实现linear模型模拟数据集定义模型加载数据集optimizer模型训练softmax回归模型Fashion-MNISTcross_entropy模型的实现利用...
    99+
    2022-11-12
  • Python机器学习实战教程
    Python机器学习实战教程分享网盘地址——https://pan.baidu.com/s/1miIb4og 密码: wtiw课程真心不错,分享给大家机器学习(Machine Learning, ML)是一门多领域交叉学科,涉及概率论、统计...
    99+
    2023-01-31
    实战 机器 教程
  • Mysql实战45讲学习详情-
    大体来说,MySQL 可以分为 Server 层和存储引擎层两部分。         select * from T where ID=10; 这条查询语句的执行过程: 外部层:   用户与server层交互...
    99+
    2021-01-25
    Mysql实战45讲学习详情-
  • ElasticSearch学习之ESMapping实战示例
    目录什么是MappingMapping 属性字段类型(type)详解字符串类型数字类型日期类型布尔类型二进制类型范围类型复合数据类型数组类型对象类型嵌套类型地理数据类型地理坐标(ge...
    99+
    2023-01-31
    ElasticSearch ES Mapping ES Mapping
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作