PyTorch基础入门六:PyTorch搭建卷积神经网络实现MNIST手写数字识别

本文介绍了卷积神经网络的基本概念及PyTorch中的实现方法,并通过一个MNIST手写数字识别的例子展示了如何构建和训练一个简单的CNN模型。

1)卷积神经网络(CNN)简介

关于什么是卷积神经网络(CNN),请自行查阅资料进行学习。如果是初学者,这里推荐一下台湾的李宏毅的深度学习课程。链接就不给了,这些资料网站上随处可见。

值得一提的是,CNN虽然在图像处理的领域具有不可阻挡的势头,但是它绝对不仅仅只能用来图像处理领域,大家熟知的alphaGo下围棋也可以通过CNN的结构进行处理,因为下围棋与图像有着相似之处,所以说,CNN提供给我们的是一种处理问题的思想,有学者归纳出了可以用CNN解决的问题所具备的三个性质:

  • 局部性

对于一张图片而言,需要检测图片中的特征来决定图片的类别,通常情况下这些特征都不是由整张图片决定的,而是由一些局部的区域决定的。例如在某张图片中的某个局部检测出了鸟喙,那么基本可以判定图片中有鸟这种动物。

  • 相同性

对于不同的图片,它们具有同样的特征,这些特征会出现在图片的不同位置,也就是说可以用同样的检测模式去检测不同图片的相同特征,只不过这些特征处于图片中不同的位置,但是特征检测所做的操作几乎一样。例如在不同的图片中,虽然鸟喙处于不同的位置,但是我们可以用相同的模式去检测。

  • 不变性

对于一张图片,如果我们进行下采样,那么图片的性质基本保持不变。

 

2)PyTorch中的卷积神经网络

简要介绍一下PyTorch中卷积神经网络中用到的一些方法。

  • 卷积层:nn.Conv2d()

其参数如下:

参数·含义
in_channels输入信号的通道数.
out_channels卷积后输出结果的通道数.
kernel_size卷积核的形状. 例如kernel_size=(3, 2)表示3X2的卷积核,如果宽和高相同,可以只用一个数字表示
stride卷积每次移动的步长, 默认为1.
padding 处理边界时填充0的数量, 默认为0(不填充).
dilation采样间隔数量, 默认为1, 无间隔采样.
groups输入与输出通道的分组数量. 当不为1时, 默认为1(全连接).
bias为 True 时, 添加偏置.

 

 

 

 

 

 

 

 

 

 

当然,这么多参数有一些是不常用的,读者只需要在实践中慢慢体会一些常用的即可,其他参数需要将理论打扎实之后去官网查阅。

  • 池化层:nn.MaxPool2d()

其参数如下:

参数含义
kernel_size最大池化操作时的窗口大小
stride最大池化操作时窗口移动的步长, 默认值是 kernel_size
padding 输入的每条边隐式补0的数量
dilation  用于控制窗口中元素的步长的参数
return_indices如果等于 True, 在返回 max pooling 结果的同时返回最大值的索引 这在之后的 Unpooling 时很有用
ceil_mode如果等于 True, 在计算输出大小时,将采用向上取整来代替默认的向下取整的方式

 

3)实现MNIST手写数字识别

一共定义了五层,其中两层卷积层,两层池化层,最后一层为FC层进行分类输出。其网络结构如下:

中间一行表示当前数据块的维度,第一个维度为深度,后面两个为宽度和高度。输入数据为灰度图,所以深度为1,图片像素为28*28的图片,后面经过卷积,池化,会发现深度不断加深,而宽度和高度会逐渐减少,因此,最后CNN处理过的图片只是一个局部的图片,换句话说,计算机在进行CNN对图片进行识别的时候,它通过观察图片局部的信息来进行分类的,这一点和我们通过人眼来观察图片进行分类是不一样的。

下面是CNN网络的代码实现:

# !/usr/bin/python
# coding: utf8
# @Time    : 2018-08-05 19:22
# @Author  : Liam
# @Email   : luyu.real@qq.com
# @Software: PyCharm
#                        .::::.
#                      .::::::::.
#                     :::::::::::
#                  ..:::::::::::'
#               '::::::::::::'
#                 .::::::::::
#            '::::::::::::::..
#                 ..::::::::::::.
#               ``::::::::::::::::
#                ::::``:::::::::'        .:::.
#               ::::'   ':::::'       .::::::::.
#             .::::'      ::::     .:::::::'::::.
#            .:::'       :::::  .:::::::::' ':::::.
#           .::'        :::::.:::::::::'      ':::::.
#          .::'         ::::::::::::::'         ``::::.
#      ...:::           ::::::::::::'              ``::.
#     ```` ':.          ':::::::::'                  ::::..
#                        '.:::::'                    ':'````..
#                     美女保佑 永无BUG
from torch import nn

class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Conv2d(1, 25, kernel_size=3),
            nn.BatchNorm2d(25),
            nn.ReLU(inplace=True)
        )

        self.layer2 = nn.Sequential(
            nn.MaxPool2d(kernel_size=2, stride=2)
        )

        self.layer3 = nn.Sequential(
            nn.Conv2d(25, 50, kernel_size=3),
            nn.BatchNorm2d(50),
            nn.ReLU(inplace=True)
        )

        self.layer4 = nn.Sequential(
            nn.MaxPool2d(kernel_size=2, stride=2)
        )

        self.fc = nn.Sequential(
            nn.Linear(50 * 5 * 5, 1024),
            nn.ReLU(inplace=True),
            nn.Linear(1024, 128),
            nn.ReLU(inplace=True),
            nn.Linear(128, 10)
        )

    def forward(self, x):
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        return x

然后利用上述模型进行处理,其处理的方法和上一篇博文中的方法是一样的,这里不再赘述。

可以看到处理结果比上一次好多了:

 

完整代码请移步GitHub

PyTorch 中构建卷积神经网络CNN)以识别 MNIST 手写数字数据集是一个经典的深度学习入门项目。以下是完整的实现流程,涵盖数据加载、模型定义、训练与测试以及结果可视化。 ### 数据加载和预处理 MNIST 数据集可以通过 `torchvision` 库直接下载,并利用 `DataLoader` 进行批量读取和打乱数据。以下代码展示了如何加载和预览部分图像: ```python import torch from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pyplot as plt import numpy as np # 定义数据预处理方式 transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) ]) # 加载训练集和测试集 train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform) test_dataset = datasets.MNIST(root='./data', train=False, download=True, transform=transform) train_loader = DataLoader(dataset=train_dataset, batch_size=64, shuffle=True) test_loader = DataLoader(dataset=test_dataset, batch_size=64, shuffle=False) # 可视化前20个图像 data_iter = iter(train_loader) images, labels = next(data_iter) plt.figure(figsize=(20, 5)) for i in range(20): plt.subplot(2, 10, i+1) npimg = np.squeeze(images[i].numpy()) plt.imshow(npimg, cmap=plt.cm.binary) plt.axis('off') plt.show() ``` ### 构建 CNN 模型 一个简单的 CNN 模型通常包含两个卷积层和两个全连接层,同时可以使用 Dropout 来防止过拟合。以下是具体实现: ```python import torch.nn as nn import torch.nn.functional as F class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(1, 10, kernel_size=5) # 输入通道为1(灰度图),输出通道为10 self.conv2 = nn.Conv2d(10, 20, kernel_size=5) self.conv2_drop = nn.Dropout2d() # 在第二个卷积层后加入Dropout self.fc1 = nn.Linear(320, 50) self.fc2 = nn.Linear(50, 10) def forward(self, x): x = F.relu(F.max_pool2d(self.conv1(x), 2)) # 卷积 -> 池化 -> ReLU x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2)) x = x.view(-1, 320) # 展平张量 x = F.relu(self.fc1(x)) x = self.fc2(x) return F.log_softmax(x, dim=1) model = Net() ``` ### 模型训练 在训练过程中,需要指定优化器(如 `Adam`)和损失函数(如 `NLLLoss`)。训练时需调用 `model.train()` 确保 Batch Normalization 和 Dropout 正常工作: ```python import torch.optim as optim # 定义损失函数和优化器 criterion = nn.NLLLoss() optimizer = optim.Adam(model.parameters(), lr=0.001) # 训练模型 epochs = 5 for epoch in range(epochs): running_loss = 0 model.train() # 设置模型为训练模式 for images, labels in train_loader: optimizer.zero_grad() output = model(images) loss = criterion(output, labels) loss.backward() optimizer.step() running_loss += loss.item() print(f"Epoch {epoch+1} - Training loss: {running_loss/len(train_loader)}") ``` ### 模型测试 测试阶段需要将模型设置为评估模式 (`model.eval()`),并计算准确率: ```python correct_count, all_count = 0, 0 model.eval() # 设置模型为评估模式 with torch.no_grad(): for images, labels in test_loader: output = model(images) preds = torch.argmax(output, dim=1) correct_count += (preds == labels).sum().item() all_count += len(labels) print(f"Test accuracy: {correct_count / all_count}") ``` ### 结果可视化 最后,展示一些测试样本及其预测结果: ```python # 测试并显示预测结果 data_iter = iter(test_loader) images, labels = next(data_iter) model.eval() output = model(images) preds = torch.argmax(output, dim=1) plt.figure(figsize=(20, 5)) for i in range(20): plt.subplot(2, 10, i+1) npimg = np.squeeze(images[i].numpy()) plt.imshow(npimg, cmap=plt.cm.binary) plt.title(f"{preds[i].item()}") plt.axis('off') plt.show() ``` 通过上述步骤,完成了基于 PyTorchCNNMNIST 手写数字识别任务,包括数据预处理、模型构建、训练、测试和结果可视化全过程。 ---
评论 30
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值