6.2pytorch图像的多分类--手写字体识别(代码片段)

王小小小草 王小小小草     2022-12-04     743

关键词:

欢迎订阅本专栏:《PyTorch深度学习实践》
订阅地址:https://blog.csdn.net/sinat_33761963/category_9720080.html

  • 第二章:认识Tensor的类型、创建、存储、api等,打好Tensor的基础,是进行PyTorch深度学习实践的重中之重的基础。
  • 第三章:学习PyTorch如何读入各种外部数据
  • 第四章:利用PyTorch从头到尾创建、训练、评估一个模型,理解与熟悉PyTorch实现模型的每个步骤,用到的模块与方法。
  • 第五章:学习如何利用PyTorch提供的3种方法去创建各种模型结构。
  • 第六章:利用PyTorch实现简单与经典的模型全过程:简单二分类、手写字体识别、词向量的实现、自编码器实现。
  • 第七章:利用PyTorch实现复杂模型:翻译机(nlp领域)、生成对抗网络(GAN)、强化学习(RL)、风格迁移(cv领域)。
  • 第八章:PyTorch的其他高级用法:模型在不同框架之间的迁移、可视化、多个GPU并行计算。

LeNet网络,做图像的同学肯定超级熟悉,这是1998年提出的一种卷积神经网络,当时风靡于手写数字识别。

关于它的理论知识于网络结构,可以参看我的博客:,也可以在网上搜索,有非常多的文章来介绍这个经典的模型。

Letent的模型结构由卷积-池化-卷积-池化-全连接-全连接-高斯连接这几个步骤组成。现在我们来一起看看如何构建LeNet,并进行手写数字的识别。

6.2.1 准备数据集

MINST是一个手写数字数据库,官网地址为:http://yann.kecun.com/exdb/mnist, 他是非常经典的一个数据集,由60000张训练样本,10000张测试样本,每张图片的尺寸是28*28。

由于这是一个很经典的用于学习和练习的数据集,PyTorch提供了快速下载和加载NIMIST数据集的方法,无需我们自己去官网下载了。torchvision就是PyTorch准们便些的处理图像的工具包,其中包含了图像预处理,加载等的方法,还包括一些经过预训练的经典卷积神经网络模型。现在我们来用Torchvision来下载、加载、预处理MINIST数据集。

import torch
from torchvision import datasets, transforms
import torch.utils.data as Data

# 转换特征
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,),(0.3081,))
])

# 下载、加载、预处理数据
trainset = datasets.MNIST('data', train=True, download=True, transform=transform)
testset = datasets.MNIST('data', train=False, download=True, transform=transform)

# 转换成批量迭代器:DataLoader
trainloader = torch.utils.data.dataLoader(trainset, batch_size=4, shuffle=True, num_work=2)
testloader = torch.utils.data.dataLoader(testset, batch_size=4, shuffle=False, num_work=2)

解释:

(1)torchvision.transforms.Compose()是用来设置预处理的方法,其参数是一个list,list中是预处理方法。

(2)datasets.MNIST()中,第一个参数是数据的路径,参数train设置是否下载加载训练集,download指是否需要去下载,下载后会保存再第一个参数设置的数据路径里,若无需下载则会去该路径下读取数据,tansform是传入前文设置好的预处理方法。如此设置后,程序会去自动下载数据并加载进来,然后根据transform中预处理方法的顺序去做数据的处理。

运行以上代码,代码所在目录下会多一个目录’data’,里面包含processed和raw文件夹,raw路径下是MNIST原始数据集,有4份,分别是训练集、测试机的图像数据与标签数据。

(3)DataLoader是将dataset作为输入,设置batch_size,生成一个迭代器,每次都会输出一批batch_size大小的数据,shuffle参数可以设置是否将原来的dataset打乱后输出数据,num_work是加载数据的子进程数目。在实际项目中,基本上都会使用批量随机梯度下降,因此dataLoader()非常常用。

6.2.2 构建LeNet模型

因为Lenet由好多层构成,因此选择nn.Module的subclass方式去构建模型结构。

  • nn.Conv2d 构建二维卷积层,有3个参数需要输入:in_channels为输入图片的个数,out_channels输出特征图的数目(卷积核的个数),kernel_size为卷积核的大小,本网络中为5·5的矩阵,可以携程(5,5)也可以直接写5,其他参数有默认值:stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode=‘zeros’
  • nn.Linear 构建线性层,in_features是输入的维度, out_features是输出的维度, 还有一个默认值的参数bias=True,表示需要偏置项b
import torch.nn as nn

class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        self.c1 = nn.Conv2d(1,6(5,5))
        self.c3 = nn.Conv2d(6,16,5) 
        self.fc1 = nn.Linear(16*4*4, 120)
        self.fc2 = nn.Linear(120,84)
        self.fc3 = nn.Linear(84,10)
    
    def forward(self, x):
        x = F.max_pool2d(F.relu(self.c1(x)), 2)
        x = F.max_pool2d(F.relu(self.c3(x)), 2)
        x = x.view(-1, self.num_flat_features(x))  # 拉平,使x变成2维矩阵,每个样本的特征拉平成一个维度,以方便之后的线性计算
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        
        return x
        
    def num_flat_features(self,x):
        "size的第一个维度是该批样本的数目,其他维度相乘为所有特征数目"
        size = x.size()[1:]
        num_features = 1
        for s in size:
            num_features *= s
        return num_features

回顾构建nn.Moduel的subclass的要点:

  • 必须继承nn.Module父类
  • 在__init__初始函数中创建layer即submodule,注意这里创建的layer都是有参数的,初始化实例的时候,这些参数也会被初始化,且默认使开启自动梯度计算的;而没有参数的激活函数relu则是直接在forward函数中被调用。
  • 必须定义一个forward函数,其中为模型前向计算的过程
  • num_flat_features是自己定义的函数
  • 对于Conv2d, Linear以及其他很多的submodule,可以在官网找到它们的用法:https://pytorch.org/docs/stable/nn.html#linear-layers

其他要点:

  • 卷积层、线性层中的参数一定要填正确,不理解的再去熟悉一下卷积、池化等计算过程,在其他实践中,一定要先手算一遍模型每层的参数维度,输入输出维度,以确保正确。
  • tensor.view()这个函数是用来变换张量维度的,-1表示在该维度上的值根据其他值自动计算,这个函数会经常被用到。
  • 这其实是一个多元分类的问题,既然是分类问题,最后一层全连接之后肯定要接一个softmax,但是上面的结构中却没有,而是直接返回了全连接的输出,别急,因为pytorch提供的交叉熵损失函数nn.CrossEntropyLoss()中包含了softamx这个步骤(4.6.2节中有单独讲解),等下会使用它。

6.2.3 实例化模型、损失、优化器

训练模型前的这三样东西缺一不可:

CUDA = torch.cuda.is_available()  # 查看是否有GPU

if cuda:
    lenet = LeNet().cuda()
else:
    lenet = LeNet
    
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(lenet.parameters(), rl=0.001, momentum=0.9)

要点讲解:

  • 判断是否有cuda,若有就要将model放到cuda上,以加速训练。建议大家在平时开发时也这样写代码,如此,无论在本机CPU开发还是放到GPU上训练,都无需改动代码。
  • nn.CrossEntropyLoss()这个损失函数,会在很多很多场合用到,无论时图像还是自然语言,所以pay attention.
  • torch.optim下还有很多优化器,你可以使用其他优化器做比较。

6.2.4 训练

好啦,万事俱备,只欠训练。训练还是老套路:

def train(model, criterion, optimizer, epochs=1):
    for epoch in epochs:
        running_loss = 0.0
        for i, data in enumerate(trainloader, 0):
            inputs, labels = data
            if CUDA:
                inputs, labels = inputs.cuda(), label.cuda()
                
            optimizer.zero_grad()
            
            outputs = model(inputs)
            
            loss = criterion(outputs, labels)
            loss.backward()
            
            running_loss += loss.item()
            if i % 999 == 0: # 每经过1000次batch的计算就打印一次平均损失
                print('epoch:%d, batch:%d, loss:%.3f' % (epoch+1, i+1, running_loss / 1000))
                
    print('finish training')
    
train(lenet, criterion, optimizer, epochs=2)
            

要点讲解:

  • 可以打印data出来看看是什么数据结构,其实是个二元组(inputs,labels)
  • 仍然使用了if CUDA的判断,若有GPU则将数据inputs, labels放到GPU上。记住,目前有两处是需要手动放到指定设备上的。

6.2.5存储与加载

在4.8节已经单独讲过模型的存储与加载的两种方法了。现在再来回顾一下:

(1)法1:直接存储加载模型
该方法直接又简洁,存储整个模型结构和参数,当模型很复杂的时候,这种方式会占用较大内存。

torch.save(lenet, 'model.pkl') # 存储
lenet = torch.load('model.pkl') # 加载

(2)法2:存储与加载模型参数
该方法直接保存参数,节省的空间,但它不存储模型结构,所以在加载时需要先构造好模型结构。不过这种方式时比较推荐大家使用的。

torch.save(lenet.state_dict(), 'model.pkl')
lenet.load_state_dict(torch.load('model.pkl'))

6.2.6测试

我们在4.4节讲解过训练过程中用验证集去做评估并且打印在训练集和验证集上的结果,以便动态实时查看模型的训练效果。在模型全部训练结束之后,或者已经保存之后,需要看看在额外测试集上的效果,就可以利用上面的方式加载模型进行测试。

6.2.1中已经加载了testset测试集了,也已经生成对应的dataloader了:

# 下载、加载、预处理数据
testset = datasets.MNIST('data', train=False, download=True, transform=transform)

# 转换成批量迭代器:DataLoader
testloader = torch.utils.data.dataLoader(testset, batch_size=4, shuffle=False, num_work=2)

现在开始测试与评估:

def test(testloader, model):
    correct = 0
    total = 0
    for data in testloader:
        inputs, labels = data
        if CUDA:
            inputs, labels = inputs.cuda(), labels.cuda()
        outputs = model(inputs)
        _, predicts = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicts == labels).sum()
    print('accurate on the testset: %d %%' % (100 * correct / total))
    
test(test_loader, lenet)
    

要点讲解:

  • 每个任务或模型都应该有一个既定的评估指标,从而量化模型的效果,这里采用的是准确率。关于各类量化指标的知识可以参考我的博客:https://blog.csdn.net/sinat_33761963/article/details/54910447
  • 当然咯,pytorch也提供了很多直接计算评估指标的函数,在之后会介绍。

总结

这一节讲CNN的经典模型LeNet的PyTorch实现。

  • 需要先具备卷积网络的知识,0基础的可以参看我的博客;https://blog.csdn.net/sinat_33761963/article/details/52893739,
    https://blog.csdn.net/sinat_33761963/article/details/80672556
  • 无需死记硬背代码,要掌握的是构建网络和训练的整体结构
  • 对于新出现的一些函数,要去理解它的功能,参数如何设置,为什么要这么做
  • 本文虽然讲解了很简单的LeNet模型,但完全可以举一反三,延伸到更复杂的模型的实现。

图像分类基于pytorch搭建lstm实现mnist手写数字体识别(双向lstm,附完整代码和数据集)(代码片段)

...sdn.net/AugustMe/article/details/128969138文章中,我们使用了基于PyTorch搭建LSTM实现MNIST手写数字体识别,LSTM是单向的,现在我们使用双向LSTM试一试效果,和之前的单向LSTM模型稍微有差别,请注意查看代码的变化。1.导入依赖库这些依赖... 查看详情

使用 PyTorch 的多标签、多类图像分类器 (ConvNet)

】使用PyTorch的多标签、多类图像分类器(ConvNet)【英文标题】:Multi-label,multi-classimageclassifier(ConvNet)withPyTorch【发布时间】:2018-12-0113:32:29【问题描述】:我正在尝试使用PyTorch实现一个图像分类器(CNN/ConvNet),我想从csv文件中读取... 查看详情

图像分类基于pytorch搭建lstm实现mnist手写数字体识别(单向lstm,附完整代码和数据集)(代码片段)

写在前面:首先感谢兄弟们的关注和订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。提起LSTM大家第一反应是在NLP的数据集上比较常见,不过在... 查看详情

[pytorch系列-29]:神经网络基础-全连接浅层神经网络实现10分类手写数字识别(代码片段)

作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客 本文网址:https://blog.csdn.net/HiWangWenBing/article/details/120607797目录前言深度学习模型框架第1章业务领域分析1.1 步骤1-1:... 查看详情

用pytorch实现多层感知机(mlp)(全连接神经网络fc)分类mnist手写数字体的识别(代码片段)

1.导入必备的包1importtorch2importnumpyasnp3fromtorchvision.datasetsimportmnist4fromtorchimportnn5fromtorch.autogradimportVariable6importmatplotlib.pyplotasplt7importtorch.nn.functionalasF8fromtorch.utils.da 查看详情

ai常用框架和工具丨13.pytorch实现基于cnn的手写数字识别

代码实例,PyTorch实现基于CNN的手写数字识别,希望对您有所帮助。文章目录环境说明一、模型训练1.1导入相关依赖1.2选择使用的硬件1.3超参数配置1.4准备训练集和测试集1.5模型创建1.6模型评估指标1.7模型训练1.8模型测试1.9模型... 查看详情

ai常用框架和工具丨13.pytorch实现基于cnn的手写数字识别

代码实例,PyTorch实现基于CNN的手写数字识别,希望对您有所帮助。文章目录环境说明一、模型训练1.1导入相关依赖1.2选择使用的硬件1.3超参数配置1.4准备训练集和测试集1.5模型创建1.6模型评估指标1.7模型训练1.8模型测试1.9模型... 查看详情

ai常用框架和工具丨13.pytorch实现基于cnn的手写数字识别

代码实例,PyTorch实现基于CNN的手写数字识别,希望对您有所帮助。文章目录环境说明一、模型训练1.1导入相关依赖1.2选择使用的硬件1.3超参数配置1.4准备训练集和测试集1.5模型创建1.6模型评估指标1.7模型训练1.8模型测试1.9模型... 查看详情

pytorch实现手写数字识别(代码片段)

PyTorch实现手写数字识别使用Pytorch实现手写数字识别1.思路和流程分析2.准备训练集和测试集2.1torchvision.transforms的图形数据处理方法2.1.1torchvision.transforms.ToTensor2.1.2torchvision.transforms.Normalize(mean,std)2.1.3torchvision.transforms.Com 查看详情

卷积神经网络手写数字识别(包含pytorch实现代码)(代码片段)

Hello!欢迎来到六个核桃Lu!运用卷积神经网络实现手写数字识别1算法分析及设计卷积神经网络:图1-2        如图1-2,卷积神经网络由若干个方块盒子构成,盒子从左到右仿佛越来越小,但却越来越厚... 查看详情

pytorch实现rnn网络对mnist字体分类(代码片段)

 我们知道,循环神经网络RNN非常擅长处理序列数据,但它也可以用来处理图像数据,这是因为一张图像可以看作一组由很长的像素点组成的序列。下面将会使用RNN对MNIST数据集建立分类器。目录1.准备数据集、定义数... 查看详情

图像分类---利用pytorch搭建alexnet网络模型训练自己的数据集(猫狗分类)(代码片段)

1数据准备    很多例子做图像分类的时候都喜欢用手写数字作为例子来讲解图像分类,这是一个及其不负责任的教学,我个人认为做深度学习有时候是要在数据集上下功夫的,而且因为很多框架都内置了手写数字数... 查看详情

各类场景应用中涉及的ai算法汇总

参考技术A整理了各类场景应用中AI算法一、图像CV内容安全,目标检测,图像识别,智能视觉生产,图像搜索,图像分割,物体检测,图像分类,图像标签,名人识别,概念识别,场景识别,物体识别,场景分析,智能相册,内... 查看详情

knn分类算法实现手写数字识别

...约有200个样本。?每个样本保持在一个txt文件中。?手写体图像本身的大小是32x32的二值图,转换到txt文件保存后,内容也是32x32个数字,0或者1,如下:数据集压缩包解压后有两个目录:(将这两个目录文 查看详情

基于pytorch框架实现手写图片的分类(代码片段)

...模型4,训练模型5,结果评价​编辑总结前言基于pytorch框架实现手写图片的分类🍨本文为🔗365天深度学习训练营中的学习记录博客🍦参考文章:Pytorch实战|第P4周:猴痘病识别🍖原作者:K同学... 查看详情

pytorch入门实战|第p1周:实现mnist手写数字识别

查看详情

keras入门实战:手写数字识别

...。深度学习已经在很多方面都成功得到了应用,尤其是在图像识别和分类领域,机器识别图像的能力甚至超过了人类。本文用深度学习Python库Keras实现深度学习入门教程mnist手写数字识别。mnist手写数字识别是机器学习和深度学习... 查看详情

手写数字识别基于matlabcnn网络手写数字识别分类含matlab源码1286期

...笔,只需要将大熊猫黑色的地方涂上黑色,一个大熊猫的图像就可以展现出来。我们画大熊猫的方式,其实和妈妈们的十字绣很接近——在给定的格子里,绣上不同的颜色,最后就可以展现出一幅特定的“图片”。而机器识图的... 查看详情