pytorch使用CNN实现MNIST手写体的识别

**MNIST数据集介绍:**MNIST数据集在torvision.datasets里面,可以自行加载,其中训练集有6W张,测试集有1W,都为灰度图,即channel为1,图片的大小都是28x28,下面图片就是一部分数据。
mnist数据集

导入工具包

import torch
from torch.autograd import Variable
import torch.nn as nn
import matplotlib.pyplot as plt
import torchvision
import torch.utils.data as Data

超参数设置

pyper parameter


"""
每次在训练集中提取64张图像进行批量化训练,目的是提高训练速度。
就好比搬砖,一次搬一块砖头的效率肯定要比一次能搬64块要低得多
"""
BATCH_SIZE = 64
#学习率,学习率一般为0.01,0.1等等较小的数,为了在梯度下降求解时避免错过最优解
LR = 0.001
"""
EPOCH 假如现在我有1000张训练图像,因为每次训练是64张,
每当我1000张图像训练完就是一个EPOCH,训练多少个EPOCH自己决定
"""
EPOCH = 1
"""
现在我要训练的训练集是系统自带的,需要先下载数据集,
当DOWNLOAD_MNIST为True是表示学要下载数据集,一但下载完,保存
然后这个参数就可以改为False,表示不用再次下载
"""
DOWNLOAD_MNIST = True

读取训练集

torchvision里面有许多的数据集,现在就要下载MNIST数据集,就是手写体数字

root表示下载到哪个目录下
train表示下载的是训练集,而不是测试集
tranform格式转换为tensor
download是否要下载


train_data = torchvision.datasets.MNIST(
    root='./mnist',
    train = True,
    transform=torchvision.transforms.ToTensor(),
    download=DOWNLOAD_MNIST
)

划分训练集

loader将训练集划分为n个64的集合,方便每次取64个,当最后不足64时,将剩下的归为一个集合里

datase需要划分的数据集
batch_size按多少划分
shuffle是否要打乱数据,一般打乱对结果有一个更好的影响
num_workers表示需要多少个核进行操作

train_loader = Data.DataLoader(dataset=train_data, batch_size=BATCH_SIZE, shuffle=True, num_workers=2 )
#每个batch_size的shape为[64, 1, 28, 28]

测试集读取

#测试集操作和上面注释一样
test_data = torchvision.datasets.MNIST(
    root='./mnist',
    train = False,
)

对测试集处理


test_x = Variable(torch.unsqueeze(test_data.test_data, dim=1), volatile=True).type(torch.FloatTensor)[:2000]/255.0
"""
test_data.test_data中的shape为[10000, 28, 28]代表1w张图像,都是28x28,当时并未表明channels,因此在unsqueeze在1方向想加一个维度,
则shape变为[10000, 1, 28, 28],然后转化为tensor的float32类型,取1w张中的2000张,并且将其图片进行归一化处理,避免图像几何变换的影响
"""
#标签取前2000
test_y = test_data.test_labels[:2000]

定义网络结构

#定义网络结构
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        #前面都是规定结构
        #第一个卷积层,这里使用快速搭建发搭建网络
        self.conv1 = nn.Sequential(
            nn.Conv2d(
                in_channels=1,#灰度图,channel为一
                out_channels=16,#输出channels自己设定
                kernel_size=3,#卷积核大小
                stride=1,#步长
                padding=1#padding=(kernel_size-stride)/2   往下取整
            ),
            nn.ReLU(),#激活函数,线性转意识到非线性空间
            nn.MaxPool2d(kernel_size=2)#池化操作,降维,取其2x2窗口最大值代表此窗口,因此宽、高减半,channel不变
        )
        #此时shape为[16, 14, 14]
        self.conv2 = nn.Sequential(
            nn.Conv2d(
                in_channels=16,
                out_channels=32,
                kernel_size=3,
                stride=1,
                padding=1
            ),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2)
        )
        #此时shape为[32, 7, 7]
        #定义全连接层,十分类,并且全连接接受两个参数,因此为[32*7*7, 10]
        self.prediction = nn.Linear(32*7*7, 10)
        #前向传播过程
    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = x.view(x.size(0), -1)
        output = self.prediction(x)
        return output

实例化model,并且定义优化器以及损失函数

#创建网络
cnn = CNN()

#大数据常用Adam优化器,参数需要model的参数,以及学习率
optimizer = torch.optim.Adam(cnn.parameters(), LR)
#定义损失函数,交叉熵
loss_func = nn.CrossEntropyLoss()

训练

#训练阶段
for epoch in range(EPOCH):
    #step,代表现在第几个batch_size
    #batch_x 训练集的图像
    #batch_y 训练集的标签
    for step, (batch_x, batch_y) in enumerate(train_loader):
        #model只接受Variable的数据,因此需要转化
        b_x = Variable(batch_x)
        b_y = Variable(batch_y)
        #将b_x输入到model得到返回值
        output = cnn(b_x)
        print(output)
        #计算误差
        loss = loss_func(output, b_y)
        #将梯度变为0
        optimizer.zero_grad()
        #反向传播
        loss.backward()
        #优化参数
        optimizer.step()
        #打印操作,用测试集检验是否预测准确
        if step%50 == 0:
            test_output = cnn(test_x)
            #squeeze将维度值为1的除去,例如[64, 1, 28, 28],变为[64, 28, 28]
            pre_y = torch.max(test_output, 1)[1].data.squeeze()
            #总预测对的数除总数就是对的概率
            accuracy = float((pre_y == test_y).sum()) / float(test_y.size(0))
            print("epoch:", epoch, "| train loss:%.4f" % loss.data, "|test accuracy:%.4f" %accuracy)

到目前为止所有代码已经贴完,也就是一个完整的卷积神经网络已经实现,接下来就是与代码,等代结果。
是不是觉得很简单!
下面是我运行结果
在这里插入图片描述
可以看出来准确率可以达到97.65%,已经是一个很好结果了,目前为止所有过程都已经完成了。
下面我吧完整代码贴在后面

import torch
from torch.autograd import Variable
import torch.nn as nn
import matplotlib.pyplot as plt
import torchvision
import torch.utils.data as Data

#pyper parameter
"""
每次在训练集中提取64张图像进行批量化训练,目的是提高训练速度。
就好比搬砖,一次搬一块砖头的效率肯定要比一次能搬64块要低得多
"""
BATCH_SIZE = 64
#学习率,学习率一般为0.01,0.1等等较小的数,为了在梯度下降求解时避免错过最优解
LR = 0.001
"""
EPOCH 假如现在我有1000张训练图像,因为每次训练是64张,
每当我1000张图像训练完就是一个EPOCH,训练多少个SEPOCH自己决定
"""
EPOCH = 1
"""
现在我要训练的训练集是系统自带的,需要先下载数据集,
当DOWNLOAD_MNIST为True是表示学要下载数据集,一但下载完,保存
然后这个参数就可以改为False,表示不用再次下载
"""
DOWNLOAD_MNIST = True

"""torchvision里面有许多的数据集,现在就要下载MNIST数据集,就是手写体数字"""
"""
root表示下载到哪个目录下
train表示下载的是训练集,而不是测试集
tranform格式转换为tensor
download是否要下载
"""
train_data = torchvision.datasets.MNIST(
    root='./mnist',
    train = True,
    transform=torchvision.transforms.ToTensor(),
    download=DOWNLOAD_MNIST
)
#loader将训练集划分为n个64的集合,方便每次取64个,当最后不足64时,将剩下的归为一个集合里
"""
datase需要划分的数据集
batch_size按多少划分
shuffle是否要打乱数据,一般打乱对结果有一个更好的影响
num_workers表示需要多少个核进行操作
"""
#每个batch_size的shape为[64, 1, 28, 28]
train_loader = Data.DataLoader(dataset=train_data, batch_size=BATCH_SIZE, shuffle=True, num_workers=2 )
#测试集操作和上面一样
test_data = torchvision.datasets.MNIST(
    root='./mnist',
    train = False,
)
#定义网络结构
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        #前面都是规定结构
        #第一个卷积层,这里使用快速搭建发搭建网络
        self.conv1 = nn.Sequential(
            nn.Conv2d(
                in_channels=1,#灰度图,channel为一
                out_channels=16,#输出channels自己设定
                kernel_size=3,#卷积核大小
                stride=1,#步长
                padding=1#padding=(kernel_size-stride)/2   往下取整
            ),
            nn.ReLU(),#激活函数,线性转意识到非线性空间
            nn.MaxPool2d(kernel_size=2)#池化操作,降维,取其2x2窗口最大值代表此窗口,因此宽、高减半,channel不变
        )
        #此时shape为[16, 14, 14]
        self.conv2 = nn.Sequential(
            nn.Conv2d(
                in_channels=16,
                out_channels=32,
                kernel_size=3,
                stride=1,
                padding=1
            ),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2)
        )
        #此时shape为[32, 7, 7]
        #定义全连接层,十分类,并且全连接接受两个参数,因此为[32*7*7, 10]
        self.prediction = nn.Linear(32*7*7, 10)
        #前向传播过程
    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = x.view(x.size(0), -1)
        output = self.prediction(x)
        return output
#创建网络
cnn = CNN()

#大数据常用Adam优化器,参数需要model的参数,以及学习率
optimizer = torch.optim.Adam(cnn.parameters(), LR)
#定义损失函数,交叉熵
loss_func = nn.CrossEntropyLoss()
#训练阶段
for epoch in range(EPOCH):
    #step,代表现在第几个batch_size
    #batch_x 训练集的图像
    #batch_y 训练集的标签
    for step, (batch_x, batch_y) in enumerate(train_loader):
        #model只接受Variable的数据,因此需要转化
        b_x = Variable(batch_x)
        b_y = Variable(batch_y)
        #将b_x输入到model得到返回值
        output = cnn(b_x)
        print(output)
        #计算误差
        loss = loss_func(output, b_y)
        #将梯度变为0
        optimizer.zero_grad()
        #反向传播
        loss.backward()
        #优化参数
        optimizer.step()
        #打印操作,用测试集检验是否预测准确
        if step%50 == 0:
            test_output = cnn(test_x)
            #squeeze将维度值为1的除去,例如[64, 1, 28, 28],变为[64, 28, 28]
            pre_y = torch.max(test_output, 1)[1].data.squeeze()
            #总预测对的数除总数就是对的概率
            accuracy = float((pre_y == test_y).sum()) / float(test_y.size(0))
            print("epoch:", epoch, "| train loss:%.4f" % loss.data, "|test accuracy:%.4f" %accuracy)
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页