news 2026/10/10 14:48:31

PyTorch CNN实战:MNIST手写数字识别课设包完整解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PyTorch CNN实战:MNIST手写数字识别课设包完整解析

简介:这份资源面向深度学习入门者与课程设计需求的学生,围绕卷积神经网络识别MNIST手写数字这一经典实验展开,帮助读者理解CNN的基本结构与训练流程。压缩包共11个文件,约176KB,包含Python脚本、Word设计报告、Markdown说明、JSON配置、PNG训练与测试结果图及许可证等,代码与文档配套,便于边看报告边跑通实验。资源基于Python与Pytorch实现,涵盖数据加载、模型搭建、训练与测试等环节,并附有训练两轮后的准确率曲线与手写数字样本图,可直观对照模型效果。目前已有2027人学习下载,适合作为课程设计参考或CNN入门练手项目,读者可据此快速复现实验、理解卷积层与池化层的作用,并在此基础上调整网络结构或超参数进行扩展尝试。

1. 拆开这个 CNN+MNIST 课设包:它到底能不能直接跑通

如果你正在做深度学习课程设计,或者刚学完卷积神经网络想找个能跑通的完整项目练手,这个基于 Python 的 CNN 识别 MNIST 数据集压缩包值得先看一眼。它不是一个只有几行 demo 的玩具,里面包含了一份完整的设计报告 Word 文档、训练与测试脚本、两轮训练的准确率曲线图、手写数字样本图,以及一份 README 说明。技术栈是 Python + PyTorch,核心文件是cnn.py,配套output.txt记录训练日志,images目录存放可视化结果。换句话说,这是一个「报告 + 代码 + 结果图」三件套齐全的课设资源,适合需要交作业、写实验报告、或者想拿一个干净基线快速改造成自己项目的同学。下面我按实际拆包和复现的顺序,把这份资源从结构到跑通再到避坑讲清楚。

2. 资源结构与运行环境:先看清包里有什么再动手

2.1 文件清单与各自作用

拿到压缩包后别急着双击cnn.py,先把目录结构过一遍。这个包的文件组织比较典型,我按实际用途拆成三类:

文件/目录类型作用
cnn.py代码主训练与测试脚本,定义 CNN 网络、数据加载、训练循环
README.md文档项目说明,通常包含运行方式和依赖
设计报告.docx文档课程设计报告,含背景、网络结构、实验结果分析
output.txt日志训练过程输出记录,可对照复现结果
images/图片存放training_2epoch.png、testing_2epoch.png、digits.png、sample_digit.png
.gitignore配置Git 忽略规则,不影响运行
.vscode/settings.json配置VS Code 工作区设置,可能指定了解释器路径
LICENSE协议开源许可证

这里有个容易忽略的点:images目录里的training_2epoch.png和testing_2epoch.png是两轮训练后的准确率/损失曲线,digits.png通常是数据集样本网格图,sample_digit.png是单张手写数字示例。这些图在写报告时可以直接引用,省去自己画图的时间。output.txt则是训练日志的文本留存,如果你跑出来的结果和它对不上,说明环境或随机种子有差异。

2.2 环境准备:Python、PyTorch 与依赖安装

这个项目依赖 PyTorch,不是 TensorFlow。如果你机器上只有 TensorFlow,需要先装 PyTorch。常见做法是建一个虚拟环境,避免和系统里其他包冲突。我一般会这么做:

# 创建虚拟环境,Python 3.8 及以上都行 python -m venv mnist_cnn_env # 激活环境(Windows) mnist_cnn_env\Scripts\activate # 激活环境(Linux/macOS) source mnist_cnn_env/bin/activate # 安装 PyTorch,CPU 版本足够跑 MNIST pip install torch torchvision # 安装可视化依赖,画图用 pip install matplotlib numpy

这里解释一下参数和选择理由。python -m venv是标准库自带的虚拟环境工具,不需要额外装 virtualenv。PyTorch 的 CPU 版本对 MNIST 这种小数据集完全够用,训练两轮也就几分钟,没必要折腾 CUDA。torchvision里自带datasets.MNIST,会自动下载数据,不用手动找数据集文件。如果你用的是 Anaconda,也可以conda create -n mnist_cnn python=3.8然后conda install pytorch torchvision -c pytorch,效果一样。

提示:安装 PyTorch 时如果网络慢,可以换国内镜像源,比如pip install torch torchvision -i https://pypi.tuna.tsinghua.edu.cn/simple。但注意镜像源同步可能有延迟,版本号以官方为准。

装完之后验证一下:

import torch import torchvision print(torch.__version__) print(torchvision.__version__)

如果两行都能打印出版本号,说明环境没问题。如果报ModuleNotFoundError,检查是不是虚拟环境没激活,或者 pip 装到了系统 Python 里。

2.3 数据加载与预处理:MNIST 自动下载与归一化

MNIST 数据集在torchvision.datasets里可以直接调用,不需要自己去官网下载。常见写法是:

from torchvision import datasets, transforms # 定义预处理:转张量 + 归一化 transform = transforms.Compose([ transforms.ToTensor(), # 把 PIL 图片转成 [0,1] 的 Tensor transforms.Normalize((0.1307,), (0.3081,)) # MNIST 全局均值和标准差 ]) # 下载并加载训练集 train_dataset = datasets.MNIST( root='./data', # 数据存放路径 train=True, # 训练集 download=True, # 本地没有就自动下载 transform=transform ) # 测试集 test_dataset = datasets.MNIST( root='./data', train=False, download=True, transform=transform )

Normalize((0.1307,), (0.3081,))这两个数字是 MNIST 训练集的全局均值和标准差,不是随便写的。用它们归一化可以让输入分布更接近标准正态,训练收敛更稳。如果你跳过归一化,模型也能跑,但准确率可能低一两个百分点,而且损失曲线会抖。download=True第一次运行会从官方源拉数据,大概几十兆,如果卡住就检查网络,或者手动下载后放到./data/MNIST/raw目录下。

3. CNN 模型定义与训练脚本:逐段拆解 cnn.py

3.1 网络结构:两层卷积加全连接的设计逻辑

这个包里的 CNN 结构是经典的 LeNet 变体,两层卷积、两层池化、两层全连接。我按常见实现还原一下:

import torch.nn as nn import torch.nn.functional as F class CNN(nn.Module): def __init__(self): super(CNN, self).__init__() # 第一层卷积:输入 1 通道,输出 32 通道,卷积核 3x3 self.conv1 = nn.Conv2d(1, 32, kernel_size=3, padding=1) # 第二层卷积:输入 32 通道,输出 64 通道,卷积核 3x3 self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1) # 池化层:2x2 最大池化 self.pool = nn.MaxPool2d(2, 2) # 全连接层:经过两次池化后 28x28 -> 14x14 -> 7x7 self.fc1 = nn.Linear(64 * 7 * 7, 128) self.fc2 = nn.Linear(128, 10) # 10 类输出 def forward(self, x): # 第一层:卷积 -> ReLU -> 池化 x = self.pool(F.relu(self.conv1(x))) # [B,32,14,14] # 第二层:卷积 -> ReLU -> 池化 x = self.pool(F.relu(self.conv2(x))) # [B,64,7,7] # 展平 x = x.view(-1, 64 * 7 * 7) # 全连接 + ReLU x = F.relu(self.fc1(x)) # 输出层 x = self.fc2(x) return x

这里有几个参数值得说明。padding=1是为了让卷积后尺寸不变,28x28 进 28x28 出,这样两次池化后正好是 7x7,全连接层输入维度64*7*7才对得上。如果你把padding去掉,卷积后变成 26x26,池化后 13x13,再卷积 11x11,池化 5x5,全连接就得改成64*5*5,否则会报维度不匹配。kernel_size=3是经验值,3x3 卷积堆两层比 5x5 一层参数更少、非线性更强。输出层fc2是 10 维,对应 0 到 9 十个数字,没有加 Softmax,因为 PyTorch 的CrossEntropyLoss内部已经包含了 LogSoftmax。

3.2 训练循环:损失函数、优化器与批次设置

训练部分的核心是CrossEntropyLoss和Adam优化器,批次大小通常设 64 或 128。我一般会这么写:

import torch.optim as optim from torch.utils.data import DataLoader # 超参数 batch_size = 64 learning_rate = 0.001 epochs = 2 # 数据加载器 train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True) test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False) # 设备选择 device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model = CNN().to(device) # 损失函数和优化器 criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=learning_rate) # 训练循环 for epoch in range(epochs): model.train() running_loss = 0.0 for images, labels in train_loader: images, labels = images.to(device), labels.to(device) optimizer.zero_grad() # 清空梯度 outputs = model(images) # 前向传播 loss = criterion(outputs, labels) # 计算损失 loss.backward() # 反向传播 optimizer.step() # 更新参数 running_loss += loss.item() print(f'Epoch {epoch+1}, Loss: {running_loss/len(train_loader):.4f}')

shuffle=True对训练集很重要,每个 epoch 打乱顺序能防止模型学到样本顺序的伪规律。optimizer.zero_grad()必须放在反向传播之前,否则梯度会累加。Adam的学习率设 0.001 是默认值,对 MNIST 来说收敛很快,两轮就能到 98% 以上。如果你用 SGD,学习率得调到 0.01 左右,而且收敛慢一些。batch_size=64是折中值,太大显存吃紧,太小梯度噪声大。

3.3 测试与评估:准确率计算与结果保存

测试阶段要关掉梯度计算,用torch.no_grad()包起来,省显存也更快:

model.eval() correct = 0 total = 0 with torch.no_grad(): for images, labels in test_loader: images, labels = images.to(device), labels.to(device) outputs = model(images) _, predicted = torch.max(outputs, 1) # 取最大概率的类别 total += labels.size(0) correct += (predicted == labels).sum().item() print(f'Test Accuracy: {100 * correct / total:.2f}%')

torch.max(outputs, 1)返回每行最大值和对应索引,索引就是预测类别。model.eval()会把 Dropout 和 BatchNorm 切到推理模式,虽然这个简单 CNN 里没用到,但养成习惯没坏处。跑完两轮,准确率一般在 98.5% 到 99.2% 之间。如果低于 98%,检查归一化有没有加、学习率是不是太大、或者数据有没有正确下载。

4. 避坑与常见问题:跑不通时先查这几条

4.1 现象:报错RuntimeError: size mismatch

原因通常是全连接层输入维度写错了。如果你改了卷积层的padding或kernel_size,特征图尺寸会变,fc1的输入就不是64*7*7了。解决办法是打印一下卷积后的形状:

# 在 forward 里临时加一行 x = self.pool(F.relu(self.conv2(x))) print(x.shape) # 看实际输出维度

然后按打印结果改fc1的输入。别硬套网上的代码,结构一变维度就得跟着变。

4.2 现象:训练损失不下降,准确率卡在 10% 左右

这是典型的「模型没学到东西」。常见原因有三个:一是学习率太大导致梯度爆炸,把lr从 0.001 降到 0.0001 试试;二是忘了optimizer.zero_grad(),梯度累加后更新方向乱了;三是数据标签没对齐,比如DataLoader的shuffle和target错位。先检查第二条,这是血泪经验里出现频率最高的。

4.3 现象:下载 MNIST 卡住或报 SSL 错误

download=True时如果网络不稳定,会卡在下载环节。解决办法是手动下载四个文件放到./data/MNIST/raw/目录下,文件名分别是train-images-idx3-ubyte、train-labels-idx1-ubyte、t10k-images-idx3-ubyte、t10k-labels-idx1-ubyte。放好后把download改成False,再跑就不会重新下载了。

4.4 现象:output.txt里的结果和自己跑的对不上

这很正常,因为随机种子没固定。PyTorch 默认每次初始化权重不同,训练结果会有小幅波动。如果你想复现output.txt里的准确率,在代码开头加:

import torch import numpy as np import random torch.manual_seed(42) np.random.seed(42) random.seed(42)

但即使固定种子,不同 PyTorch 版本、不同硬件也可能有微小差异,不用强求完全一致。

4.5 现象:VS Code 里提示找不到 torch

.vscode/settings.json里可能指定了 Python 解释器路径,但和你实际虚拟环境不一致。打开 VS Code 的命令面板,选Python: Select Interpreter,指向你创建的mnist_cnn_env里的python.exe。或者直接在 settings.json 里改python.defaultInterpreterPath。这个坑不致命,但会让人误以为环境没装好。

5. 进阶技巧:把两轮训练扩到十轮并画出对比曲线

这个包默认只跑两轮,准确率已经不错,但如果你想在报告里展示更充分的实验,可以扩到十轮,并画出训练/测试曲线对比。我一般会这么做:在训练循环里记录每个 epoch 的 loss 和 accuracy,然后用 matplotlib 画图。

import matplotlib.pyplot as plt train_losses = [] test_accuracies = [] for epoch in range(10): model.train() running_loss = 0.0 for images, labels in train_loader: images, labels = images.to(device), labels.to(device) optimizer.zero_grad() outputs = model(images) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() train_losses.append(running_loss / len(train_loader)) # 每个 epoch 结束后测准确率 model.eval() correct = 0 total = 0 with torch.no_grad(): for images, labels in test_loader: images, labels = images.to(device), labels.to(device) outputs = model(images) _, predicted = torch.max(outputs, 1) total += labels.size(0) correct += (predicted == labels).sum().item() acc = 100 * correct / total test_accuracies.append(acc) print(f'Epoch {epoch+1}, Loss: {train_losses[-1]:.4f}, Acc: {acc:.2f}%') # 画图 fig, ax1 = plt.subplots() ax1.plot(range(1, 11), train_losses, 'b-', label='Training Loss') ax1.set_xlabel('Epoch') ax1.set_ylabel('Loss', color='b') ax2 = ax1.twinx() ax2.plot(range(1, 11), test_accuracies, 'r-', label='Test Accuracy') ax2.set_ylabel('Accuracy (%)', color='r') plt.title('Training Loss vs Test Accuracy') plt.savefig('images/training_10epoch.png', dpi=150) plt.show()

这段代码的关键是双轴图:左轴画 loss,右轴画 accuracy,能直观看出模型有没有过拟合。如果 loss 持续下降但 accuracy 平了,说明再训也没用;如果 loss 开始上升,那就是过拟合了,得加 Dropout 或早停。dpi=150保证保存的图够清晰,写进 Word 报告不糊。跑完十轮,准确率通常能到 99.2% 以上,但提升幅度很小,所以原包只跑两轮是合理的——课设够用,省时间。

注意:扩到十轮后训练时间会从几分钟变成十几分钟,如果机器慢就保持两轮,把报告重点放在结构分析和结果对比上,不必堆 epoch。

从那以后我每次拿到这种课设包,都会先固定随机种子、再跑一遍基线、最后才改结构。这样出问题能快速定位是环境还是代码。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/10 14:48:31

VOC手机检测数据集从零构建:标注、转换与踩坑指南

简介:面向目标检测算法训练与验证的数据集资源,围绕手机目标识别场景构建,适合使用YOLO、Faster-RCNN等主流框架的算法工程师、科研人员及计算机视觉学习者。包内共一万五千余个文件,包含五千余张真实场景jpg图片,以及…

作者头像 李华
网站建设 2026/10/10 14:46:03

LivePortrait 本地部署实战:ONNX 导出与 onnxruntime C++/Python 推理

简介:本资源面向希望在人像动画生成方向落地的开发者与算法工程师,提供一套基于onnxruntime推理的LivePortrait部署程序,同时给出C与Python两套实现,便于在桌面端或工程环境中集成。压缩包共14个文件,约459KB&#xff…

作者头像 李华
网站建设 2026/10/10 14:45:21

给AI编程助手补上长期记忆:claude-mem本地记忆工具实战指南

最近我在调整 AI 辅助编程的工作流时,踩了一个特别真实的坑:模型的单次对话能力再强,它依然不记得你昨天做过什么。上午我花了二十分钟跟命令行里的编程助手解释某个服务的调用约定,下午换了个文件继续写代码,它又把同…

作者头像 李华
网站建设 2026/10/10 14:44:47

SD卡参数错误不慌:镜像备份与数据恢复全流程

被“参数错误”吓到过的人应该不少。插上SD卡准备导照片,双击盘符,屏幕上弹出一句“无法访问,参数错误”,那一刻多数人的第一反应就是:完了,几年照片全没了。但如果你真的因此把卡格式化或者直接扔进抽屉吃…

作者头像 李华
网站建设 2026/10/10 14:43:27

C# WinForms图书管理系统:数据库设计与远程连接全实践

这个项目标题放在技术社区里,属于一眼就能看明白类型的那种——C# WinForms、图书管理、数据库、图片管理,还附带一套完整文档。我当初做类似项目时踩了不少坑,今天专门把它拆开揉碎聊一聊,希望能给正在做课设、毕设,或…

作者头像 李华
网站建设 2026/10/10 14:43:00

Docker镜像源配置指南:从加速拉取到自建私有仓库

“到底哪有docker镜像源?”这个问题,我一年里能看到很多次。提问的人通常已经盯着终端看了半天,镜像进度条卡住不动,CtrlC 再试还是一样。第一次遇到这种场面的人很容易怀疑是电脑或 Docker 出了问题,但我可以直说&…

作者头像 李华