百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

pytorch利用CNN卷积神经网络来识别手写数字

toyiye 2024-09-01 05:43 3 浏览 0 评论

pytorch——人工智能的开源深度学习框架

pytorch深度学习框架之tensor张量

计算机视觉的基石——读懂 CNN卷积神经网络

使用MNIST数据集训练第一个pytorch CNN手写数字识别神经网络

上期文章我们分享了使用MINIST数据集训练第一个CNN卷积神经网络,并保存了预训练模型,本期我们基于上期的模型,进行神经网络的识别

MINIST数据

MINIST的数据分为2个部分:55000份训练数据(mnist.train)和10000份测试数据(mnist.test)。这个划分有重要的象征意义,他展示了在机器学习中如何使用数据。在训练的过程中,我们必须单独保留一份没有用于机器训练的数据作为验证的数据,它能确保训练的结果的可行性。

前面已经提到,每一份MINIST数据都由图片以及标签组成。我们将图片命名为“x”,将标记数字的标签命名为“y”。训练数据集和测试数据集都是同样的结构,例如:训练的图片名为 mnist.train.images 而训练的标签名为 mnist.train.labels。

每一个图片均为28×28像素,我们可以将其理解为一个二维数组的结构,这里重点强调一下MINIST数据集是黑底白字,这里在识别数字的时候需要转换一下自己的数据图片,一般我们的照片时白底黑字,这里在调试代码时也遇到了类似的问题,神经网络总是识别错误

CNN卷积神经网络搭建

首先按照上期的代码搭建一下我们的CNN 卷积神经网络

import torch
import torch.nn as nn
from PIL import Image  # 导入图片处理工具
import PIL.ImageOps
import numpy as np
from torchvision import transforms
import cv2
import matplotlib.pyplot as plt
# 定义神经网络
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Sequential(  # input shape (1, 28, 28)
            nn.Conv2d(
                in_channels=1,  # 输入通道数
                out_channels=16,  # 输出通道数
                kernel_size=5,  # 卷积核大小
                stride=1,  #卷积步数
                padding=2,  # 如果想要 con2d 出来的图片长宽没有变化, 
                            # padding=(kernel_size-1)/2 当 stride=1
            ),  # output shape (16, 28, 28)
            nn.ReLU(),  # activation
            nn.MaxPool2d(kernel_size=2),  # 在 2x2 空间里向下采样, output shape (16, 14, 14) )
        self.conv2 = nn.Sequential(  # input shape (16, 14, 14)
            nn.Conv2d(16, 32, 5, 1, 2),  # output shape (32, 14, 14)
            nn.ReLU(),  # activation
            nn.MaxPool2d(2),  # output shape (32, 7, 7) )
        self.out = nn.Linear(32 * 7 * 7, 10)  # 全连接层,0-9一共10个类
# 前向反馈
    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = x.view(x.size(0), -1)  # 展平多维的卷积图成 (batch_size, 32 * 7 * 7)
        output = self.out(x)
        return output

第一层,我们输入minist的数据集,minist的数据图片是一维 28*28的图片,所以第一层的输入(1,28,28),高度为1,设置输出16通道,使用5*5的卷积核对图片进行卷积运算,每步移动一格,为了避免图片尺寸变化,设置pading为2,则经过第一层卷积就输出(16,28,28)数据格式

再经过relu与maxpooling (使用2*2卷积核)数据输出(16,14,14)

第二层卷积层是简化写法nn.Conv2d(16, 32, 5, 1, 2)的第一个参数为输入通道数in_channels=16,其第二个参数是输出通道数out_channels=32, # n_filters(输出通道数),第三个参数为卷积核大小,第四个参数为卷积步数,最后一个为pading,此参数为保证输入输出图片的尺寸大小一致

        self.conv2 = nn.Sequential(  # input shape (16, 14, 14)
            nn.Conv2d(16, 32, 5, 1, 2),  # output shape (32, 14, 14)
            nn.ReLU(),  # activation
            nn.MaxPool2d(2),  # output shape (32, 7, 7)
        )

全连接层,最后使用nn.linear()全连接层进行数据的全连接数据结构(32*7*7,10)以上便是整个卷积神经网络的结构,

大致为:input-卷积-Relu-pooling-卷积-Relu-pooling-linear-output

卷积神经网络建完后,使用forward()前向传播神经网络进行输入图片的训练

初始化图片数据

file_name = '2.png'  # 导入自己的图片
img = Image.open(file_name)
plt.imshow(img)
plt.show()
img = img.convert('L')
plt.imshow(img)
plt.show()
img = PIL.ImageOps.invert(img)
plt.imshow(img)
plt.show()
train_transform = transforms.Compose([
       transforms.Grayscale(),
         transforms.Resize((28, 28)),
         transforms.ToTensor(),
 ])
img = train_transform(img)
img = torch.unsqueeze(img, dim=0)

首先我们需要导入我们需要识别的图片,在数字图像处理中,针对不同的图像格式有其特定的处理算法。所以,在做图像处理之前,我们需要考虑清楚自己要基于哪种格式的图像进行算法设计及其实现。本文基于这个需求,使用python中的图像处理库PIL来实现不同图像格式的转换。




img = img.convert('L'):模式“L”

此转换为PIL灰色图像,它的每个像素用8个bit表示,0表示黑,255表示白,其他数字表示不同的灰度。在PIL中,从模式“RGB”转换为“L”模式是按照下面的公式转换的:

L = R * 299/1000 + G * 587/1000+ B * 114/1000

转换到灰度空间后,这里便是最重要的一步img = PIL.ImageOps.invert(img)

把照片的像素值翻转,把0的地方换成1,1的地方换成0,这就成为了MINIST数据的要求

这里我们可以通过plt.show()函数查看一下当前图片的效果

这是我们要识别的图片,可以看到是白底黑字的效果,若不经过图片的处理,神经网络无法进行正确的识别,通过2值化图片转换后的效果如下图,变成了MINIST数据要求的图片格式,黑底白字

转换图片到torch

train_transform = transforms.Compose([
       transforms.Grayscale(),
         transforms.Resize((28, 28)),
         transforms.ToTensor(),
 ])

img = train_transform(img)
img = torch.unsqueeze(img, dim=0)

我们转换图片到白字黑底后,我们需要把图片转换到pytorch能够识别的数据模式,这里采用的是transforms.Compose函数统一所有的变换

变换是常见的图像处理操作。可以使用 将它们链接在一起Compose。大多数转换类都有一个等价的函数:函数式转换对转换进行细粒度控制。大多数转换都接受PIL 图像和张量图像,尽管有些转换是PIL-only,有些是tensor-only。该转换变换可以被用于转换和从PIL图像。transforms函数里面有很多图片转换的函数,包含

  • Grayscale:将图像转换为灰度。如果图像是 Torch Tensor,则它应该具有 [..., 3, H, W] 形状,其中 ... 表示任意数量的前导维度
  • Resize:将输入图像调整为给定的大小。如果图像是 Torch Tensor,则它应该具有 [..., H, W] 形状,其中 ... 表示任意数量的前导维度
  • ToTensor:转换为张量。此转换不支持 torchscript。如果 PIL 图像,则将 [0, 255] 范围内的 PIL 图像或 numpy.ndarray (H x W x C) 转换为 [0.0, 1.0] 范围内形状 (C x H x W) 的 torch.FloatTensor到其中一种模式(L、LA、P、I、F、RGB、YCbCr、RGBA、CMYK、1)或者 numpy.ndarray dtype = np.uint8
  • ToPILImage:将张量或 ndarray 转换为 PIL Image。此转换不支持 torchscript。将 Torch.*Tensor 形状 C x H x W 或形状 H x W x C 的 numpy ndarray 转换为 PIL 图像,同时保留值范围。
  • CenterCrop:在中心裁剪给定的图像。如果图像是 Torch Tensor,则它应该具有 [..., H, W] 形状,其中 ... 表示任意数量的前导维度。如果图像尺寸沿任何边缘小于输出尺寸,图像用 0 填充,然后中心裁剪。
  • ColorJitter:随机改变图像的亮度、对比度、饱和度和色调。如果图像是 Torch Tensor,则它应该具有 [..., 3, H, W] 形状,其中 ... 表示任意数量的前导维度。如果 img 是 PIL Image,则不支持模式“1”、“L”、“I”、“F”和具有透明度(alpha 通道)的模式。
  • Normalize:使用均值和标准差对张量图像进行归一化。此转换不支持 PIL 图像。给定 mean:(mean[1],...,mean[n])和 std:(std[1],..,std[n])对于n 通道,此变换将标准化输入的每个通道, torch.*Tensor即, output[channel] = (input[channel] - mean[channel]) / std[channel]

pytorch通过一系列的转换,便可以把输入的图片转换成功神经网络需要的格式

神经网络的识别

model = CNN()
model.load_state_dict(torch.load('./model/CNN_NO1.pk',map_location='cpu'))
model.eval()

index_to_class = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

with torch.no_grad():
    y = model(img)
    output = torch.squeeze(y)
    predict = torch.softmax(output, dim=0)
    print(predict)
    predict_cla = torch.argmax(predict).numpy()
    print(predict_cla)
print(index_to_class[predict_cla], predict[predict_cla].numpy())

图片输出预处理完成后,我们便可以使用神经网络模型进行预测

首先我们要初始化神经网络,并使用torch.load函数加载我们上期文章训练完成的神经网络,map_location我们指定为CPU,当然若有GPU ,可以使用GUP运行代码

model.load_state_dict(torch.load('./model/CNN_NO1.pk',map_location='cpu'))

由于MNIST数据集只有0-9个数字,我们设置一个list存放这10个值

Python 有多种机制可以在本地禁用梯度计算:要在整个代码块中禁用渐变,有上下文管理器,如 no-grad 模式和推理模式。为了从梯度计算中更细粒度地排除子图,可以设置requires_grad张量。这里主要的好处是可以 节省大量的内存,我们只是为了测试我们的神经网络,可以采用类似做法。

然后我们把图片传入神经网络进行预测,我们可以计算出神经网络的预测结果与置信度

tensor([2.3575e-05, 2.2012e-03, 2.9602e-02, 1.7745e-02, 1.5333e-01, 3.1148e-03,
        1.2766e-03, 2.0447e-02, 4.6207e-02, 7.2605e-01])
9
9 0.7260508

运行以上代码,神经网络会输出每个值的预测置信度,我们从中挑选出置信度最大的。

相关推荐

# Python 3 # Python 3字典Dictionary(1)

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中,格式如...

Python第八课:数据类型中的字典及其函数与方法

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值...

Python中字典详解(python 中字典)

字典是Python中使用键进行索引的重要数据结构。它们是无序的项序列(键值对),这意味着顺序不被保留。键是不可变的。与列表一样,字典的值可以保存异构数据,即整数、浮点、字符串、NaN、布尔值、列表、数...

Python3.9又更新了:dict内置新功能,正式版十月见面

机器之心报道参与:一鸣、JaminPython3.8的热乎劲还没过去,Python就又双叒叕要更新了。近日,3.9版本的第四个alpha版已经开源。从文档中,我们可以看到官方透露的对dic...

Python3 基本数据类型详解(python三种基本数据类型)

文章来源:加米谷大数据Python中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。在Python中,变量就是变量,它没有类型,我们所说的"类型"是变...

一文掌握Python的字典(python字典用法大全)

字典是Python中最强大、最灵活的内置数据结构之一。它们允许存储键值对,从而实现高效的数据检索、操作和组织。本文深入探讨了字典,涵盖了它们的创建、操作和高级用法,以帮助中级Python开发...

超级完整|Python字典详解(python字典的方法或操作)

一、字典概述01字典的格式Python字典是一种可变容器模型,且可存储任意类型对象,如字符串、数字、元组等其他容器模型。字典的每个键值key=>value对用冒号:分割,每个对之间用逗号,...

Python3.9版本新特性:字典合并操作的详细解读

处于测试阶段的Python3.9版本中有一个新特性:我们在使用Python字典时,将能够编写出更可读、更紧凑的代码啦!Python版本你现在使用哪种版本的Python?3.7分?3.5分?还是2.7...

python 自学,字典3(一些例子)(python字典有哪些基本操作)

例子11;如何批量复制字典里的内容2;如何批量修改字典的内容3;如何批量修改字典里某些指定的内容...

Python3.9中的字典合并和更新,几乎影响了所有Python程序员

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

Python3大字典:《Python3自学速查手册.pdf》限时下载中

最近有人会想了,2022了,想学Python晚不晚,学习python有前途吗?IT行业行业薪资高,发展前景好,是很多求职群里严重的香饽饽,而要进入这个高薪行业,也不是那么轻而易举的,拿信工专业的大学生...

python学习——字典(python字典基本操作)

字典Python的字典数据类型是基于hash散列算法实现的,采用键值对(key:value)的形式,根据key的值计算value的地址,具有非常快的查取和插入速度。但它是无序的,包含的元素个数不限,值...

324页清华教授撰写【Python 3 菜鸟查询手册】火了,小白入门字典

如何入门学习python...

Python3.9中的字典合并和更新,了解一下

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

python3基础之字典(python中字典的基本操作)

字典和列表一样,也是python内置的一种数据结构。字典的结构如下图:列表用中括号[]把元素包起来,而字典是用大括号{}把元素包起来,只不过字典的每一个元素都包含键和值两部分。键和值是一一对应的...

取消回复欢迎 发表评论:

请填写验证码