【Pytorch图像分类】搭建卷积神经网络(CNN)和使用迁移学习(Transfer Learning)实现图片识别

2023-05-16

1. 摘要

图像分类,也可以称作图像识别,顾名思义,就是辨别图像中的物体属于什么类别。核心是从给定的分类集合中给图像分配一个标签的任务。实际上,这意味着我们的任务是分析一个输入图像并返回一个将图像分类的标签。在这里,我们将分别自己搭建卷积神经网路、迁移学习分别对图像数据集进行分类。本篇使用的数据集下载地址为:
链接:https://pan.baidu.com/s/1mS4xIf1sr3mhYn-cJNMqjQ
提取码:k57i
在这里插入图片描述
Pytorch_datasets文件夹底下包括两个文件夹存放各自的图片数据集。在这里插入图片描述

2.搭建卷积神经网络实现图像分类

卷积神经网络与普通的神经网络的区别在于,卷积神经网络包含了一个卷积层convolutional layer和池化层pooling layer构成的特征提取器。卷积神经网路中每层卷积层由若干卷积单元组成,每个卷积单元的参数都是通过反向传播算法优化得到的。卷积运算的目的是提取输入的不同特征,第一层卷积层可能只能提取一些低级的特征如边缘、线条和角等层级,更多层的网络能从低级特征中迭代提取更复杂的特征。池化层(Pooling layer),通常在卷积层之后会得到维度很大的特征,将特征切成几个区域,取其最大值或平均值,得到新的、维度较小的特征。
在这里插入图片描述
如上图左,全连接神经网络是一个“平面”,包括输入层—激活函数—全连接层,右图的卷积神经网络是一个“立体”,包括输入层—卷积层—激活函数—池化层—全连接层。卷积神经网络提取的数据量更大,因此常用在图像处理上。
接下来,我们自己搭建神经网络对上面同样的数据集进行分类

  1. 首先,导入相应的包
import os
import torch 
from torch import nn,optim
from torch.nn import functional as F
from torch.utils import data
from torchvision import datasets,transforms
  1. 图像数据预处理
train_path = "./pytorch_datasets/train"
test_path = "./pytorch_datasets/test"

#定义数据集预处理的方法
data_transform = transforms.Compose([
#         transforms.Resize((224,224)),
        transforms.RandomResizedCrop(150),
        transforms.ToTensor(),
        transforms.Normalize((0.1307,),(0.3081,))
])

datasets_train = datasets.ImageFolder(train_path,data_transform)
datasets_test = datasets.ImageFolder(test_path,data_transform)

train_loader = data.DataLoader(datasets_train,batch_size=32,shuffle=True)
test_loader = data.DataLoader(datasets_test,batch_size=16,shuffle=False)
  1. pytorch搭建卷积神经网络
#搭建网络
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Conv2d(3, 32, 3)
        self.max_pool1 = nn.MaxPool2d(2)
        self.conv2 = nn.Conv2d(32, 64, 3)
        self.max_pool2 = nn.MaxPool2d(2)
        self.conv3 = nn.Conv2d(64, 128, 3)
        self.max_pool3 = nn.MaxPool2d(2)
        self.conv4 = nn.Conv2d(128, 128, 3)
        self.max_pool4 = nn.MaxPool2d(2)
        self.fc1 = nn.Linear(6272, 512)
        self.fc2 = nn.Linear(512, 1)
        
    def forward(self, x):
        in_size = x.size(0)
        x = self.conv1(x)
        x = F.relu(x)
        x = self.max_pool1(x)
        x = self.conv2(x)
        x = F.relu(x)
        x = self.max_pool2(x)
        x = self.conv3(x)
        x = F.relu(x)
        x = self.max_pool3(x)
        x = self.conv4(x)
        x = F.relu(x)
        x = self.max_pool4(x)
        # 展开
        x = x.view(in_size, -1)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.fc2(x)
        x = torch.sigmoid(x)
        return x
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(DEVICE)
model = CNN().to(DEVICE)
optimizer = optim.Adam(model.parameters(),lr=0.0001)

在这里插入图片描述

  1. 对图像数据集进行训练30次,打印损失
for epoch in range(30):
    model.train()
    for i,(image,label) in enumerate(train_loader):
        data,target = Variable(image).cuda(),Variable(label.cuda()).unsqueeze(-1)
        optimizer.zero_grad()
        output = model(data)
        output=output.to(torch.float32)
        target=target.to(torch.float32)
#         print(output.shape,target.shape)
        loss = F.binary_cross_entropy(output,target)
        loss.backward()
        optimizer.step()
        if (i+1)%10==0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
            epoch, (i+1) * len(data), len(train_loader.dataset),
            100. * (i+1) / len(train_loader), loss.item()))

在这里插入图片描述

  1. 对测试集数据进行验证评估,打印精确度
for epoch in range(30):
    model.eval()
    test_loss = 0
    correct = 0
    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(DEVICE), target.to(DEVICE).float().unsqueeze(-1)
            output = model(data)
            test_loss += F.binary_cross_entropy(output, target, reduction='sum').item() # 将一批的损失相加
            pred = torch.tensor([[1] if num[0] >= 0.5 else [0] for num in output]).to(DEVICE)
            correct += pred.eq(target.long()).sum().item()
        print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        100. * correct / len(test_loader.dataset)))

在这里插入图片描述

3.迁移学习实现图像分类

问题来了?什么是迁移学习?迁移学习(Transfer learning) 顾名思义就是把已训练好的模型(预训练模型)参数迁移到新的模型来帮助新模型训练。考虑到大部分数据或任务都是存在相关性的,所以通过迁移学习我们可以将已经学到的模型参数(也可理解为模型学到的知识)通过某种方式来分享给新模型从而加快并优化模型的学习效率不用像大多数网络那样从零学习。其中,实现迁移学习有以下三种手段:
1.Transfer Learning:冻结预训练模型的全部卷积层,只训练自己定制的全连接层。
2.Extract Feature Vector:先计算出预训练模型的卷积层对所有训练和测试数据的特征向量,然后抛开预训练模型,只训练自己定制的简配版全连接网络。
3.Fine-tuning:冻结预训练模型的部分卷积层(通常是靠近输入的多数卷积层,因为这些层保留了大量底层信息)甚至不冻结任何网络层,训练剩下的卷积层(通常是靠近输出的部分卷积层)和全连接层。
预训练模型有很多,本文选用InceptionV3预训练模型,它是由谷歌团队从ImageNet的1000个类别的超大数据集训练而来的,表现优异,经常用来做计算机视觉方面的迁移学习研究和应用。
在这里插入图片描述

  1. 同样,首先导入所需要的包
from sklearn.model_selection import train_test_split
import numpy as np
import os
from tqdm import tqdm
from PIL import Image
import torch
import torchvision.datasets
import torchvision.transforms as transforms
import torchvision.models as models
  1. 图片数据预处理
trainpath = "./pytorch_datasets/train"
testpath = "./pytorch_datasets/test"
batch_size = 16

traintransform = transforms.Compose([transforms.RandomRotation(20),
                                     transforms.ColorJitter(brightness=0.1),
                                     transforms.Resize([224,224]),
                                    transforms.ToTensor()])
valtransform = transforms.Compose([transforms.Resize([224,224]),
                                 transforms.ToTensor()])

trainData = torchvision.datasets.ImageFolder(trainpath,transform=traintransform)
testData = torchvision.datasets.ImageFolder(testpath,transform=valtransform)

trainLoader = torch.utils.data.DataLoader(dataset=trainData,batch_size=batch_size,shuffle=True)
testLoader = torch.utils.data.DataLoader(dataset=testData,batch_size=batch_size,shuffle=False)
  1. 微调模型进行训练
model = models.resnet34(pretrained=True)
model.fc = torch.nn.Linear(512,2)
  1. 定义损失函数和优化器
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(),lr=0.0001)
  1. 进行训练数据集
from torch.autograd import Variable
import time
train_loss = []
valid_loss = []
accuracy = []
for epoch in range(100):
    epoch_start_time = time.time()
    model.train()
    total_loss = 0
    train_corrects = 0
    for i,(image,label) in enumerate(trainLoader):
        image = Variable(image.cuda())
        label = Variable(label.cuda())
   
        model.cuda()
        target = model(image)
        loss = criterion(target,label)
        
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        total_loss += loss.item()
        max_value,max_index = torch.max(target,1)
        pred_label = max_index.cpu().numpy()
        true_label = label.cpu().numpy()
        train_corrects += np.sum(pred_label==true_label)
        
    loss = total_loss/float(len(trainLoader))
    train_acc = train_corrects/100
    train_loss.append(loss)
for epoch in range(100):
    model.eval()
    corrects = eval_loss = 0
    with torch.no_grad():
        for image,label in testLoader:
            image = Variable(image.cuda())
            label = Variable(label.cuda())
            model.cuda()
            pred = model(image)
            loss = criterion(pred,label)
            eval_loss += loss.item()
            max_value,max_index = torch.max(pred,1)
            pred_label = max_index.cpu().numpy()
            true_label = label.cpu().numpy()
            corrects += np.sum(pred_label==true_label)
    loss = eval_loss/float(len(testLoader))
    acc = corrects/100
    valid_loss.append(loss)
    accuracy.append(acc)
import matplotlib.pyplot as plt
print("**********ending*********")
plt.plot(train_loss)
plt.plot(valid_loss)
plt.title('loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Pytorch图像分类】搭建卷积神经网络(CNN)和使用迁移学习(Transfer Learning)实现图片识别 的相关文章

  • 不要再使用 Gitee 当图床了,官方已经开启防盗链了

    如果你正在使用或打算使用 Gitee 作为图床 xff0c 那么请不要这么做或打消该念头 近日 xff0c Gitee 官方已经开启防盗链 正在使用 Gitee 当图床的小伙伴或许已经发现所有的图片都已经变成了 Gitee 的 Logo 了
  • 基于BP神经网络的人脸朝向识别

    一 数字图像处理 1 1 问题假设 所给的全部人脸图像都未出现损坏等问题 xff1b 人脸的朝向仅分为5类 xff1a 左 中左 中间 中右 右 xff0c 其他朝向不予考虑 xff1b 对于题目中所给的人脸图像 xff0c 不考虑人脸的复
  • ::在c++中的意思

    在c 43 43 中 一 作用域符号 xff1a xff1a 前面是类名称 xff0c 后面一般是该类的成员名称 例类A中包含member1 A member1 二 全局作用域符号 用于区分全局变量和局部变量 xff1a xff1a cha
  • linux下cannot execute binary file: Exec format error解决办法

    对于linux下cannot execute binary file Exec format error明确说明是执行文件格式错误 xff0c 可能情况 xff1a 1 使用错误的命令 xff0c 如gcc c hello c o hell
  • PX4/Pixhawk---uORB深入理解和应用(最新版)

    1 简介 ps 第1章简介是参考 uORB深入理解和应用 1 1 PX4 Pixhawk的软件体系结构 PX4 Pixhawk的软件体系结构主要被分为四个层次 xff0c 这可以让我们更好的理解PX4 Pixhawk的软件架构和运作 xff
  • 深拷贝和浅拷贝的区别

    1 简单理解 深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体 xff0c 而不是引用 假设B复制了A xff0c 修改A的时候 xff0c 看B是否发生变化 xff1a 如果B跟着也变了 xff0c 说明是浅拷贝 xff0c
  • Linux系统下搭建PX4/Pixhawk原生固件编译环境

    对于新版本的固件V1 11 3 在pixhawk官网可以找到开发环境的搭建 xff0c 这里把开发环境链接贴出来 xff1a https docs px4 io master zh dev setup dev env linux ubunt
  • Pixhawk无人机飞行模式详解 (PX4源码)

    我帮大家把飞行模式控制量与特点总结一下 xff0c 方便看代码 xff0c 如下所示 xff1a 辅助模式 Position Mode 位置模式 xff08 定点模式 xff09 横滚俯仰控制角度 xff0c 油门控制上下速度 xff0c
  • pixhawk无人机避障

    本人最近用树莓派结合PX4做无人机避障 xff0c 使用激光雷达 xff0c 有没有一起的小伙伴 xff0c 我们一起交流 xff01 私信我 xff0c
  • 目录前导符不一致解决办法

    最近弄毕业设计 xff0c 写完论文以后发现生成的目录后面的前导码省略号数目 间距不一致 xff0c 非常的难看 xff0c 于是经过仔细研究找到了解决办法 xff1a 首先是问题所在 xff0c 请看下图 xff1a 首先在word中打开
  • 几种编码方式(RZ、NRZ、NRZI、曼彻斯特编码)

    在数字电路中 xff0c 组成一连串信息的基元就是0和1 xff0c 无论是在CPU DSP MCU甚至是个数字计数器中 xff0c 数字电路在其中能够处理的信息也只有0和1 xff0c 而对于任何外界的信息 xff0c 计算机都能通过两个
  • WIN10运行软件,窗口不显示 解决办法

    win10 运行软件后 xff0c 不显示窗口 今天遇到个问题 xff0c 我打开软碟通之后 xff0c 任务栏显示它已经打开了 xff0c 但是窗口就是不显示 xff0c 如下图 xff1a 用alt 43 tab 查看 xff0c 也能
  • 变频器的四大组成部分和工作原理

    随着电子技的发展变频器已经有了很大的变化 xff0c 但其基本原理并没有发生改变 变频器的主要部分有四个 xff1a 整流器 中间电路 逆变器 控制电路 1 xff09 整流器 通用变频器的整流电路是由三相桥式整流桥组成 它的功能是将工频电
  • Pytorch中torch的操作合集

    tensor的基本操作 PyTorch系例 torch Tensor详解和常用操作 这里最重要的概念是索引出来的结果与原数据共享内存 xff0c 也即修改一个 xff0c 另一个也会跟着修改 tensor的广播机制 Pytorch xff1
  • torch.tensor 内存共享机制

    tensor属于可变数据类型 xff0c 因此变量的值存储在堆中 xff0c 变量名存储在栈中 xff0c 当进行变量赋值时 xff0c 就是让栈中的变量指向堆 xff0c 如下面代码 xff1a span class token keyw
  • 熵 KL散度 交叉熵的理解

    熵 KL散度 交叉熵的概念 xff1a 理解二分类交叉熵 可视化的方法解释对数损失交叉熵公式推导 xff1a 理解交叉熵作为损失函数在神经网络中的作用熵 KL散度 交叉熵的关系 xff1a KL散度与交叉熵区别与联系训练过程中三者的应用 x
  • Docker数据目录迁移解决方案

    介绍 在docker的使用中随着下载镜像越来越多 xff0c 构建镜像 运行容器越来越多 数据目录必然会逐渐增大 xff1b 当所有docker镜像 容器对磁盘的使用达到上限时 xff0c 就需要对数据目录进行迁移 如何避免 xff1a 1
  • Git 三剑客 ———— git gui 可视化工具

    目录 页面介绍Unstaged changesStaged Changes xff08 Will Commit xff09 File DisplayCommand Set Repository 操作区Edit 操作区Branch 操作区Co
  • 数组对象转json格式

    1 数组转化成JSON对象后 xff0c key值是索引 xff0c value是数组对应的值 数组也可以转化成JSON对象 var jStr3 61 34 10 20 30 40 50 60 34 var j3 61 JSON parse
  • JS——DOM的结点操作

    H5自定义属性 自定义属性目的 目的 xff1a 是为了保存并且使用数据 有些数据可以把保存到页面中而不用保存到数据库 可以通过getAttribute获取 自定义属性 xff1a data 开头 这是一种规范 dataset xff1a

随机推荐