首页/新闻资讯/正文详情

Pytorch实现mnist手写数字识别

发布时间:2026/11/15 14:58:25 来源:云帆数科 栏目:资讯中心
Pytorch实现mnist手写数字识别
- ** 本文为[365天深度学习训练营](https://mp.weixin.qq.com/s/o-DaK6aQQLkJ8uE4YX1p3Q) 中的学习记录博客**- ** 原作者[K同学啊](https://mtyjkh.blog.csdn.net/)**前言这次是CNN实操流程为数据导入、数据可视化、构建CNN网络、设置超参数、编写训练函数、编写测试函数、正式训练、结果可视化。实验MNIST手写数字数据集来源于是美国国家标准与技术研究所是著名的公开数据集之一。数据集中的数字图片是由250个不同职业的人纯手写绘制数据集获取的网址为Index of /exdb/mnist下载后需解压。我们一般会采用(train_images, train_labels), (test_images, test_labels) datasets.mnist.load_data()这行代码直接调用这样就比较简单。代码实现1.设置GPUimport torch import torch.nn as nn import matplotlib.pyplot as plt import torchvision device torch.device(cuda if torch.cuda.is_available() else cpu) device2.导入数据train_ds torchvision.datasets.MNIST(data, # 数据存放目录当前目录下的 data 文件夹 trainTrue, # 加载训练集6 万张图 transformtorchvision.transforms.ToTensor(), # 把 PIL 图片转成 Tensor数值归一化到 [0,1] downloadTrue) # 本地没有就自动从网上下载 test_ds torchvision.datasets.MNIST(data, trainFalse, transformtorchvision.transforms.ToTensor(), downloadTrue)两条语句的区别只有一处不同——train参数train_ds训练集6 万张用于模型学习参数梯度下降更新权重test_ds测试集1 万张从未参与训练用于评估模型泛化能力batch_size 32 # 每批取 32 个样本 train_dl torch.utils.data.DataLoader(train_ds, # 数据源上一段的训练集 Dataset batch_sizebatch_size, # 每次取 32 张图打包成一个 batch shuffleTrue) # 每个 epoch 前打乱顺序训练必须打乱 test_dl torch.utils.data.DataLoader(test_ds, batch_sizebatch_size) # 测试集不打乱保证评估结果可复现 # 取一个批次查看数据格式 # 数据的shape为[batch_size, channel, height, weight] # 其中batch_size为自己设定channelheight和weight分别是图片的通道数高度和宽度。 imgs, labels next(iter(train_dl)) imgs.shape这段代码在上一段的基础上把 Dataset 打包成可分批、可打乱的 DataLoader数据加载器​是 PyTorch 训练流程的第二步。iter(train_dl) — 把 DataLoader 变成迭代器想象成一摞排好队的 batchnext(...) — 从迭代器里取出第一个 batch解包成 imgs图像张量和 labels对应的数字标签imgs.shape 查看这个 batch 的形状torch.Size([32, 1, 28, 28])四个维度分别是第 1 维32-batch_size —— 本批 32 张图第 2 维1-通道数灰度图只有 1 个通道彩色 RGB 是 3第 3 维28——高 28 像素第 4 维28——宽 28 像素。对应的 labels 形状是 [32]即 32 个 0~9 的整数。batch批​神经网络不是一张一张学而是一批一批算——既利用 GPU 并行又让梯度估计更稳定shuffleTrue每轮打乱防止模型记住样本顺序比如前 3 万张恰好都是同一类测试不打乱评估时顺序无所谓不打乱便于结果复现和对比一句话总结DataLoader 负责把 6 万张散装图片整理成“每批 32 张的传送带”next(iter(...)) 是从传送带上取第一箱货验一下货的规格 [32, 1, 28, 28] 是否符合预期。import numpy as np # 指定图片大小图像大小为20宽、5高的绘图(单位为英寸inch) plt.figure(figsize(20, 5)) for i, imgs in enumerate(imgs[:20]): # img 是第 i 张图单张shape [1,28,28] npimg np.squeeze(imgs.numpy()) # 去掉通道维 → [28,28] # 将整个figure分成2行10列绘制第i1个子图。 plt.subplot(2, 10, i1) plt.imshow(npimg, cmapplt.cm.binary) plt.axis(off)这段代码是把刚取出的那个 batch 里的前 20 张手写数字图画成 2 行 × 10 列的网格用来“肉眼验收”数据是否加载正确。plt.figure(figsize(20, 5))新建一张“画布”宽 20 英寸、高 5 英寸。20:5 4:1 的横长比例正好容纳 2 行 × 10 列的小图。单位是英寸实际显示像素还取决于 dpi默认 100即约 2000×500 像素。np.squeeze(img.numpy())img.numpy() — 把 PyTorch 张量转成 numpy 数组matplotlib 不认识 torch 张量np.squeeze() — 去掉所有长度为 1 的维度[1, 28, 28] → [28, 28]不降维的话imshow 会报错或画错因为它只接受二维灰度或三维 H×W×C彩色数组plt.subplot(2, 10, i1)把画布切成 2 行 × 10 列 20 个格子并把画笔定位到第 i1 个格子从 1 开始计数从左到右、从上到下编号。下次画图就落在那个格子里不会互相覆盖。plt.imshow(npimg, cmapplt.cm.binary)imshow — 在当前子图上绘制图像cmapplt.cm.binary — 使用二值灰度映射0黑→ 255白。MNIST 里数字笔画是白、背景是黑这样显示出来就是“黑底白字”和你看到的数据集预览图一致想要“白底黑字”更接近手写体可改用 cmapgray_rplt.axis(off)关闭坐标轴刻度和边框。默认 imshow 会显示 0~27 的像素坐标轴关掉后小图更干净纯看数字。#类的定义框架 import torch.nn.functional as F num_classes 10 # 图片的类别数 class Model(nn.Module): def __init__(self): super().__init__() #所有 PyTorch 网络都要继承 nn.Module #super().__init__() 初始化父类注册参数、显存管理等机制才能生效 # 特征提取网络 self.conv1 nn.Conv2d(1, 32, kernel_size3) # 第一层卷积输入 1 个通道灰度图→ 输出 32 个通道32 个 3×3 卷积核每个核学会提取一种特征如边缘、拐角。输出通道数可以理解为“这一层学出了 32 种特征图”。 self.pool1 nn.MaxPool2d(2) # 设置池化层2×2 最大池化每 2×2 区域只保留最大值 → 图像宽高减半。作用是压缩尺寸、保留显著特征、增强平移鲁棒性。 self.conv2 nn.Conv2d(32, 64, kernel_size3) # 第二层卷积,卷积核大小为3*3 self.pool2 nn.MaxPool2d(2) # 分类网络 self.fc1 nn.Linear(1600, 64) # 全连接层1600 → 64 self.fc2 nn.Linear(64, num_classes) # 64 → 10输出 10 个类别的得分 # 前向传播 def forward(self, x): x self.pool1(F.relu(self.conv1(x))) # [32,1,28,28] # → conv1 → [32,32,26,26] 3×3 卷积28−3126 # → relu → 同上负值归零 # → pool1 → [32,32,13,13] 宽高减半 x self.pool2(F.relu(self.conv2(x))) # → conv2 → [32,64,11,11] # → pool2 → [32,64,5,5] x torch.flatten(x, start_dim1) # → [32, 1600] 64×5×51600摊平成一维 x F.relu(self.fc1(x)) # → [32, 64] x self.fc2(x) # → [32, 10] 每张图 10 个类别得分 return x这段代码定义了一个经典的 CNN卷积神经网络​用来做手写数字分类。结构是两层“卷积池化”做特征提取再接两层全连接做分类。__init__ 是“备料”——声明卷积核、池化窗、全连接矩阵这些可学习部件forward 是“加工流程”——图像经“卷积→激活→池化”两轮提炼从 784 个像素浓缩成 1600 个特征再映射到 10 个数字类别的得分。​ 这是 MNIST 上能轻松跑到 98% 准确率的经典 LeNet 变体结构。pip install torchinfo #首次使用需要安装from torchinfo import summary # 将模型转移到GPU中我们模型运行均在GPU中进行 model Model().to(device) summary(model)Layer (type:depth-idx) Param #Model --├─Conv2d: 1-1 320 # 3×3×1×32 32 偏置├─MaxPool2d: 1-2 -- # 池化无参数├─Conv2d: 1-3 18,496 # 3×3×32×64 64├─MaxPool2d: 1-4 --├─Linear: 1-5 64,064 # 1600×64 64├─Linear: 1-6 650 # 64×10 10Total params: 83,530Trainable params: 83,530Non-trainable params: 0summary(model) 不带输入信息时只能显示各层参数看不到中间张量形状。model.to(device) 是“把工厂搬进 GPU 车间”summary() 是“贴一张设备清单”——列清每一层的结构和参数量让你在训练前确认网络搭得对不对、模型有多大。loss_fn nn.CrossEntropyLoss() # 创建损失函数 learn_rate 1e-2 # 学习率 opt torch.optim.SGD(model.parameters(),lrlearn_rate) # 训练循环 def train(dataloader, model, loss_fn, optimizer): size len(dataloader.dataset) # 训练集的大小一共60000张图片 num_batches len(dataloader) # 批次数目187560000/32 train_loss, train_acc 0, 0 # 初始化训练损失和正确率 for X, y in dataloader: # 获取图片及其标签 X, y X.to(device), y.to(device) # 计算预测误差 pred model(X) # 网络输出 loss loss_fn(pred, y) # 计算网络输出和真实值之间的差距targets为真实值计算二者差值即为损失 # 反向传播 optimizer.zero_grad() # grad属性归零 loss.backward() # 反向传播 optimizer.step() # 每一步自动更新 # 记录acc与loss train_acc (pred.argmax(1) y).type(torch.float).sum().item() train_loss loss.item() train_acc / size train_loss / num_batches return train_acc, train_loss def test (dataloader, model, loss_fn): size len(dataloader.dataset) # 测试集的大小一共10000张图片 num_batches len(dataloader) # 批次数目31310000/32312.5向上取整 test_loss, test_acc 0, 0 # 当不进行训练时停止梯度更新节省计算内存消耗 with torch.no_grad(): for imgs, target in dataloader: imgs, target imgs.to(device), target.to(device) # 计算loss target_pred model(imgs) loss loss_fn(target_pred, target) test_loss loss.item() test_acc (target_pred.argmax(1) target).type(torch.float).sum().item() test_acc / size test_loss / num_batches return test_acc, test_loss epochs 5 train_loss [] train_acc [] test_loss [] test_acc [] for epoch in range(epochs): model.train() epoch_train_acc, epoch_train_loss train(train_dl, model, loss_fn, opt) model.eval() epoch_test_acc, epoch_test_loss test(test_dl, model, loss_fn) train_acc.append(epoch_train_acc) train_loss.append(epoch_train_loss) test_acc.append(epoch_test_acc) test_loss.append(epoch_test_loss) template (Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f}, Test_acc:{:.1f}%Test_loss:{:.3f}) print(template.format(epoch1, epoch_train_acc*100, epoch_train_loss, epoch_test_acc*100, epoch_test_loss)) print(Done)

相关推荐

UE5 入门系列(四):蓝图基础(上)
UE5 入门系列(四):蓝图基础(上)

UE5 入门系列(四):蓝图入门 —— 事件图表与可视化编程思维前面我们搭好了环境、熟悉了编辑器,也理解了 UE 的框架类。从本篇开始,我们正式进入"写逻辑"的阶段 先用蓝图完成第一个可交互功能,完全… · 2026/11/3 20:56:34

建立自己的FDE学习路线:从知识地图走向岗位实践
建立自己的FDE学习路线:从知识地图走向岗位实践

FDE岗位实务指南 第28篇这是本系列的最后一篇。前面二十七篇,从岗位认知一路讲到作品证明,方法给了一整套。但方法本身不构成成长——把方法用进自己的工作、拿到反馈、修正再用,这个循环才构成。最后一篇要回答的问题很朴素:二十… · 2026/11/10 2:33:34

黎曼引理 第11题2009
黎曼引理 第11题2009

高数|黎曼引理 第11题 题目 lim⁡n→∞∫01e−xsin⁡nx dx______ \lim_{n\rightarrow\infty}\int_{0}^{1} e^{-x}\sin nx \,dx \_\_\_\_\_\_ n→∞lim​∫01​e−xsinnxdx______答案:0\boldsymbol{0}0核心知识点(黎曼引理) 结论… · 2026/11/12 1:00:54

深圳低压电工作业招聘通过率揭秘:证书过期了不知道怎么复审延期怎么办
深圳低压电工作业招聘通过率揭秘:证书过期了不知道怎么复审延期怎么办

深圳低压电工作业招聘通过率揭秘:证书过期了不知道怎么复审延期怎么办 证书过期了不知道怎么复审延期?这个问题在深圳低压电工作业招聘岗位上,是很多从业者都遇到过的“坎”。特别是在深圳,低压电工证不仅是上岗的“通行证”,更是薪资、岗位晋升的关键。… · 2026/11/15 14:57:24

徐州靠谱电工证机构怎么考,含金量到底高不高?
徐州靠谱电工证机构怎么考,含金量到底高不高?

徐州靠谱电工证机构怎么考,含金量到底高不高? 你是不是正在找工作,却发现岗位要求里写着“必须持有低压电工证”“高压电工证”?别急,这正是你开始行动的最佳时机。 徐州靠谱电工证机构… · 2026/11/15 14:57:24

附近电工证报名地点怎么找?学历不高怕报不上名?全国通用证别错过
附近电工证报名地点怎么找?学历不高怕报不上名?全国通用证别错过

附近电工证报名地点怎么找?学历不高怕报不上名?全国通用证别错过 你学历不高,怕报不了名,怕考试过不了,怕证书不通用?别急,先搞清楚【附近电工证报名地点】到底在哪,怎么报名,哪个证最实用,全国通用的证又有哪些。… · 2026/11/15 14:57:24

电工证兼职不交社保多少钱?证书过期了不知道怎么复审延期怎么办
电工证兼职不交社保多少钱?证书过期了不知道怎么复审延期怎么办

电工证兼职不交社保多少钱?证书过期了不知道怎么复审延期怎么办 证书过期了不知道怎么复审延期,这事儿真不少见,尤其是像电工这类特种作业证,很多人靠它吃饭,但一旦没及时复审,就等于断了饭碗。特别是现在不少电工证兼职不交社保,很多人想靠这个证多接… · 2026/11/15 14:57:24

电工证可以考试几次啊,全国通用的考试规则你得知道
电工证可以考试几次啊,全国通用的考试规则你得知道

电工证可以考试几次啊,全国通用的考试规则你得知道 怕考不过白交培训费?电工证考试不是一次定终身,但也不是想考几次就考几次。特别是全国通用的电工证,考试规则和流程都有明确规定。本文从郑州培训机构学员的角度出发,详细拆解电工证可以考试几次啊、考… · 2026/11/15 14:57:24

北京电工证异地复审保姆级教程:怕考不过白交培训费?看完这条全搞定
北京电工证异地复审保姆级教程:怕考不过白交培训费?看完这条全搞定

北京电工证异地复审保姆级教程:怕考不过白交培训费?看完这条全搞定 怕考不过白交培训费?别急,这条保姆级教程帮你搞定【北京电工证异地复审】全过程,从实操考试到电子证书下载,全流程不踩坑。 为什么北京电工证异地复审越来越多人关注?… · 2026/11/15 14:56:24

长春初级电工证怎么考?通过率揭秘全在这里
长春初级电工证怎么考?通过率揭秘全在这里

长春初级电工证怎么考?通过率揭秘全在这里 之前考的证在外省能不能转过来?这几乎是每个想从事电工工作的人都会问的问题。特别是那些在外地打拼多年、手里握着一张“外地电工证”的人,到了长春想继续干这一行,第一反应就是“我的证能用吗?”。今天我们就… · 2026/11/15 0:00:50

国内电工证报考条件与考试时间
国内电工证报考条件与考试时间

低压电工证怎么考?学历不高也能报名,官方报名入口全在这 你是不是经常听说“电工证是入行门槛”,但又担心自己学历不够、经验不足,根本报不了名?别急,今天就带你从零了解【国内电工证】的报考流程、考试内容,还有怎么在 官方报名入口… · 2026/11/15 0:00:50

电工作业时如何断电?电子证书到底能不能全国通用?
电工作业时如何断电?电子证书到底能不能全国通用?

电工作业时如何断电?电子证书到底能不能全国通用? 实操考试心里没底怕挂科,特别是电工作业时如何断电这一操作,不仅关系到你能不能拿到证书,更关系到以后能不能顺利上岗。很多人觉得这不过就是“断个电”,但其实这里面的门道可不少,稍有不慎就可能出错… · 2026/11/15 0:00:50

长春初级电工证怎么考?通过率揭秘全在这里
长春初级电工证怎么考?通过率揭秘全在这里

长春初级电工证怎么考?通过率揭秘全在这里 之前考的证在外省能不能转过来?这几乎是每个想从事电工工作的人都会问的问题。特别是那些在外地打拼多年、手里握着一张“外地电工证”的人,到了长春想继续干这一行,第一反应就是“我的证能用吗?”。今天我们就… · 2026/11/15 0:00:50

国内电工证报考条件与考试时间
国内电工证报考条件与考试时间

低压电工证怎么考?学历不高也能报名,官方报名入口全在这 你是不是经常听说“电工证是入行门槛”,但又担心自己学历不够、经验不足,根本报不了名?别急,今天就带你从零了解【国内电工证】的报考流程、考试内容,还有怎么在 官方报名入口… · 2026/11/15 0:00:50

电工作业时如何断电?电子证书到底能不能全国通用?
电工作业时如何断电?电子证书到底能不能全国通用?

电工作业时如何断电?电子证书到底能不能全国通用? 实操考试心里没底怕挂科,特别是电工作业时如何断电这一操作,不仅关系到你能不能拿到证书,更关系到以后能不能顺利上岗。很多人觉得这不过就是“断个电”,但其实这里面的门道可不少,稍有不慎就可能出错… · 2026/11/15 0:00:50

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/15 1:51:20

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/15 4:02:19

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/15 3:02:05

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码