计算机系统应用教程网站

网站首页 > 技术文章 正文

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

btikc 2024-10-12 11:02:43 技术文章 14 ℃ 0 评论

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

pytorch深度学习框架之tensor张量

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

本期文章的主要内容:

1、CNN卷积神经网络

2、torchvision.datasets

3、MINIST数据集

4、神经网络的训练

5、pytorch训练模型的保存

PyTorch 提供了许多预加载的数据集(例如 FashionMNIST),所有数据集都是torch.utils.data.Dataset 的子类,它们具有__getitem__和__len__实现的方法。因此,它们都可以传递给torch.utils.data.DataLoader 也可以使用torch.multiprocessing并行加载多个样本的数据 。例如:

以下是如何从 TorchVision加载Fashion-MNIST数据集的示例。Fashion-MNIST由 60,000 个训练示例和 10,000 个测试示例组成。每个示例都包含一个 28×28 灰度图像和来自 10 个类别之一的相关标签。

MINIST数据

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

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

每一个图片均为28×28像素,我们可以将其理解为一个二维数组的结构:

我们使用以下参数加载MNIST 数据集:

      • root ( string ) – 数据集所在MNIST/processed/training.ptMNIST/processed/test.pt存在的根目录。
      • train ( bool , optional ) – 如果为 True,则从 中创建数据集training.pt,否则从test.pt.
      • download ( bool , optional ) – 如果为 true,则从 Internet 下载数据集并将其放在根目录中。如果数据集已经下载,则不会再次下载。
      • transform ( callable , optional ) – 一个函数/转换,它接收一个 PIL 图像并返回一个转换后的版本。例如,transforms.RandomCrop
      • target_transform ( callable , optional ) – 一个接收目标并对其进行转换的函数/转换。
torchvision.datasets.MNIST( root: str ,
                           train: bool = True , 
                           transform: Optional[Callable] = None , 
  target_transform: Optional[Callable] = None , 
    download: bool = False )

所有数据集都有几乎相似的 API。它们都有两个共同的参数: transformtarget_transform,本期文章,我们基于MNIST数据集来写一个简单的神经网络,并进行神经网络的训练

下载数据集 torchvision.datasets

import torch
import torch.nn as nn
import torch.utils.data as Data
import torchvision  # 数据库模块
import matplotlib.pyplot as plt
# torch.manual_seed(1)  # reproducible
EPOCH = 20  # 训练整批数据次数,训练次数越多,精度越高
BATCH_SIZE = 50  # 每次训练的数据集个数
LR = 0.001  # 学习效率
DOWNLOAD_MNIST = False  # 如果你已经下载好了mnist数据就设置 False

# Mnist 手写数字 训练集
train_data = torchvision.datasets.MNIST(
    root='./data/',  # 保存或者提取位置
    train=True,  # this is training data
    transform=torchvision.transforms.ToTensor(),  # 转换 PIL.Image or numpy.ndarray 成tensor
    # torch.FloatTensor (C x H x W), 训练的时候 normalize 成 [0.0, 1.0] 区间
    download=DOWNLOAD_MNIST,  # 没下载就会自动下载数据集,当等于true
)
# Mnist 手写数字 测试集
test_data = torchvision.datasets.MNIST(
	root='./mnist/',
	train=False, # this is training data
)

通过以上代码,我们便在工程目录下的data文件夹下下载了MNIST的全部数据集,torchvision.datasets是pytorch为了方便研发者,进行了绝大部分的数据库的集合,通过torchvision.datasets可以很方便地下载使用其包含的数据集,其torchvision.datasets下面主要包含如下数据集,其他方面的数据集可以自行下载尝试

torchvision.datasets
Caltech
CelebA
CIFAR
Cityscapes
COCO
EMNIST
FakeData
Fashion-MNIST
Flickr
HMDB51
ImageNet
Kinetics-400
KITTI
KMNIST
LSUN
MNIST
Omniglot
PhotoTour
Places365
QMNIST
SBD
SBU
SEMEION
STL10
SVHN
UCF101
USPS
VOC
WIDERFace

CNN卷积神经网络搭建

# 批训练 50samples, 1 channel, 28x28 (50, 1, 28, 28)
train_loader = Data.DataLoader(dataset=train_data, batch_size=BATCH_SIZE, shuffle=True)
# 每一步 loader 释放50个数据用来学习
# 为了演示, 我们测试时提取2000个数据先
# shape from (2000, 28, 28) to (2000, 1, 28, 28), value in range(0,1)
test_x = torch.unsqueeze(test_data.data, dim=1).type(torch.FloatTensor)[:2000] / 255.  
test_y = test_data.targets[:2000]
#test_x = test_x.cuda() # 若有cuda环境,取消注释
#test_y = test_y.cuda() # 若有cuda环境,取消注释

# 定义神经网络
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

我们使用Data.DataLoader来加载我们下载好的MNIST数据集,并分开训练集与测试集

接下来我们建立一个CNN卷积神经网络:

第一层,我们输入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()前向传播神经网络进行输入图片的训练

通过以上的神经网络的搭建,我们便建立一个神经网络,此神经网络类似MINIST的双隐藏层结构

神经网络的训练

神经网络搭建完成后,我们便可以进行神经网络的训练

cnn = CNN() # 创建CNN
# cnn = cnn.cuda() # 若有cuda环境,取消注释
optimizer = torch.optim.Adam(cnn.parameters(), lr=LR)  
loss_func = nn.CrossEntropyLoss() 
for epoch in range(EPOCH):
    for step, (b_x, b_y) in enumerate(train_loader):  # 每一步 loader 释放50个数据用来学习
        #b_x = b_x.cuda() # 若有cuda环境,取消注释
        #b_y = b_y.cuda() # 若有cuda环境,取消注释
        output = cnn(b_x)  # 输入一张图片进行神经网络训练
        loss = loss_func(output, b_y)  # 计算神经网络的预测值与实际的误差
        optimizer.zero_grad()  #将所有优化的torch.Tensors的梯度设置为零
        loss.backward()  # 反向传播的梯度计算
        optimizer.step()  # 执行单个优化步骤
        if step % 50 == 0: # 我们每50步来查看一下神经网络训练的结果
            test_output = cnn(test_x)
            pred_y = torch.max(test_output, 1)[1].data.squeeze()
            # 若有cuda环境,使用84行,注释82行
            # pred_y = torch.max(test_output, 1)[1].cuda().data.squeeze()
            accuracy = float((pred_y == test_y).sum()) / float(test_y.size(0))
            print('Epoch: ', epoch, '| train loss: %.4f' % loss.data, 
            	'| test accuracy: %.2f' % accuracy)

首先我们使用CNN()函数进行神经网络的初始化,并建立一个神经网络模型,并利用optim.Adam优化函数建立一个optimizer神经网络优化器,torch.optim是一个实现各种优化算法的包。大部分常用的方法都已经支持,接口也足够通用,以后也可以轻松集成更复杂的方法。

常用的优化器主要有:
Optimizer
GradientDescentOptimizer
AdadeltaOptimizer
AdagradOptimizer
AdagradDAOptimizer
MomentumOptimizer
AdamOptimizer
FtrlOptimizer
ProximalGradientDescentOptimizer
ProximalAdagradOptimizer
RMSPropOptimizer

然后建立一个损失函数,我们神经网络的目的就是使用损失函数使神经网络的训练loss越来越小。然后进行神经网络的训练,我们每50步打印一下神经网络的训练效果

测试神经网络的结果与保存神经网络

# test 神经网络
test_output = cnn(test_x[:10])
pred_y = torch.max(test_output, 1)[1].data.squeeze()
# 若有cuda环境,使用92行,注释90行
#pred_y = torch.max(test_output, 1)[1].cuda().data.squeeze()
print(pred_y, 'prediction number')
print(test_y[:10], 'real number')
# save CNN
# 仅保存CNN参数,速度较快
torch.save(cnn.state_dict(), './model/CNN_NO1.pk')
# 保存CNN整个结构
#torch.save(cnn(), './model/CNN.pkl')

我们提取前10个MNIST的数据,并进行神经网络的预测,此时我们可以打印出来神经网络的预测值与实际值,最后并保存神经网络的模型,此模型我们可以直接使用来进行手写数字的识别

从训练结果可以看出,只训练了24*50个循环,神经网络的精度已经达到0.97

Epoch:  0 | train loss: 2.3018 | test accuracy: 0.18
Epoch:  0 | train loss: 0.5784 | test accuracy: 0.82
Epoch:  0 | train loss: 0.3423 | test accuracy: 0.89
Epoch:  0 | train loss: 0.1502 | test accuracy: 0.92
Epoch:  0 | train loss: 0.2063 | test accuracy: 0.93
Epoch:  0 | train loss: 0.1348 | test accuracy: 0.92
Epoch:  0 | train loss: 0.1209 | test accuracy: 0.95
Epoch:  0 | train loss: 0.0577 | test accuracy: 0.95
Epoch:  0 | train loss: 0.1297 | test accuracy: 0.95
Epoch:  0 | train loss: 0.0237 | test accuracy: 0.96
Epoch:  0 | train loss: 0.1275 | test accuracy: 0.97
Epoch:  0 | train loss: 0.1364 | test accuracy: 0.97
Epoch:  0 | train loss: 0.0728 | test accuracy: 0.97
Epoch:  0 | train loss: 0.0752 | test accuracy: 0.98
Epoch:  0 | train loss: 0.1444 | test accuracy: 0.97
Epoch:  0 | train loss: 0.0597 | test accuracy: 0.97
Epoch:  0 | train loss: 0.1162 | test accuracy: 0.97
Epoch:  0 | train loss: 0.0260 | test accuracy: 0.97
Epoch:  0 | train loss: 0.0830 | test accuracy: 0.97
Epoch:  0 | train loss: 0.1918 | test accuracy: 0.97
Epoch:  0 | train loss: 0.2217 | test accuracy: 0.97
Epoch:  0 | train loss: 0.0767 | test accuracy: 0.97
Epoch:  0 | train loss: 0.2015 | test accuracy: 0.97
Epoch:  0 | train loss: 0.1214 | test accuracy: 0.97
tensor([7, 2, 1, 0, 4, 1, 4, 9, 5, 9]) prediction number
tensor([7, 2, 1, 0, 4, 1, 4, 9, 5, 9]) real number

最后打印出来的前10个预测模型,完全一致

ok,本期我们分享了神经网络的搭建,并利用MNIST的数据集进行了神经网络的训练,并进行了神经网络的预测,下期文章我们利用训练好的模型进行神经网络的识别。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表