pytorch手写数字识别(CNN)

27 篇文章 8 订阅


一、前言

  1. 数据集是 MNIST手写数字 数据集,自取 https://download.csdn.net/download/weixin_43721000/87708518
  2. 网络结构为两层卷积两层线性层

二、实现方法

1.导包

import numpy as np 
import pandas as pd 

from matplotlib import pyplot as plt

import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader

2. 使用gpu

# 使用 GPU ----------------------------------------------
print(torch.cuda.is_available())
device = torch.device("cuda")
print(device)

3. 定义数据读取方法

# 定义数据读取类 ------------------------------------------
class MNISTDataset(Dataset):
    def __init__(self, data_type):
        self.data_type = data_type
        
        if self.data_type not in ['train', 'test']: raise Exception('数据集类型有误!')
        
        # 指定数据集路径
        if self.data_type == 'train':
            self.data_path = "/kaggle/input/digit-recognizer/train.csv"
        elif self.data_type == 'test':
            self.data_path = "/kaggle/input/digit-recognizer/test.csv"
        
        # 读取数据集
        df = pd.read_csv(self.data_path)
        
        # 标签和样本赋值
        if self.data_type == 'train':
            # 训练集标签与图片分割
            self.label = df['label'].to_numpy().reshape(-1, 1)
            self.image = df.drop(columns='label').to_numpy().reshape(-1, 1, 28, 28) / 255
        elif self.data_type == 'test':
            # 测试集没有标签,直接加载
            self.image = df.to_numpy().reshape(-1, 1, 28, 28) / 255

            
    def __len__(self):
        return len(self.image)
    
    
    def __getitem__(self, index):
        # 样本转为tensor
        image = torch.FloatTensor(self.image[index])
        
        # 标签转为模型输出格式(仅训练集有标签)
        if self.data_type == 'train':
            label = torch.zeros(10, dtype=torch.float)
            label[int(self.label[index])] = 1.0
            return image, label
        else:
            return image

# 训练集    
train_datasets = MNISTDataset("train")
train_dataloader = DataLoader(train_datasets, batch_size=100, shuffle=True)

# 测试集
test_datasets = MNISTDataset("test")
test_dataloader = DataLoader(test_datasets, batch_size=100, shuffle=False)

4.定义模型、损失函数、优化器

# 定义模型结构 -----------------------------------------
# 两个卷积加两个线性层的网络
class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        self.seq1 = nn.Sequential(
            nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1),  # 32个卷积核卷积,卷积后图片数量变为32,大小不变 (28-3+1)/1 + 1*2 = 28 
            nn.ELU(inplace=True),                                  # 激活函数
            nn.MaxPool2d(kernel_size=2, stride=2)                  # 宽高为2步长为2进行最大池化,图片宽高减半,变为 14
        )
        
        self.seq2 = nn.Sequential(
            nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1), # 64个卷积核卷积,卷积后图片数量变为64,大小不变 (14-3+1)/1 + 1*2 = 14 
            nn.ELU(inplace=True),                                  # 激活函数
            nn.MaxPool2d(kernel_size=2, stride=2)                  # 宽高为2步长为2进行最大池化,图片宽高减半,变为 7
        )
        
        self.seq3 = nn.Sequential(
            nn.Linear(7*7*64, 32, bias=True),                      # 64张图片像素点拉直输入全连接层
            nn.ELU(inplace=True),                                  # 激活函数
            nn.Linear(32, 10, bias=True),                          # 经过全连接输出10分类
            nn.ELU()                                               # 激活函数
        )
        
    def forward(self, x):
        x = self.seq1(x)
        x = self.seq2(x)
        x = x.view(x.size(0), -1)
        x = self.seq3(x)
        return x


# 初始化模型
model = SimpleCNN()
model = model.to(device)

# 定义损失函数(交叉熵)
criterion = nn.CrossEntropyLoss().to(device)

# 定义优化器(adam)
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

5.训练

# 训练 ----------------------------------------------------
# 记录每代平均损失值的数组
history_loss = []
# 迭代100次
EPOCH = 100
for epoch in range(EPOCH):
    loss_tmp = []
    for i, (image, label) in enumerate(train_dataloader):
        # 拿出一个批次的数据
        image, label = image.to(device), label.to(device)
        # 送入网络
        y_pred = model(image)
        # 计算损失
        loss = criterion(y_pred, label)
        # 梯度清零
        optimizer.zero_grad()
        # 反向传播
        loss.backward()
        # 梯度更新
        optimizer.step()
        # 记录损失值
        loss_tmp.append(loss.item())
        
    # 计算当前 EPOCH 的平均损失
    history_loss.append(np.mean(loss_tmp))
    print(f"\rEPOCH: [{epoch+1}/{EPOCH}], LOSS: {history_loss[-1]:1.6f}", end="")

6.绘制损失值图像

# 绘制每代平均损失值图像
plt.plot(history_loss, label="Cross Entropy Loss")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.legend()
plt.show()

在这里插入图片描述

7.预测

# 对所有测试集进行预测
result = []
for i, image in enumerate(test_dataloader):
    # 图片转到 GPU 上
    image = image.to(device)
    # 预测
    y_pred = model(image)
    label_pred = torch.argmax(y_pred, dim=1)
    # 预测结果转回cpu并加入数组
    result += label_pred.cpu().tolist()

8.绘制测试集图像与预测结果的对照图

# 绘制前 30 项预测结果
height, width = 5, 6
fig, axes = plt.subplots(height, width, figsize=(10, 10))

for i in range(height):
    for j in range(width):
        idx = height * i + j
        axes[i][j].imshow(test_datasets[idx][0], cmap='gray')
        axes[i][j].set_title(result[idx])
        axes[i][j].axis('off')

plt.show()

在这里插入图片描述

  • 27
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 25
    评论
PyTorch是一个开源的机器学习框架,可以用于构建深度学习模型。手写数字识别是一个常见的机器学习任务,可以使用PyTorch来实现。 首先,你需要准备训练和测试数据集。在PyTorch中,可以使用TorchVision库来加载和预处理数据。通过使用TorchVision的transforms模块,你可以对图像进行各种处理,比如转换为张量、裁剪或标准化。\[1\] 接下来,你可以使用TorchVision提供的MNIST数据集,它包含了大量的手写数字图像和对应的标签。你可以使用torchvision.datasets.MNIST来加载数据集,并使用transforms.Compose来组合多个数据处理操作。\[3\] 然后,你可以定义一个神经网络模型来进行手写数字识别。你可以使用PyTorch的torch.nn模块来构建模型。可以选择使用卷积神经网络(CNN)来提取图像特征,并使用全连接层进行分类。你可以定义一个继承自torch.nn.Module的类,并在其中定义模型的结构和前向传播方法。 在训练过程中,你可以使用PyTorch的torch.optim模块来选择优化算法,并使用torch.nn模块中的损失函数来计算模型的损失。通过迭代训练数据集,不断调整模型的参数,使得模型能够更好地预测手写数字。 最后,你可以使用训练好的模型对测试数据进行预测,并评估模型的性能。可以使用torch.utils.data.DataLoader来加载测试数据集,并使用模型的forward方法来进行预测。可以使用准确率等指标来评估模型的性能。 综上所述,你可以使用PyTorch来实现手写数字识别任务。通过加载和预处理数据集,定义模型结构,选择优化算法和损失函数,迭代训练数据集,最终得到一个能够准确预测手写数字的模型。 #### 引用[.reference_title] - *1* *2* [使用Pytorch实现手写数字识别](https://blog.csdn.net/Jennifer_Love_Frank/article/details/120162483)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [用PyTorch实现MNIST手写数字识别(非常详细)](https://blog.csdn.net/sxf1061700625/article/details/105870851)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

什么都干的派森

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值