机器视觉期末作业实战:Python手写体字符识别从环境配置到模型调优

发布时间:2026/10/8 1:05:20
机器视觉期末作业实战:Python手写体字符识别从环境配置到模型调优 简介这份资源是面向高校学生与机器视觉初学者的手写体字符识别完整项目可直接用于课程设计、期末大作业或自学练手。项目基于Python实现围绕MNIST数据集展开涵盖数据加载、模型定义、训练与测试等完整流程并提供了MLP与MiniVGG两种网络结构便于对比不同模型的识别效果。压缩包共8个文件以5个py源码文件为主另含数据集压缩包、依赖清单与说明文档整体约31.64MB部署门槛低按说明安装依赖即可运行。代码注释详尽新手也能看懂每一步逻辑。目前已有344人学习说明其参考价值得到一定认可。读者可获得一套可直接复现的识别方案、清晰的目录组织与训练测试脚本既能快速完成作业交付也能借此理解卷积网络与全连接网络在手写字符任务上的差异适合作为入门机器视觉的实践起点。1. 从一份能直接跑通的机器视觉期末作业说起手写体字符识别到底怎么落地课程设计周刚开始实验室里最常见的场景就是有人对着 MNIST 数据集发呆——数据下载卡住、模型跑不动、准确率上不去最后交上去的代码连自己都讲不清。这份「机器视觉期末作业-基于 python 实现手写体字符识别」的资源包恰好是冲着这个痛点来的它把源代码、文档说明、数据集三样东西打包在一起目录结构清晰到data、models、train.py、test.py各司其职连requirements.txt都给你备好了。它解决的不是「从零造轮子」的问题而是「在有限时间内交出一份能讲清楚、能复现、能拿分」的作业。适合谁正在做机器视觉课程设计、期末大作业的本科生以及想用 MNIST 手写数字识别入门深度学习但不想被环境配置劝退的 python 新手。下面我按自己拆包复现的顺序把这份资源从结构到跑通再到避坑讲一遍。2. 拆开资源包目录结构、模型选型与 MNIST 数据流2.1 目录里每个文件在干什么拿到压缩包解压后根目录下能看到这些内容data文件夹、MNIST_Dataset.zip、dataset.py、requirements.txt、models文件夹内含MiniVGG.py和MLP.py、train.py、test.py、README.md。这个结构不是随便摆的它对应了一条完整的手写体字符识别流水线。data目录是留给数据集的落脚点MNIST_Dataset.zip是原始数据压缩包解压后通常得到 IDX 格式的训练集和测试集文件。dataset.py负责把原始数据读进来、做归一化和张量转换最终交给DataLoader按 batch 喂给模型。models下两个文件代表两种建模思路MLP.py是全连接网络结构简单、训练快适合先跑通流程MiniVGG.py是轻量卷积网络用堆叠的卷积层加池化层提取图像特征准确率更高适合作为最终提交版本。train.py和test.py分别是训练入口和评估入口requirements.txt锁定依赖版本README.md给出基本运行说明。提示先别急着改代码把README.md从头到尾读一遍确认作者标注的运行顺序和依赖版本能省掉后面一半的报错排查时间。2.2 为什么选 MLP 和 MiniVGG 两条路线MNIST 手写数字识别是机器视觉里最经典的入门任务图像尺寸固定为 28×28 灰度图类别数 10。用 MLP 做就是把 784 个像素拉平成一个向量经过若干全连接层加激活函数最后 softmax 输出 10 类概率。它的优势是代码短、参数少、CPU 上几分钟就能跑完一轮适合验证环境和数据管道是否正常。MiniVGG 则引入了卷积操作。卷积核在图像上滑动能捕捉笔画边缘、拐角这类局部特征池化层负责降维和保留主要信息。相比 MLP它对图像空间结构的利用更充分测试集准确率通常能高出几个百分点。常见做法是先用 MLP 跑通全流程确认数据加载、损失计算、反向传播都没问题再切到 MiniVGG 做最终训练。这样排错时变量少不会一上来就被卷积层的维度问题绕晕。2.3 数据加载与预处理的关键参数dataset.py是整个流程的入口它决定了模型看到的数据长什么样。下面是我根据这类项目常见写法整理的核心逻辑你可以对照自己包里的文件确认。# dataset.py 核心逻辑示意 import torch from torchvision import datasets, transforms from torch.utils.data import DataLoader # 定义预处理转张量 归一化 transform transforms.Compose([ transforms.ToTensor(), # 把 PIL 图像转成 [0,1] 区间的张量 transforms.Normalize((0.1307,), (0.3081,)) # MNIST 全局均值和标准差 ]) def get_dataloader(batch_size64, data_dir./data): # 训练集开启 shuffle打乱顺序避免模型学到样本排列规律 train_set datasets.MNIST(rootdata_dir, trainTrue, downloadFalse, transformtransform) train_loader DataLoader(train_set, batch_sizebatch_size, shuffleTrue) # 测试集不需要 shuffle保持固定顺序方便复现评估结果 test_set datasets.MNIST(rootdata_dir, trainFalse, downloadFalse, transformtransform) test_loader DataLoader(test_set, batch_sizebatch_size, shuffleFalse) return train_loader, test_loader这段代码里有两个参数值得注意。batch_size默认给 64显存或内存紧张时可以降到 32但太小会导致梯度更新抖动训练曲线不平滑。Normalize里的(0.1307,)和(0.3081,)是 MNIST 数据集的全局均值和标准差这两个数字是统计出来的经验值直接抄就行不要自己随便改否则模型收敛会变慢。downloadFalse表示数据已经放在本地data目录如果你第一次运行且本地没有数据需要改成True但这一步经常因为网络问题卡住后面避坑章节会细说。2.4 模型定义与训练循环的衔接models/MLP.py和models/MiniVGG.py各自定义一个继承自nn.Module的类forward方法里写前向传播。train.py负责实例化模型、定义损失函数和优化器、写训练循环。常见做法是损失函数用CrossEntropyLoss优化器用Adam或SGD学习率从 0.001 起步。训练循环里每个 epoch 包含前向传播算输出、计算损失、反向传播求梯度、优化器更新参数。test.py则加载训练好的权重在测试集上算准确率。这里有个容易忽略的点train.py和test.py里对模型结构的引用必须一致。如果你训练时用的是 MiniVGG测试时却实例化了 MLP加载权重会直接报维度不匹配。我一般会在train.py里把模型类名和保存路径写成变量测试时从同一个配置读避免手滑。3. 环境配置与训练跑通从 requirements.txt 到第一轮准确率3.1 依赖安装与版本对齐requirements.txt是这份资源能跑通的前提。典型内容会包含torch、torchvision、numpy、matplotlib这几项。安装时最稳妥的方式是建一个独立虚拟环境避免和系统里已有的包冲突。# 创建虚拟环境以 conda 为例 conda create -n mnist_hw python3.8 -y conda activate mnist_hw # 安装依赖 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple这里指定 python 3.8 是因为部分 torch 版本对 3.9 以上支持有差异课程设计环境通常求稳不求新。-i后面跟的是国内镜像源能明显加快下载速度。安装完成后用pip list确认 torch 和 torchvision 版本匹配比如 torch 1.10 配 torchvision 0.11版本错配会导致import torchvision直接失败。3.2 数据集的放置与加载验证资源包里已经带了MNIST_Dataset.zip解压后把得到的文件放进data目录。MNIST 原始数据通常是四个文件train-images-idx3-ubyte、train-labels-idx1-ubyte、t10k-images-idx3-ubyte、t10k-labels-idx1-ubyte。dataset.py里root参数指向./datadownloadFalse所以只要文件放对位置加载不会触发网络请求。验证数据是否加载成功可以单独跑一段小脚本from dataset import get_dataloader train_loader, test_loader get_dataloader(batch_size64) images, labels next(iter(train_loader)) print(f一个 batch 的图像形状: {images.shape}) # 期望 [64, 1, 28, 28] print(f一个 batch 的标签形状: {labels.shape}) # 期望 [64] print(f标签示例: {labels[:10]})如果图像形状是[64, 1, 28, 28]说明通道维度和尺寸都正确。如果报错说找不到文件检查data目录下是不是多了一层嵌套文件夹这是解压时最常见的路径问题。3.3 启动训练与关键参数调整确认数据没问题后直接运行训练脚本python train.py --model MiniVGG --epochs 10 --batch_size 64 --lr 0.001不同项目的train.py参数写法可能略有差异有的用argparse有的直接在文件里写死。如果脚本不支持命令行传参就打开train.py找到对应变量手动改。几个关键参数的作用epochs控制训练轮数MNIST 上 MLP 跑 10 轮、MiniVGG 跑 5 到 8 轮通常就能到 98% 以上batch_size影响内存占用和梯度稳定性lr是学习率太大震荡不收敛太小收敛慢。训练过程中终端会打印每轮的 loss 和准确率。正常情况下 loss 应该持续下降准确率持续上升。如果 loss 变成nan多半是学习率太大或者数据归一化没做对。如果准确率卡在 10% 左右不动检查标签和输出维度是否对齐。3.4 测试评估与结果复现训练结束后运行测试脚本python test.py --model MiniVGG --weights ./checkpoints/minivgg_best.pthtest.py会加载保存的权重在测试集上计算整体准确率有的还会输出混淆矩阵或部分错误样本的可视化。MNIST 测试集有 10000 张图MLP 通常能到 97% 到 98%MiniVGG 能到 99% 左右。如果结果明显偏低先确认测试时用的预处理和训练时是否完全一致——这是最容易被忽略的坑训练用了归一化而测试没加准确率会直接掉一大截。4. 避坑与排查MNIST 下载 404、维度不匹配与准确率玄学4.1 torchvision 下载 MNIST 报 404现象把download改成True后运行终端报HTTP Error 404: Not Found或连接超时。原因torchvision默认从境外源拉取 MNIST 数据网络不稳定时经常失败而且部分旧版本 torchvision 的下载链接已经失效。解决不要依赖自动下载。直接用资源包里自带的MNIST_Dataset.zip解压后按 3.2 节的路径放好保持downloadFalse。如果手头没有压缩包也可以从其他可信渠道获取原始 IDX 文件手动放进data/MNIST/raw/目录下。4.2 模型加载权重时报维度不匹配现象test.py加载.pth文件时抛出RuntimeError: size mismatch for ...。原因训练和测试用的模型类不一致比如训练存的是 MiniVGG 的权重测试却实例化了 MLP或者模型定义改过之后没有重新训练。解决确认train.py和test.py里实例化的模型类名完全相同权重文件路径指向对应模型。改过网络结构后必须重新训练不能复用旧权重。4.3 训练准确率一直上不去现象跑了十几个 epoch训练集准确率还在 90% 以下测试集更低。原因常见有三种——学习率设得太大导致 loss 震荡数据没有做归一化导致输入分布差异大或者标签和输出没有对齐比如标签是 0 到 9 但模型输出 1 到 10。解决先把学习率降到 0.0001 试一轮确认 loss 是否稳定下降检查dataset.py里Normalize是否生效打印一个 batch 的标签值确认范围。这三步能覆盖大部分准确率异常。4.4 显存或内存不足导致训练中断现象训练到一半报CUDA out of memory或进程被系统杀掉。原因batch_size设得太大或者同时开了多个训练进程。解决把batch_size从 64 降到 32 甚至 16MiniVGG 参数量不大小 batch 也能收敛。如果是 CPU 训练检查内存占用关掉不必要的后台程序。没有 GPU 的话MLP 在 CPU 上跑完全没问题MiniVGG 会慢一些但也能跑完。4.5 测试准确率远低于训练准确率现象训练集准确率 99%测试集只有 90% 出头。原因过拟合模型记住了训练样本但泛化能力差或者测试集预处理和训练集不一致。解决先核对两边的transform是否完全相同。如果确认一致说明模型过拟合可以减小模型规模、增加 dropout 层、或者提前停止训练。MNIST 上 MiniVGG 过拟合不算严重但如果训练轮数太多比如 30 轮以上测试准确率反而可能下降。5. 进阶技巧把这份作业改出个人亮点与验证方法5.1 用混淆矩阵定位易错类别光看整体准确率不够答辩时老师常问「哪些数字容易认错」。在test.py里加一段混淆矩阵计算能直接看出问题。import torch import numpy as np from sklearn.metrics import confusion_matrix from dataset import get_dataloader from models.MiniVGG import MiniVGG model MiniVGG() model.load_state_dict(torch.load(./checkpoints/minivgg_best.pth)) model.eval() _, test_loader get_dataloader(batch_size64) all_preds, all_labels [], [] with torch.no_grad(): for images, labels in test_loader: outputs model(images) preds outputs.argmax(dim1) all_preds.extend(preds.numpy()) all_labels.extend(labels.numpy()) cm confusion_matrix(all_labels, all_preds) print(cm) # 找出混淆最多的类别对 for i in range(10): for j in range(10): if i ! j and cm[i][j] 5: print(f数字 {i} 被误认为 {j} 的次数: {cm[i][j]})这段代码加载训练好的 MiniVGG在测试集上逐 batch 推理收集预测值和真实标签最后用sklearn的confusion_matrix输出 10×10 矩阵。矩阵对角线是正确分类数非对角线是误判。MNIST 上常见的混淆对是 4 和 9、3 和 5、7 和 1因为笔画结构相近。把这个结果放进报告里比只写一个准确率数字有说服力得多。5.2 用错误样本可视化做定性分析混淆矩阵给的是数字把分错的图挑出来看一眼更直观。在上一段代码基础上把预测错误的样本索引记下来用matplotlib画出来。import matplotlib.pyplot as plt # 收集错误样本 wrong_images, wrong_preds, wrong_labels [], [], [] with torch.no_grad(): for images, labels in test_loader: outputs model(images) preds outputs.argmax(dim1) for img, pred, label in zip(images, preds, labels): if pred ! label: wrong_images.append(img.squeeze().numpy()) wrong_preds.append(pred.item()) wrong_labels.append(label.item()) # 画前 8 个错误样本 fig, axes plt.subplots(2, 4, figsize(10, 5)) for ax, img, pred, label in zip(axes.flat, wrong_images[:8], wrong_preds[:8], wrong_labels[:8]): ax.imshow(img, cmapgray) ax.set_title(f真实:{label} 预测:{pred}) ax.axis(off) plt.tight_layout() plt.savefig(error_samples.png, dpi150)这段代码把每个分错的样本单独拎出来标题标注真实标签和预测标签。跑完之后打开error_samples.png你会看到有些数字连人眼都难辨认这类样本分错属于正常。如果发现某类错误集中出现且人眼觉得不该错说明模型还有改进空间可以针对性加数据增强。5.3 加数据增强提升泛化能力MNIST 训练集有 60000 张但都是居中、规整的手写数字。如果想让模型对轻微旋转、平移更鲁棒可以在dataset.py的transform里加增强。transform transforms.Compose([ transforms.RandomAffine(degrees10, translate(0.1, 0.1)), # 随机旋转±10度、平移10% transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ])RandomAffine在训练时随机对图像做小幅度旋转和平移测试时保持原始变换不变。这样模型见到的样本更多样测试集准确率通常能再涨 0.2 到 0.5 个百分点。注意增强只加在训练集上测试集不要加否则评估结果不可比。5.4 验证方法固定随机种子保证可复现答辩时老师可能让你当场再跑一遍如果每次结果都不一样会很尴尬。在train.py开头固定随机种子import torch import numpy as np import random def set_seed(seed42): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) torch.backends.cudnn.deterministic True torch.backends.cudnn.benchmark False set_seed(42)torch.backends.cudnn.deterministic True会让 GPU 上的卷积运算也走确定性算法代价是速度略慢但换来了结果可复现。CPU 训练本身基本确定加上这段更保险。固定种子后同样的代码跑两次准确率小数点后两位应该一致。从那以后我每次交课程设计前都会先把随机种子固定、把错误样本图跑出来、把混淆矩阵存进报告再检查一遍requirements.txt里的版本号是否和实际环境一致。这三件事花不了半小时但能挡掉答辩时八成的追问。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询