6 卷积神经网络实现MNIST手写数字识别

代码实现了基本的CNN
共两层神经网络,包括两层卷积层两层池化层
使用的数据集为单通道28*28像素的MNIST数据集,共10个标签
训练集可直接在代码里下载
代码模块如下:

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms  # datasets模块封装了一些常用的数据集 transforms模块封装了一些图像预处理操作


# 构建网络模型
class CNN(nn.Module):

    # 初始化子类
    def __init__(self):

        # 继承父类属性
        super(CNN, self).__init__()  # 第一种继承方法 python2 python3通用
        # 构建第一层卷积神经网络
        self.conv1 = nn.Sequential(  # 输入大小(1, 28, 28)
            nn.Conv2d(               # 构建卷积层
                in_channels=1,       # 输入特征图数量 灰度图 一个
                out_channels=16,     # 输入特征图数量
                kernel_size=5,       # 卷积核大小
                stride=1,            # 步长
                padding=2,           # 边缘填充
            ),
            nn.ReLU(),               # relu层
            nn.MaxPool2d(kernel_size=2),  # 池化层
        )
        self.conv2 = nn.Sequential(nn.Conv2d(16, 32, 5, 1, 2), nn.ReLU(), nn.MaxPool2d(2))
        self.out = 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)  # flatten操作拉长
        output = self.out(x)
        return output


# 计算精度
def accuracy(predictions, labels):
    pr = torch.max(predictions.data, 1)[1]  # torch.max()函数返回[最大值, 索引] 这里只返回索引 dim=0时返回每行 dim=1时返回每列
    rights = pr.eq(labels.data.view_as(pr)).sum()  # eq()函数比较梁变量各个值是否相同 返回bool值 view_as()函数返回与函数内变量相同大小的格式 最后计算True的个数
    return rights, len(labels)


if __name__ == '__main__':

    # 定义超参数
    input_size = 28  # 图像的总尺寸为28*28
    num_classes = 10  # 标签的种类数
    num_epochs = 3  # 训练的总循环周期
    batch_size = 128  # 每批次的大小
    learning_rata = 0.001

    # 训练集 直接下载
    train_dataset = datasets.MNIST(root="./data", train=True, transform=transforms.ToTensor(), download=True)

    # 测试集 直接下载
    test_dataset = datasets.MNIST(root="./data", train=False, transform=transforms.ToTensor(), download=True)

    # 构建batch数据
    train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)  # 总数据量/batch_size
    test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True)

    # 初始化模型、损失函数、梯度下降函数三大类
    net = CNN()  # 初始化模型
    criterion = nn.CrossEntropyLoss()  # 初始化交叉熵损失函数 常用于多分类与二分类问题
    optimizer = torch.optim.Adam(net.parameters(), lr=learning_rata)  # 初始化梯度下降函数

    net.train()  # 训练模式
    for epoch in range(num_epochs):
        # 当前epoch的结果保存下来
        train_rights = []

        # 针对容器中的每一个批次进行循环
        for batch_idx, (train_data, train_target) in enumerate(train_loader):   # enumerate函数对列表进行排序并生成索引
            optimizer.zero_grad()  # 梯度归0
            train_output = net(train_data)  # 计算预测结果 输出格式为tensor
            loss = criterion(train_output, train_target)  # 将预测值与真实值带入损失函数计算损失值
            loss.backward()  # 反向传播
            optimizer.step()  # 沿梯度下降方向更新所有参数
            right = accuracy(train_output, train_target)  # 计算预测正确的个数
            train_rights.append(right)

            if batch_idx % 100 == 0:
                net.eval()
                val_rights = []

                for (test_data, test_target) in test_loader:
                    train_output = net(test_data)
                    right = accuracy(train_output, test_target)
                    val_rights.append(right)

                # 准确率计算
                train_r = (sum([tup[0] for tup in train_rights]), sum([tup[1] for tup in train_rights]))
                val_r = (sum([tup[0] for tup in val_rights]), sum([tup[1] for tup in val_rights]))

                # 打印训练信息
                print("当前epoch:{} [{}/{} ({:.0f}%)]\t损失:{:.6f}\t训练集准确率:{:.2f}%\t测试集正确率:{:.2f}%".format(
                    epoch, batch_idx * batch_size, len(train_loader.datasets), (100. * batch_idx / len(train_loader)),
                    loss.data, (100. * train_r[0].numpy() / train_r[1]), (100. * val_r[0].numpy() / val_r[1])))

MNIST训练集包含60000个像本,测试集包含10000个样本
训练了3个epoch,batch_size = 128, lr = 0.001
训练结果如下:
在这里插入图片描述
正确率达到了预期效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值