Replies: 105 comments 118 replies
-
|
编号:2502-05 实验目标本实验旨在使用卷积神经网络(CNN)实现手写数字识别,基于MNIST数据集构建一个高精度的数字分类模型。具体目标包括:
数据集与预处理数据集介绍本实验使用MNIST手写数字数据集,包含:
预处理方法
CNN 网络结构网络架构设计结构选择原因
模型参数统计
训练过程与关键参数关键参数设置
训练代码model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
history = model.fit(x_train, y_train, epochs=10, batch_size=64,
validation_split=0.1, verbose=1)训练过程训练过程中每轮输出训练准确率和验证准确率,观察到:
实验结果最终测试结果
训练曲线部分预测结果展示训练过程详细记录
结果分析与总结实验结果分析
实验结论
改进方向
关键代码文件
|
Beta Was this translation helpful? Give feedback.
-
|
编号:2503-05 神经网络手写数字识别与图像分类实验报告基于 TensorFlow.js 的交互式识别网页实验 一、实验目标和整体设计本次实验围绕“神经网络图像识别”这一主题展开,目标是通过网页交互的方式理解神经网络如何接收图像输入、完成特征表达并输出分类结果。实验代码实现了一个名为“神经网络互动入门”的网页程序,页面上包含两个主要模块:第一个是手写数字识别模块,用户可以在画布上手写 0 到 9 中的任意数字,程序将画布内容转换为 28×28 的像素输入,再调用 MNIST 模型进行预测;第二个是 CNN 图像分类模块,用户上传图片后,程序调用 MobileNet 轻量卷积神经网络进行分类,并显示 Top 5 预测结果。 二、网络结构及选择原因手写数字识别模块采用的是多层感知机 MLP。代码中模型路径为 models/digitrecognizermlp/model.json,页面也将该部分标注为“MLP 手写数字”。该模型的输入为 28×28 的灰度图像,展开后形成 784 个像素值;中间显示了两个隐藏层,分别为 Dense 512 + ReLU;输出层为 10 个类别,对应数字 0 到 9。MLP 结构相对简单,适合初学者理解输入层、隐藏层和输出层之间的关系。 三、数据预处理方法手写数字模块的预处理过程比较关键。用户在 280×280 的 canvas 画布上写数字后,程序首先读取画布像素,并判断哪些像素属于笔迹。代码通过比较像素亮度,寻找笔迹区域的最小外接矩形,也就是 minX、minY、maxX 和 maxY。这样可以裁剪掉多余空白,避免数字在缩放后太小。 四、训练过程、关键参数和遇到的问题本实验代码没有在浏览器端重新训练模型,而是直接加载已经训练好的模型。手写数字识别部分通过 tf.loadLayersModel 加载本地 MNIST MLP 模型,图像分类部分通过 mobilenet.load 加载预训练 MobileNet 模型。这样做可以减少训练时间,使实验重点放在模型调用、数据处理和结果展示上。 五、实验结果展示在手写数字识别模块中,运行结果包括目标数字、预测数字、得分以及 0 到 9 的分类概率。当预测结果与目标数字一致时,系统提示预测正确并增加得分;当识别错误时,系统会提示用户将关键笔画写得更完整。例如目标数字为 3,模型预测为 3,置信度为 92%,则结果可以记为“预测正确,得分 +1”。如果目标为 5 而预测为 3,则说明书写形态可能与训练样本差异较大。 六、结果分析及个人理解通过本实验可以看出,神经网络识别图像的关键在于把图像转换为数值,再通过模型计算不同类别的概率。手写数字模块虽然采用的是 MLP,但在数字书写较规范时仍然能够取得较好的识别效果。这说明在输入数据比较简单、类别数量较少的任务中,基础全连接神经网络也能完成分类任务。 七、关键代码、运行输出和截图材料关键代码摘录 MNIST MLP 模型加载 手写数字张量构造 手写数字预测 MobileNet 分类 运行输出与截图说明手写数字模块建议截图:画布中写好的数字、目标数字、预测数字、得分、0 到 9 的概率条。 |
Beta Was this translation helpful? Give feedback.
-
|
编号:2502-03 一、实验目标 手写数字识别是计算机视觉领域中的经典问题,其目标是让计算机能够自动识别图片中的数字信息。 本实验采用卷积神经网络(CNN)对MNIST手写数字数据集进行训练,实现0~9数字的自动分类识别,并分析CNN在图像分类任务中的优势与特点。 实验目标
二、实验环境
三、实验设计 3.1 数据集介绍 MNIST(Modified National Institute of Standards and Technology)是机器学习领域最经典的数据集之一。 数据集包含:
分类标签: 3.2 实验流程四、网络结构设计 4.1 CNN网络结构 本实验采用两层卷积网络。 4.2 网络结构选择原因 卷积层 卷积层能够自动提取数字图像中的边缘、轮廓和纹理特征。 ReLU激活函数 提高模型非线性表达能力,缓解梯度消失问题。 池化层 降低特征维度,减少计算量,提高模型泛化能力。 全连接层 整合提取到的特征信息,实现数字分类任务。 五、数据预处理方法 为了提高模型训练效果,需要对数据进行预处理。 5.1 Tensor转换transforms.ToTensor()作用:
5.2 数据标准化transforms.Normalize((0.1307,), (0.3081,))标准化公式: 其中:
作用:
六、代码实现 6.1 导入相关库 import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets
from torchvision import transforms
from torch.utils.data import DataLoader6.2 数据加载 transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
train_dataset = datasets.MNIST(
root='./data',
train=True,
download=True,
transform=transform
)
test_dataset = datasets.MNIST(
root='./data',
train=False,
download=True,
transform=transform
)
train_loader = DataLoader(
train_dataset,
batch_size=64,
shuffle=True
)
test_loader = DataLoader(
test_dataset,
batch_size=64,
shuffle=False
)6.3 CNN模型构建 class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv1 = nn.Conv2d(
1,
32,
kernel_size=3
)
self.conv2 = nn.Conv2d(
32,
64,
kernel_size=3
)
self.pool = nn.MaxPool2d(2)
self.fc1 = nn.Linear(
64 * 5 * 5,
128
)
self.fc2 = nn.Linear(
128,
10
)
def forward(self, x):
x = self.pool(
torch.relu(self.conv1(x))
)
x = self.pool(
torch.relu(self.conv2(x))
)
x = x.view(-1, 64 * 5 * 5)
x = torch.relu(self.fc1(x))
x = self.fc2(x)
return x6.4 模型训练 device = torch.device(
"cuda" if torch.cuda.is_available()
else "cpu"
)
model = CNN().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(
model.parameters(),
lr=0.001
)
epochs = 10
for epoch in range(epochs):
model.train()
running_loss = 0
for images, labels in train_loader:
images = images.to(device)
labels = 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:.4f}"
)6.5 模型测试 model.eval()
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
images = images.to(device)
labels = labels.to(device)
outputs = model(images)
_, predicted = torch.max(
outputs.data,
1
)
total += labels.size(0)
correct += (
predicted == labels
).sum().item()
accuracy = 100 * correct / total
print(
f"Accuracy:{accuracy:.2f}%"
)七、训练过程
训练过程分析训练过程中损失函数持续下降,说明模型不断学习数字图像中的特征信息。 Adam优化器能够根据梯度变化动态调整学习率,使训练过程更加稳定。 随着训练轮数增加:
八、实验结果展示 8.1 Loss变化情况
从实验结果可以看出,损失值不断下降,模型训练稳定。 8.2 测试集准确率 模型最终在测试集上达到99%以上的识别准确率。 8.3 训练输出示例 九、实验中遇到的问题及解决方案问题1:Loss下降缓慢原因: 学习率设置过低。 解决方法: lr = 0.001采用Adam优化器提高训练效率。 问题2:过拟合现象 原因: 训练轮数过多。 解决方法:
问题3:GPU无法使用 原因: CUDA与PyTorch版本不匹配。 解决方法: pip install torch torchvision重新安装对应版本。 十、实验结果分析 CNN特征提取能力强 卷积层能够自动学习数字轮廓和边缘等关键特征。 池化层有效降低计算量 池化层减少参数数量,提高训练效率。 模型泛化能力较好测试集准确率达到99%以上,说明模型能够正确识别未见过的数字图像。 网络结构简单但性能优秀 仅使用两层卷积网络便获得较高精度,说明CNN非常适合解决手写数字识别问题。 十一、实验总结 本实验基于PyTorch搭建卷积神经网络,实现了MNIST手写数字识别任务。 实验过程中完成了数据预处理、模型构建、模型训练与测试等步骤,最终在测试集上取得99%以上的识别准确率。 通过本次实验,进一步掌握了卷积神经网络的基本原理和实现方法,理解了卷积层、池化层、全连接层以及损失函数和优化器在深度学习中的作用。同时认识到合理的数据预处理和参数设置对模型性能提升的重要意义,为后续更加复杂的图像识别任务奠定了基础。 |
Beta Was this translation helpful? Give feedback.
-
|
编号:2503-07 CNN 手写数字识别实验报告一、实验目标本实验实现一个基于卷积神经网络 CNN 的手写数字识别程序,对 MNIST 数据集中 0-9 共 10 类手写数字图像进行分类。实验目标包括:
二、实验设计实验采用监督学习方式完成图像分类任务。输入为 28×28 单通道手写数字图像,输出为 0-9 的类别编号。整体流程如下:
三、数据预处理方法MNIST 原始图像为灰度图。为了提升训练稳定性和泛化能力,程序中使用以下预处理方法:
训练集使用轻量数据增强,测试集只进行 ToTensor 和 Normalize,保证测试结果稳定可比。 四、网络结构本实验使用一个轻量 CNN,包含两组卷积、批归一化、ReLU 激活和最大池化层,最后使用全连接层输出 10 类分类结果。
该结构参数量适中,训练速度较快,适合课程实验。卷积层负责提取笔画、边缘和局部形状特征;池化层降低特征图尺寸并增强平移鲁棒性;Dropout 用于缓解过拟合。 核心模型代码位于 class DigitCNN(nn.Module):
def __init__(self, num_classes: int = 10) -> None:
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(1, 32, kernel_size=3, padding=1),
nn.BatchNorm2d(32),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2),
nn.Conv2d(32, 64, kernel_size=3, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2),
)
self.classifier = nn.Sequential(
nn.Flatten(),
nn.Linear(64 * 7 * 7, 128),
nn.ReLU(inplace=True),
nn.Dropout(p=0.5),
nn.Linear(128, num_classes),
)五、训练过程训练脚本位于 运行命令如下: pip install -r requirements.txt
python -m src.train --epochs 5 --batch-size 64 --learning-rate 0.001 --download训练过程中,每一轮都会记录:
当测试准确率高于历史最佳时,程序会保存 六、代码实现与规范性项目代码采用模块化结构:
代码规范性体现在:
七、实验结果展示下表为该网络配置在 MNIST 上训练 5 轮的典型结果示例。由于运行设备、随机初始化和依赖版本不同,实际结果会略有波动。
图1 展示了训练损失、测试损失和测试准确率随 epoch 的变化。可以看到损失函数整体下降,测试准确率逐步提升,说明模型训练过程正常收敛。 图2 展示了测试集归一化混淆矩阵。主对角线颜色最深,说明大部分样本被正确分类;少数错误主要出现在形状相似的数字之间,例如 4 和 9、3 和 5、7 和 9。 八、模型训练效果分析从实验结果可以看出,CNN 对手写数字识别任务具有较好的效果。模型在 5 轮训练后测试准确率可达到约 99.18%,说明卷积层能够有效提取数字图像中的局部笔画特征。 训练损失逐轮下降,说明模型参数在不断优化;测试准确率稳定提升,说明模型没有出现明显过拟合。BatchNorm 提高了训练稳定性,Dropout 降低了全连接层过拟合风险,轻量数据增强提升了模型对不同书写风格的适应能力。 九、预测程序说明训练完成后,可以使用以下命令识别单张手写数字图片: python -m src.predict --checkpoint runs/mnist_cnn/best_model.pt --image path/to/digit.png程序会输出预测数字、置信度以及 0-9 每一类的概率。如果输入图片是白底黑字,程序会自动反色,使其更接近 MNIST 的黑底白字格式。 十、实验结论本实验完成了基于 CNN 的手写数字识别程序。通过合理的数据预处理、卷积神经网络结构设计和训练策略,模型能够在 MNIST 测试集上取得较高准确率。实验结果表明,CNN 能够有效学习图像中的空间局部特征,适合用于手写数字识别等基础计算机视觉任务。 后续可以继续改进:
|
Beta Was this translation helpful? Give feedback.
-
|
编号: 2503-13 实验目标
数据集与预处理数据集MNIST是一个经典的手写数字数据集,包含:
预处理
CNN网络结构网络架构模型参数
参数数量训练过程与关键参数训练参数
代码实现import tensorflow as tf
from tensorflow.keras import layers, models
model = models.Sequential([
layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
layers.MaxPooling2D((2, 2)),
layers.Conv2D(64, (3, 3), activation='relu'),
layers.MaxPooling2D((2, 2)),
layers.Conv2D(64, (3, 3), activation='relu'),
layers.Flatten(),
layers.Dense(64, activation='relu'),
layers.Dense(10, activation='softmax')
])
model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
history = model.fit(x_train, y_train,
epochs=10,
batch_size=64,
validation_split=0.1)实验结果训练曲线准确率与损失
样本预测结果分析与总结结果分析
总结
参考文献
|
Beta Was this translation helpful? Give feedback.
-
|
编号:2503-16 神经网络图像识别网页项目报告从手写数字到 CNN 图片分类的实现分析 一、项目简介与实验目标本项目是一个运行在浏览器中的神经网络图像识别演示程序。实验目标是利用 TensorFlow.js 技术,让用户不需要配置 Python 深度学习环境,也能在网页中体验神经网络预测过程。项目主要包含两个任务:手写数字识别和普通图片分类。 二、整体设计思路项目采用单页面网页形式完成。HTML 负责页面结构,CSS 负责界面样式,JavaScript 负责交互逻辑和模型调用。页面上方设置两个 Tab 按钮,用户点击后可以在两个实验模块之间切换。这样的设计使页面层次清楚,也方便在课堂展示中分别说明不同网络结构。 三、手写数字识别模型分析手写数字模块加载的模型为 digitrecognizermlp。从命名和页面说明可以判断,它是一个基于 MNIST 数据集的 MLP 模型。MLP 的结构主要包括输入层、隐藏层和输出层。输入层接收 784 个像素,隐藏层进行非线性特征变换,输出层给出 10 个数字类别的概率。 四、CNN / MobileNet 模型分析CNN 模块使用的是 MobileNet。MobileNet 是一种专门为轻量化应用设计的卷积神经网络,常用于移动设备和网页端图像分类。代码中使用了 version 1 和 alpha 0.25,说明实验更重视运行速度和兼容性。 五、预处理方法手写数字预处理是本项目中最重要的环节之一。用户在 280×280 画布上书写后,代码会扫描像素,找到笔迹区域;如果没有检测到笔迹,则返回空结果并提示用户先写数字。 六、关键代码说明模型加载是实验运行的基础。手写数字部分使用 tf.loadLayersModel 加载本地模型,CNN 部分使用 mobilenet.load 加载预训练模型。两个模型都采用异步方式加载,因此代码中使用 async 函数和 await 关键字。 七、实验结果与分析在手写数字模块中,当数字书写规范、位置居中、笔画完整时,模型预测结果通常较好。例如目标数字为 2,用户写出标准的 2,模型会在数字 2 的概率条上显示较高比例,并将预测值设为 2。 八、实验收获通过本实验,我理解到图像识别任务的核心流程包括数据输入、预处理、模型推理和结果展示。对于手写数字识别,保持输入格式与训练数据一致非常重要;对于 CNN 图片分类,卷积结构能够帮助模型提取图像中的局部特征。 九、关键代码、运行输出和截图材料mnistModel = await tf.loadLayersModel(mnistModelUrl); tensor: tf.tensor2d([values], [1, 784]), const probabilities = Array.from(await output.data()); const predictions = await mobileNetModel.classify(imagePreview, 5); 手写数字模块建议截图:画布中写好的数字、目标数字、预测数字、得分、0 到 9 的概率条。 |
Beta Was this translation helpful? Give feedback.
-
|
编号:2502-23 一、实验名称 基于卷积神经网络(CNN)的MNIST手写数字识别 二、实验目的
三、实验环境 CPU:Intel Core i5及以上 3.2 软件环境
安装依赖: pip install torch torchvision matplotlib numpy四、实验原理 4.1 卷积神经网络(CNN) 卷积神经网络是一种专门处理图像数据的深度学习模型。 其主要组成部分包括:
CNN能够自动提取图像特征,在图像分类、目标检测等任务中具有良好的表现。 4.2 MNIST数据集 MNIST是机器学习领域最经典的手写数字数据集。 数据集信息如下:
类别为数字: 五、实验设计 5.2 网络结构设计 本实验采用两层卷积结构。 网络结构参数如下:
六、数据预处理6.1 Tensor转换将图像转换为Tensor格式: transforms.ToTensor()转换后: 6.2 数据标准化 采用MNIST官方均值和标准差: transforms.Normalize(
(0.1307,),
(0.3081,)
)标准化公式: 其中:
标准化有利于模型快速收敛。 七、代码实现 7.1 导入库 import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets
from torchvision import transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt7.2 数据加载 transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(
(0.1307,),
(0.3081,)
)
])
train_dataset = datasets.MNIST(
root='./data',
train=True,
download=True,
transform=transform
)
test_dataset = datasets.MNIST(
root='./data',
train=False,
download=True,
transform=transform
)
train_loader = DataLoader(
train_dataset,
batch_size=64,
shuffle=True
)
test_loader = DataLoader(
test_dataset,
batch_size=64,
shuffle=False
)7.3 CNN模型实现 class CNN(nn.Module):
def __init__(self):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(
1,32,
kernel_size=3,
padding=1
),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(
32,64,
kernel_size=3,
padding=1
),
nn.ReLU(),
nn.MaxPool2d(2)
)
self.classifier = nn.Sequential(
nn.Linear(
64*7*7,
128
),
nn.ReLU(),
nn.Linear(
128,
10
)
)
def forward(self,x):
x = self.features(x)
x = x.view(
x.size(0),
-1
)
x = self.classifier(x)
return x7.4 模型训练 device = torch.device(
"cuda"
if torch.cuda.is_available()
else "cpu"
)
model = CNN().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(
model.parameters(),
lr=0.001
)
epochs = 10
loss_list = []
for epoch in range(epochs):
model.train()
running_loss = 0
for images,labels in train_loader:
images = images.to(device)
labels = labels.to(device)
optimizer.zero_grad()
outputs = model(images)
loss = criterion(
outputs,
labels
)
loss.backward()
optimizer.step()
running_loss += loss.item()
epoch_loss = running_loss / len(train_loader)
loss_list.append(epoch_loss)
print(
f"Epoch:{epoch+1}, Loss:{epoch_loss:.4f}"
)7.5 模型测试 model.eval()
correct = 0
total = 0
with torch.no_grad():
for images,labels in test_loader:
images = images.to(device)
labels = labels.to(device)
outputs = model(images)
_,predicted = torch.max(
outputs,
1
)
total += labels.size(0)
correct += (
predicted == labels
).sum().item()
accuracy = 100 * correct / total
print(
f"Accuracy:{accuracy:.2f}%"
)八、训练过程分析 8.1 超参数设置
8.2 Loss变化情况 实验结果如下:
分析:
8.3 Loss曲线 plt.plot(loss_list)
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.title("Training Loss")
plt.show()实验现象: 九、实验结果展示 9.1 测试集准确率 实验结果:
9.2 部分预测结果
结果表明模型具有较高识别精度。 9.3 混淆矩阵分析 实验发现:
总体分类效果良好。 十、代码规范性分析 本实验代码具有以下特点: 模块化设计采用: class CNN(nn.Module)封装网络结构。 结构清晰 主要分为:
便于维护与扩展。 变量命名规范 例如: train_loader
test_loader
criterion
optimizer
loss_list
accuracy符合Python编码规范。 十一、实验结果分析 优点
存在不足
改进方案
十二、实验总结 本实验利用PyTorch框架实现了基于卷积神经网络(CNN)的MNIST手写数字识别系统。实验完成了数据预处理、模型设计、参数训练、性能测试等过程。 实验结果表明,CNN模型能够有效提取数字图像特征,在MNIST测试集上获得约99%的分类准确率,验证了卷积神经网络在图像识别任务中的优越性能。 通过本实验,进一步掌握了深度学习模型的构建方法、训练流程以及实验结果分析方法,为后续计算机视觉相关研究和实践奠定了基础。 |
Beta Was this translation helpful? Give feedback.
-
|
编号:2501-17 实验目标本实验旨在使用卷积神经网络(CNN)实现手写数字识别,基于MNIST数据集构建高精度数字分类模型。通过完整实验流程,掌握卷积神经网络图像分类的核心方法,具体目标如下:理解CNN的基本原理与工作机制;熟练掌握图像数据集预处理方法;合理设计CNN网络结构;完成模型训练与优化,实现高识别准确率;分析训练过程与实验结果,评估模型拟合效果与泛化性能。 数据集与预处理数据集介绍本次实验采用经典的MNIST手写数字数据集,是深度学习图像分类的基准数据集。数据集包含0-9共10类手写灰度数字图像,具体划分如下:训练集包含60000张28×28像素图像,用于模型训练拟合;测试集包含10000张28×28像素图像,用于模型性能评估。 预处理方法为适配卷积神经网络输入要求、提升模型训练效果,对原始数据进行三项预处理操作:
x_train = x_train.reshape(-1, 28, 28, 1).astype('float32') / 255.0
x_test = x_test.reshape(-1, 28, 28, 1).astype('float32') / 255.0
y_train = tf.keras.utils.to_categorical(y_train, 10)
y_test = tf.keras.utils.to_categorical(y_test, 10)CNN 网络结构网络架构设计本实验采用多层卷积+池化叠加、末端全连接分类的经典CNN结构,整体层级结构如下: 结构选择原因卷积层统一使用3×3小型卷积核,在保证特征感受野的同时大幅减少模型参数量;通道数由32递增至64,逐层提取图像边缘、轮廓、数字纹理等浅层与深层特征。ReLU激活函数有效解决深层网络梯度消失问题,提升训练效率。 池化层采用2×2最大池化,压缩特征图尺寸,剔除冗余信息、降低计算量,同时提升模型泛化能力,抑制过拟合。 末端设置64神经元全连接层完成特征融合,结合Softmax激活输出10维概率分布,精准适配10分类手写数字识别任务。 模型参数统计本次搭建的CNN模型整体轻量化,总参数量仅93322,参数明细如下:
训练过程与关键参数关键参数设置实验统一固定训练超参数,保证训练稳定性:优化器选用自适应学习率的Adam优化器;损失函数采用多分类专用的分类交叉熵损失;批量大小设置为64;全局训练轮数为10轮;从训练集中划分10%数据作为验证集,实时监控模型泛化性能。 训练代码model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
history = model.fit(x_train, y_train, epochs=10, batch_size=64,
validation_split=0.1, verbose=1)训练过程模型训练过程整体平稳,收敛速度较快。训练初期训练准确率与验证准确率快速提升,模型能够快速学习手写数字图像特征。全程训练集与验证集指标差距较小,模型无严重过拟合现象,仅训练后期出现轻微拟合偏差,整体训练效果良好。 实验结果最终测试结果模型训练完成后,在独立测试集上的最终性能指标:
训练曲线部分预测结果展示训练过程详细记录
结果分析与总结实验结果分析在准确率表现上,模型最终测试准确率达99.25%,训练准确率99.87%、验证准确率稳定在99.45%,三者指标均处于高水平,证明本次设计的CNN网络对手写数字特征提取能力优秀,分类精度极高。 在拟合状态上,模型前6轮训练收敛稳定,验证损失持续下降;从第7轮开始验证损失小幅上升,出现轻微过拟合,但训练集与验证集准确率差值极小,模型整体泛化能力优异,不影响实际使用效果。 在收敛速度上,模型仅3轮迭代即可将准确率提升至99%以上,收敛速度极快,后续迭代指标趋于平稳,模型训练充分,无需增加迭代轮数。 实验结论本次实验基于CNN完成MNIST手写数字识别任务,成功搭建了轻量化、高精度的图像分类模型。实验证明,卷积与池化的组合结构能够高效提取图像空间特征,相较于传统神经网络更适配图像分类场景。合理的网络结构搭配Adam优化器,可实现模型快速收敛与高精度拟合。最终模型识别准确率达99.25%,性能优异,满足基础手写数字识别的应用需求。 改进方向为进一步优化模型性能,可从四个方向迭代优化:一是引入旋转、平移、缩放等数据增强方式,扩充样本数据,提升模型鲁棒性;二是增加Dropout层、L2正则化,抑制轻微过拟合问题;三是通过超参数调优,优化学习率、批量大小与网络结构参数;四是引入迁移学习,利用预训练模型进一步提升识别精度。 关键代码文件
|
Beta Was this translation helpful? Give feedback.
-
实践1:CNN识别手写数字编号: 2501-03 1. 实验目的本实验旨在实现一个基于卷积神经网络(CNN)的手写数字识别系统,通过MNIST数据集进行训练和测试,深入理解CNN的原理和应用。 2. 实验环境
3. 数据集介绍MNIST数据集MNIST是一个经典的手写数字识别数据集,包含:
数据预处理
4. CNN模型设计4.1 模型架构
4.2 模型代码class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv_layers = nn.Sequential(
nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
)
self.fc_layers = nn.Sequential(
nn.Linear(64 * 7 * 7, 128),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(128, 10)
)
def forward(self, x):
x = self.conv_layers(x)
x = x.view(-1, 64 * 7 * 7)
x = self.fc_layers(x)
return x5. 训练设置5.1 超参数配置
5.2 训练流程
6. 实验结果6.1 训练曲线训练过程中的损失和准确率变化曲线如下: 训练损失曲线
训练准确率曲线
6.2 测试结果
6.3 混淆矩阵混淆矩阵展示了模型在每个类别上的分类性能: 6.4 结果分析
7. 代码结构8. 运行方式# 安装依赖
pip install -r requirements.txt
# 运行训练
python src/main.py9. 结论本实验成功实现了一个基于CNN的手写数字识别系统,主要收获:
10. 参考文献
|
Beta Was this translation helpful? Give feedback.
-
|
编号:2501-24 实践1:CNN识别手写数字一、实验目标本实验基于卷积神经网络(CNN)实现手写数字识别任务,通过训练 MNIST 数据集完成数字分类,并分析模型训练过程及实验结果。 主要目标如下:
二、实验环境软件环境
硬件环境
三、数据集介绍本实验采用 MNIST(Modified National Institute of Standards and Technology)手写数字数据集。 数据集包含:
数据集示例: 四、数据预处理1. 加载数据集from tensorflow.keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()数据维度: print(train_images.shape)
print(test_images.shape)输出: 2. 图像归一化原始像素值范围: 归一化处理: train_images = train_images.astype("float32") / 255
test_images = test_images.astype("float32") / 255处理后范围: 3. 调整数据维度CNN输入格式要求: 转换代码: train_images = train_images.reshape(60000,28,28,1)
test_images = test_images.reshape(10000,28,28,1)4. 标签独热编码例如: 转换为: 代码: from tensorflow.keras.utils import to_categorical
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)五、网络结构设计CNN结构网络参数说明第一层卷积层Conv2D(32,(3,3))作用:
池化层MaxPooling2D((2,2))作用:
第二、三层卷积层Conv2D(64,(3,3))作用: 提取更深层图像特征。 全连接层Dense(64)作用: 整合特征信息。 输出层Dense(10, activation='softmax')作用: 输出10个数字类别的概率。 六、核心代码实现构建模型from tensorflow.keras import models
from tensorflow.keras import layers
model = models.Sequential()
model.add(
layers.Conv2D(
32,
(3,3),
activation='relu',
input_shape=(28,28,1)
)
)
model.add(layers.MaxPooling2D((2,2)))
model.add(
layers.Conv2D(
64,
(3,3),
activation='relu'
)
)
model.add(layers.MaxPooling2D((2,2)))
model.add(
layers.Conv2D(
64,
(3,3),
activation='relu'
)
)
model.add(layers.Flatten())
model.add(
layers.Dense(
64,
activation='relu'
)
)
model.add(
layers.Dense(
10,
activation='softmax'
)
)编译模型model.compile(
optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy']
)模型训练history = model.fit(
train_images,
train_labels,
epochs=5,
batch_size=64,
validation_split=0.1
)训练参数:
七、实验结果准确率变化
损失函数变化
测试结果训练曲线
预测结果展示
识别结果全部正确。 八、实验分析准确率分析从训练结果可以看出:
说明CNN能够有效学习数字图像特征。 损失函数分析随着训练进行: 说明模型逐渐收敛。 模型优缺点优点:
缺点:
九、实验总结本实验利用 TensorFlow 框架完成了基于 CNN 的手写数字识别系统设计与实现。 完成内容包括:
最终模型在测试集上取得约 99.1% 的识别准确率,验证了卷积神经网络在图像分类任务中的优秀性能。 通过本次实验,我进一步掌握了深度学习模型的构建流程,加深了对卷积神经网络原理及应用场景的理解,为后续计算机视觉相关实验奠定了基础。 参考资料
|
Beta Was this translation helpful? Give feedback.
-
|
编号:2503-04 基于 TensorFlow.js 的神经网络识别实验报告手写数字识别与 CNN 图像分类功能分析 一、实验目的本实验的目的,是通过阅读和运行一个基于 TensorFlow.js 的网页程序,掌握神经网络进行图像识别的基本步骤。程序包含手写数字识别和图像分类两个部分,前者用于识别用户在画布中书写的数字,后者用于识别用户上传的普通物体图片。实验重点不是重新训练模型,而是理解模型如何被加载、输入数据如何被处理、预测结果如何被展示。 二、程序整体结构程序页面标题为“神经网络互动入门”,上方有两个标签按钮,分别对应“MLP 手写数字”和“CNN 图像分类”。这种结构清晰地把两个功能分开,用户可以先体验简单的手写数字分类,再体验真实图片分类。页面采用左右布局:左侧是输入区域,右侧是结果和解释区域。 三、网络结构说明手写数字识别部分的模型是 MLP,也就是多层感知机。根据代码和页面文字,该部分的输入为 784 个像素值,隐藏层为两层 Dense 512 + ReLU,输出层为 10 个数字类别。MLP 的优点是结构简单,容易理解;缺点是它不擅长保留图像的空间关系。 四、数据预处理流程手写数字数据预处理主要包括五步。第一步,读取 canvas 上的像素数据;第二步,判断是否存在笔迹,如果画布为空则提示用户先写数字;第三步,找到笔迹的最小包围区域,并加入 padding;第四步,将裁剪后的数字缩放到 28×28;第五步,将像素值归一化并转换为形状为 [1, 784] 的张量。 五、关键参数与运行问题本实验的关键参数包括:手写画布为 280×280,最终输入为 28×28;MLP 输出类别为 10 类;MobileNet 分类结果数量为 5;MobileNet 版本为 1,宽度系数 alpha 为 0.25。程序还设置了手写笔画宽度 lineWidth = 24,这可以让用户写出的数字更接近 MNIST 样本中的粗笔画。 六、实验结果运行手写数字模块时,页面会显示目标数字、预测数字和得分。例如当目标为 8,用户写出较完整的 8,模型可能预测为 8,置信度较高;如果用户写得像 3,则预测结果可能变为 3。数字概率条可以看到每个类别的概率分布,不只是最终结果。 七、个人分析我认为本实验最大的特点是交互性强。传统神经网络实验通常需要在 Python 环境中运行代码,初学者只能看到终端输出;而这个程序把输入、特征和概率都放在网页中展示,更容易理解。 八、关键代码、运行输出和截图材料1.关键代码摘录 2.运行输出与截图说明 |
Beta Was this translation helpful? Give feedback.
-
|
编号:2501-10 transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
train_dataset = datasets.MNIST(root="data", train=True, download=True, transform=transform)
test_dataset = datasets.MNIST(root="data", train=False, download=True, transform=transform)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)模型结构使用 class CNN(nn.Module):
def __init__(self):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(1, 32, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2)
)
self.classifier = nn.Sequential(
nn.Flatten(),
nn.Linear(64 * 7 * 7, 128),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(128, 10)
)
def forward(self, x):
x = self.features(x)
x = self.classifier(x)
return x训练函数中包含前向传播、损失计算、梯度清零、反向传播和参数更新五个步骤。测试函数中使用 |
Beta Was this translation helpful? Give feedback.
-
|
实践1:CNN 识别手写数字 编号:2501-21 实验目标本次实验的主要目标是使用卷积神经网络(CNN)构建一个手写数字识别系统,能够准确识别MNIST数据集中的手写数字0-9。通过本次实验,我需要:
数据集与预处理数据集介绍本实验使用经典的MNIST手写数字数据集,该数据集包含:
数据预处理方法
CNN 网络结构网络架构设计我设计的CNN模型包含3个卷积层和3个全连接层,具体结构如下: 选择原因
模型参数量
训练过程与关键参数训练配置# 优化器
optimizer = optim.Adam(model.parameters(), lr=0.001, weight_decay=1e-4)
# 损失函数
criterion = nn.CrossEntropyLoss()
# 学习率调度
scheduler = optim.lr_scheduler.ReduceLROnPlateau(
optimizer, mode='min', factor=0.5, patience=3
)
# 训练轮次
epochs = 15
batch_size = 64训练策略
训练结果
最佳测试准确率:99.17% 实验结果性能指标
训练曲线训练过程中,损失函数持续下降,训练和测试准确率稳步提升,最终收敛且训练集和测试集准确率差距很小,说明模型泛化能力良好。 混淆矩阵分析从混淆矩阵可以看出:
预测样例模型能够正确识别各种手写风格的数字,对笔画粗细、倾斜程度等变化具有较好的鲁棒性。 结果分析与总结成功经验
可能的改进方向
核心收获通过本次实验,我深入理解了:
关键代码CNN模型定义class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv1 = nn.Sequential(
nn.Conv2d(1, 32, 3, padding=1),
nn.BatchNorm2d(32),
nn.ReLU(),
nn.MaxPool2d(2, 2)
)
# ... 其他层
self.fc = nn.Sequential(
nn.Flatten(),
nn.Linear(128*3*3, 256),
nn.ReLU(),
nn.Dropout(0.5),
# ...
)训练循环for epoch in range(epochs):
model.train()
for data, target in train_loader:
optimizer.zero_grad()
output = model(data)
loss = criterion(output, target)
loss.backward()
optimizer.step()运行说明环境依赖运行方式python mnist_cnn.py输出文件
实验完成日期:2026年6月11日 |
Beta Was this translation helpful? Give feedback.
-
|
编号:2502-15 一、实验名称 基于卷积神经网络(CNN)的手写数字识别系统设计与实现 二、实验目的
三、实验环境
四、实验原理 4.1 手写数字识别简介 手写数字识别(Handwritten Digit Recognition)是计算机视觉领域经典问题之一,其目标是将输入的数字图像自动分类为0~9中的一个数字类别。 MNIST数据集包含:
4.2 卷积神经网络(CNN) CNN主要由以下部分组成: (1)卷积层(Convolution Layer) 提取图像局部特征: 其中:
(2)激活函数(ReLU) 增强非线性表达能力: (3)池化层(Pooling Layer) 降低特征维度: 采用最大池化(MaxPooling)。 (4)全连接层(Fully Connected Layer) 完成最终分类: (5)Softmax分类器 输出每个类别的概率: 五、实验设计 5.1 系统流程 5.2 网络结构设计 本实验设计如下CNN结构: 5.3 网络参数
六、数据预处理 6.1 数据加载 train_dataset = datasets.MNIST(
root='./data',
train=True,
transform=transform,
download=True
)6.2 图像归一化 将像素值从: 映射到: 处理公式: 6.3 Tensor转换 transforms.ToTensor()转换为: torch.Tensor格式: 七、代码实现 7.1 导入库 import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader7.2 CNN模型构建 class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv = nn.Sequential(
nn.Conv2d(
in_channels=1,
out_channels=32,
kernel_size=3,
padding=1
),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(
32,
64,
3,
padding=1
),
nn.ReLU(),
nn.MaxPool2d(2)
)
self.fc = nn.Sequential(
nn.Linear(64*7*7,128),
nn.ReLU(),
nn.Linear(128,10)
)
def forward(self,x):
x=self.conv(x)
x=x.view(x.size(0),-1)
x=self.fc(x)
return x7.3 数据加载transform = transforms.Compose([
transforms.ToTensor()
])
train_loader = DataLoader(
train_dataset,
batch_size=64,
shuffle=True
)
test_loader = DataLoader(
test_dataset,
batch_size=64,
shuffle=False
)7.4 损失函数与优化器 model = CNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(
model.parameters(),
lr=0.001
)7.5 模型训练 epochs = 10
for epoch in range(epochs):
model.train()
for images, labels in train_loader:
outputs = model(images)
loss = criterion(outputs, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(
f"Epoch:{epoch+1}, Loss:{loss.item():.4f}"
)7.6 模型测试 model.eval()
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
outputs = model(images)
_, predicted = torch.max(outputs,1)
total += labels.size(0)
correct += (
predicted == labels
).sum().item()
accuracy = 100 * correct / total
print(
f"Accuracy:{accuracy:.2f}%"
)八、训练过程分析 实验参数设置如下:
8.1 Loss变化 训练过程中损失值变化如下:
可以发现:
8.2 Loss曲线 九、实验结果展示 9.1 测试集准确率 最终实验结果: 9.2 部分预测结果
9.3 混淆矩阵分析 实验发现:
总体分类效果较好。 十、实验总结 本实验基于PyTorch实现了卷积神经网络手写数字识别系统,并利用MNIST数据集完成训练与测试。 实验结果表明:
通过本实验进一步掌握了:
十一、实验改进方向
|
Beta Was this translation helpful? Give feedback.
-
|
编号:2502-04 项目目标与应用场景实验目标本实验旨在构建一个基于深度学习的手写数字识别系统,主要目标包括:
计算机视觉应用场景手写数字识别是计算机视觉领域的经典应用,具有广泛的实际场景:
数据集与数据处理数据集来源本实验使用MNIST手写数字数据集,这是计算机视觉领域最经典的基准数据集之一:
数据特点
预处理方法数据预处理是模型训练的关键步骤,本实验采用以下预处理方法:
关键代码(数据预处理): def load_data(self):
(self.x_train, self.y_train), (self.x_test, self.y_test) = mnist.load_data()
# 调整维度,添加通道
self.x_train = self.x_train.reshape(self.x_train.shape[0], 28, 28, 1)
self.x_test = self.x_test.reshape(self.x_test.shape[0], 28, 28, 1)
# 归一化到[0, 1]
self.x_train = self.x_train.astype('float32') / 255
self.x_test = self.x_test.astype('float32') / 255
# 独热编码
self.y_train = to_categorical(self.y_train, 10)
self.y_test = to_categorical(self.y_test, 10)模型或技术方案模型架构本实验采用卷积神经网络(CNN)作为核心模型,网络结构如下:
技术方案选择原因选择CNN的原因:
网络设计考虑:
训练配置
实现与训练过程项目结构代码实现模型构建代码: def build_model(self):
self.model = Sequential([
Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=(28, 28, 1)),
Conv2D(64, (3, 3), activation='relu'),
MaxPooling2D(pool_size=(2, 2)),
Dropout(0.25),
Flatten(),
Dense(128, activation='relu'),
Dropout(0.5),
Dense(10, activation='softmax')
])
self.model.compile(loss='categorical_crossentropy',
optimizer='adadelta',
metrics=['accuracy'])训练过程代码: def train(self, epochs=12, batch_size=128):
self.history = self.model.fit(self.x_train, self.y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(self.x_test, self.y_test))训练过程训练流程如下:
运行方式# 安装依赖
pip install tensorflow numpy matplotlib scikit-learn
# 运行程序
cd handwritten-digit-recognition
python src/digit_recognizer.py实验结果训练性能经过12轮训练后,实验结果如下:
训练历史曲线程序生成
样本预测结果程序生成
模型保存训练完成后,模型保存到
结果分析与总结实验结果分析
遇到的问题
改进方向
实验总结本实验成功实现了基于CNN的手写数字识别系统,主要成果:
通过本次实验,深入理解了卷积神经网络的原理和应用,掌握了图像分类任务的完整开发流程。 关键代码与运行说明主程序文件文件路径: 主要类与方法:
运行输出示例参考资料
|
Beta Was this translation helpful? Give feedback.
-
|
编号:2501-09 实验目标本实验旨在使用卷积神经网络(CNN)实现手写数字识别,基于MNIST数据集构建一个高精度的数字分类模型。具体目标包括:
数据集与预处理数据集介绍本实验使用MNIST手写数字数据集,包含:
预处理方法
CNN 网络结构网络架构设计结构选择原因
模型参数统计
训练过程与关键参数关键参数设置
训练代码model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
history = model.fit(x_train, y_train, epochs=10, batch_size=64,
validation_split=0.1, verbose=1)训练过程训练过程中每轮输出训练准确率和验证准确率,观察到:
实验结果最终测试结果
训练曲线部分预测结果展示训练过程详细记录
结果分析与总结实验结果分析
实验结论
改进方向
关键代码文件
|
Beta Was this translation helpful? Give feedback.
-
|
编号:2502-20 CNN 识别手写数字实验报告实验目标本次实验的目标是使用卷积神经网络 CNN 完成手写数字识别任务。实验基于 MNIST 手写数字数据集,构建一个能够识别 0—9 十类数字图像的分类模型。通过本次实践,我主要完成以下内容:
整体设计思路是:首先对 MNIST 图像数据进行预处理,使其符合 CNN 输入要求;然后搭建由卷积层、池化层、展平层和全连接层组成的神经网络;最后使用 Adam 优化器进行训练,并通过测试集准确率评价模型的泛化能力。 数据集与预处理本实验使用 MNIST 手写数字数据集。MNIST 是深度学习入门中常用的图像分类数据集,包含大量 0—9 的灰度手写数字图片。每张图片大小为 28×28 像素,图像为单通道灰度图。 数据集基本情况如下:
在预处理阶段,主要进行了以下操作: 1. 调整输入维度原始 MNIST 图像的形状为 (样本数量, 图像高度, 图像宽度, 通道数)由于 MNIST 是灰度图,因此通道数为 1。处理后图像形状变为: (60000, 28, 28, 1)2. 像素值归一化原始图像像素值范围为 0—255。为了加快模型收敛速度,并避免不同像素值尺度过大影响训练,将像素值统一缩放到 0—1 之间: x_train = x_train.astype("float32") / 255.0
x_test = x_test.astype("float32") / 255.0归一化后,模型训练更加稳定,也更容易收敛。 3. 标签处理MNIST 标签原本是 0—9 的整数类别。在使用交叉熵损失函数进行多分类训练时,可以将标签转换为独热编码形式。例如数字 3 可表示为: [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]对应代码如下: y_train = tf.keras.utils.to_categorical(y_train, 10)
y_test = tf.keras.utils.to_categorical(y_test, 10)CNN 网络结构本次实验搭建了一个典型的卷积神经网络模型,网络主要由卷积层、池化层、展平层和全连接层组成。 模型结构如下: 模型代码如下: model = tf.keras.Sequential([
tf.keras.layers.Conv2D(32, (3, 3), activation="relu", input_shape=(28, 28, 1)),
tf.keras.layers.MaxPooling2D((2, 2)),
tf.keras.layers.Conv2D(64, (3, 3), activation="relu"),
tf.keras.layers.MaxPooling2D((2, 2)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation="relu"),
tf.keras.layers.Dropout(0.3),
tf.keras.layers.Dense(10, activation="softmax")
])网络结构选择原因第一,卷积层能够自动提取图像中的局部特征,例如笔画边缘、弯曲形状和数字轮廓。相比普通全连接网络,CNN 更适合处理图像数据。 第二,使用 3×3 卷积核可以在较少参数量的情况下提取局部特征,既保证了特征提取能力,又避免模型过于复杂。 第三,最大池化层可以降低特征图尺寸,减少计算量,同时保留主要特征,使模型对数字位置的轻微变化具有一定鲁棒性。 第四,ReLU 激活函数能够增强模型的非线性表达能力,并缓解梯度消失问题。 第五,输出层使用 Softmax 激活函数,将模型输出转换为 10 个类别的概率分布,概率最大的类别就是最终预测结果。 训练过程与关键参数模型编译代码如下: model.compile(
optimizer="adam",
loss="categorical_crossentropy",
metrics=["accuracy"]
)训练代码如下: history = model.fit(
x_train,
y_train,
epochs=10,
batch_size=64,
validation_split=0.1
)本次实验的主要训练参数如下:
遇到的问题及解决方法在实验过程中主要遇到了以下问题:
实验结果模型训练完成后,在测试集上进行评估,测试代码如下: test_loss, test_acc = model.evaluate(x_test, y_test, verbose=2)
print("测试集损失:", test_loss)
print("测试集准确率:", test_acc)一次运行输出结果如下: 最终测试准确率约为 99.12%,说明模型能够较好地识别大多数手写数字。 训练过程中准确率和损失变化情况如下表所示:
从训练结果可以看出,模型在前几轮中准确率提升明显,说明 CNN 能够快速学习手写数字图像中的有效特征。随着训练轮数增加,训练准确率继续上升,但验证准确率提升逐渐变慢,表明模型已经基本收敛。 关键代码完整实验代码如下: import tensorflow as tf
from tensorflow.keras.datasets import mnist
import matplotlib.pyplot as plt
import numpy as np
# 1. 加载 MNIST 数据集
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# 2. 数据预处理
x_train = x_train.reshape(-1, 28, 28, 1).astype("float32") / 255.0
x_test = x_test.reshape(-1, 28, 28, 1).astype("float32") / 255.0
y_train = tf.keras.utils.to_categorical(y_train, 10)
y_test = tf.keras.utils.to_categorical(y_test, 10)
# 3. 构建 CNN 模型
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(32, (3, 3), activation="relu", input_shape=(28, 28, 1)),
tf.keras.layers.MaxPooling2D((2, 2)),
tf.keras.layers.Conv2D(64, (3, 3), activation="relu"),
tf.keras.layers.MaxPooling2D((2, 2)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation="relu"),
tf.keras.layers.Dropout(0.3),
tf.keras.layers.Dense(10, activation="softmax")
])
# 4. 编译模型
model.compile(
optimizer="adam",
loss="categorical_crossentropy",
metrics=["accuracy"]
)
# 5. 训练模型
history = model.fit(
x_train,
y_train,
epochs=10,
batch_size=64,
validation_split=0.1
)
# 6. 测试模型
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=2)
print("测试集损失:", test_loss)
print("测试集准确率:", test_acc)
# 7. 绘制准确率曲线
plt.plot(history.history["accuracy"], label="train accuracy")
plt.plot(history.history["val_accuracy"], label="validation accuracy")
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.legend()
plt.title("Training and Validation Accuracy")
plt.show()
# 8. 显示部分预测结果
predictions = model.predict(x_test[:10])
predicted_labels = np.argmax(predictions, axis=1)
true_labels = np.argmax(y_test[:10], axis=1)
print("预测标签:", predicted_labels)
print("真实标签:", true_labels)部分预测输出如下: 从部分预测结果可以看出,模型对测试集中前 10 张图像均预测正确,说明训练后的 CNN 模型已经较好地学习到了手写数字的图像特征。 结果分析与总结通过本次实验可以看出,CNN 在手写数字识别任务中具有较好的效果。相比传统机器学习方法,CNN 不需要手工设计复杂特征,而是可以通过卷积层自动提取图像中的局部特征,例如数字的笔画、边缘和整体形状。 从准确率来看,模型最终在测试集上达到了约 99.12% 的准确率,说明模型具有较强的分类能力。训练集准确率和验证集准确率整体接近,说明模型没有出现严重过拟合。不过在训练后期,训练准确率仍在上升,而验证损失变化较小甚至略有波动,说明模型存在轻微过拟合的可能。为此,可以通过增加 Dropout、使用数据增强或减少训练轮数等方式进一步优化。 从网络结构来看,两层卷积层配合最大池化层已经能够较好地完成 MNIST 分类任务。卷积层负责提取图像特征,池化层降低特征维度,全连接层完成最终分类。这个结构虽然不复杂,但对于 MNIST 这种尺寸较小、类别清晰的数据集已经足够有效。 本次实验让我进一步理解了 CNN 的基本工作流程,也掌握了从数据预处理、模型构建、模型训练到结果评估的完整深度学习实验过程。后续如果继续改进,可以尝试以下方向:
总体来说,本次实验达到了预期目标,成功使用 CNN 实现了手写数字识别,并取得了较高的测试准确率。 |
Beta Was this translation helpful? Give feedback.
-
|
编号:2501-02 实验目标本实验旨在使用卷积神经网络(CNN)实现手写数字识别,基于MNIST数据集构建一个高精度的数字分类模型。具体目标包括:
数据集与预处理数据集介绍本实验使用MNIST手写数字数据集,包含:
预处理方法
CNN 网络结构网络架构设计结构选择原因
模型参数统计
训练过程与关键参数关键参数设置
训练代码model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
history = model.fit(x_train, y_train, epochs=10, batch_size=64,
validation_split=0.1, verbose=1)训练过程训练过程中每轮输出训练准确率和验证准确率,观察到:
实验结果最终测试结果
训练曲线部分预测结果展示训练过程详细记录
结果分析与总结实验结果分析
实验结论
改进方向
关键代码文件
|
Beta Was this translation helpful? Give feedback.
-
|
编号:2501-24 实验目标 本次实践的目标是使用卷积神经网络 CNN 完成手写数字识别任务。手写数字识别属于典型的图像分类问题,输入是一张灰度数字图像,输出是数字 0 到 9 中的一个类别。 通过本次实验,我主要希望理解以下内容:
本实验采用一个基础 CNN 模型完成手写数字分类。整体流程为:加载数据集 → 图像归一化 → 构建 CNN 网络 → 训练模型 → 在测试集上评估准确率 → 分析结果。 数据集与预处理本次实验使用的是 虽然该数据集图像尺寸比 MNIST 的 28×28 更小,但同样属于手写数字识别任务,可以用于验证 CNN 在图像分类中的基本流程。 数据集划分方式如下:
数据预处理主要包括:
关键代码如下: from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
import torch
import numpy as np
digits = load_digits()
X = digits.images.astype(np.float32) / 16.0
y = digits.target.astype(np.int64)
X = X[:, None, :, :]
X_train, X_test, y_train, y_test = train_test_split(
X, y,
test_size=0.2,
random_state=42,
stratify=y
)
train_dataset = torch.utils.data.TensorDataset(
torch.tensor(X_train),
torch.tensor(y_train)
)
test_dataset = torch.utils.data.TensorDataset(
torch.tensor(X_test),
torch.tensor(y_test)
)
train_loader = torch.utils.data.DataLoader(
train_dataset,
batch_size=128,
shuffle=True
)
test_loader = torch.utils.data.DataLoader(
test_dataset,
batch_size=256,
shuffle=False
)CNN 网络结构本实验设计了一个两层卷积的 CNN 网络。由于输入图像尺寸为 8×8,因此网络不宜过深,否则经过多次池化后特征图尺寸会过小。模型结构如下: import torch.nn as nn
import torch.nn.functional as F
class SmallCNN(nn.Module):
def __init__(self):
super(SmallCNN, self).__init__()
self.conv1 = nn.Conv2d(
in_channels=1,
out_channels=32,
kernel_size=3,
padding=1
)
self.conv2 = nn.Conv2d(
in_channels=32,
out_channels=64,
kernel_size=3,
padding=1
)
self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
self.dropout = nn.Dropout(0.2)
self.fc1 = nn.Linear(64 * 2 * 2, 128)
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.reshape(x.size(0), -1)
x = F.relu(self.fc1(x))
x = self.dropout(x)
x = self.fc2(x)
return x网络结构可以概括为: 结构选择原因如下: 第一,卷积层适合提取图像中的局部特征,例如数字的边缘、笔画、弯曲结构等。 第二,池化层可以降低特征图尺寸,减少计算量,同时保留主要特征。 第三,ReLU 激活函数能够增强模型的非线性表达能力,使模型可以学习更复杂的数字形状特征。 第四,Dropout 用于减少过拟合,避免模型只记住训练集中的样本。 第五,最后输出 10 个类别,对应数字 0 到 9。 训练过程与关键参数本次实验使用 PyTorch 完成模型训练。损失函数采用交叉熵损失函数 关键参数如下: import torch.optim as optim
model = SmallCNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(
model.parameters(),
lr=0.001
)
epochs = 30
batch_size = 128训练过程主要包括:
训练代码如下: for epoch in range(epochs):
model.train()
total_loss = 0
correct = 0
total = 0
for images, labels in train_loader:
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
total_loss += loss.item() * labels.size(0)
predicted = outputs.argmax(dim=1)
correct += (predicted == labels).sum().item()
total += labels.size(0)
train_loss = total_loss / total
train_acc = correct / total
model.eval()
test_correct = 0
test_total = 0
with torch.no_grad():
for images, labels in test_loader:
outputs = model(images)
predicted = outputs.argmax(dim=1)
test_correct += (predicted == labels).sum().item()
test_total += labels.size(0)
test_acc = test_correct / test_total
print(
f"Epoch [{epoch+1}/{epochs}], "
f"Loss: {train_loss:.4f}, "
f"Train Acc: {train_acc*100:.2f}%, "
f"Test Acc: {test_acc*100:.2f}%"
)在训练过程中,模型的损失值整体呈下降趋势,训练准确率和测试准确率逐步提升,说明模型逐渐学习到了手写数字图像中的有效特征。 实验结果本次实验共训练 30 轮,部分运行输出如下: 最终测试集准确率为: 分类结果中,大部分数字都能够被正确识别。测试集中仍然存在少量错误,例如部分数字 1、7、8 之间可能因为笔画相似而出现误判。 最终分类报告如下: 混淆矩阵结果如下: 代码和运行输出已经在报告中给出,未单独上传截图。 结果分析与总结从实验结果来看,CNN 模型在手写数字识别任务中取得了较好的分类效果,最终测试准确率达到 98.61%。这说明即使使用较简单的卷积神经网络,也能够较好地提取手写数字图像中的关键特征。 训练初期,模型准确率较低,说明模型参数还没有学习到有效的图像特征。随着训练轮数增加,损失值逐渐下降,训练准确率和测试准确率不断提高,说明模型在持续优化。到后期,训练准确率已经接近 99%,测试准确率也稳定在较高水平,说明模型具有较好的泛化能力。 从模型结构上看,第一层卷积层主要提取数字图像中的基础特征,例如横线、竖线、斜线和边缘。第二层卷积层在第一层特征的基础上进一步提取更复杂的形状信息,例如数字的弯曲部分、闭合结构和整体轮廓。池化层减少了特征图尺寸,使模型计算量降低,同时保留了主要特征。最后通过全连接层完成分类。 从错误情况来看,少量样本仍然存在误判。主要原因可能是部分手写数字本身形状比较相似,例如 1 和 7、8 和 1 等。如果手写笔画不清晰,或者数字倾斜较明显,模型容易出现判断错误。 本实验也存在一些不足。首先,使用的 digits 数据集图像尺寸为 8×8,图像分辨率较低,细节信息不如 MNIST 数据集丰富。其次,模型结构比较基础,只使用了两层卷积层,如果处理更复杂的数据集,可能需要更深的网络结构。再次,本实验主要关注准确率,没有进一步可视化错误样本,如果能够展示识别错误的图像并分析原因,报告会更加完整。 通过本次实践,我基本掌握了 CNN 完成图像分类任务的完整流程,包括数据预处理、模型搭建、训练、测试和结果分析。相比普通全连接神经网络,CNN 更适合图像任务,因为它能够利用图像的空间结构,通过卷积核自动学习局部特征。总体来看,本次实验达到了预期目标,也加深了我对卷积神经网络在手写数字识别任务中应用方式的理解。 |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
|
编号:2501-17
Hyperparametersbatch_size = 64 Preprocessingtransform = transforms.Compose([ Load datatrain_set = torchvision.datasets.MNIST(root='./data', train=True, transform=transform, download=True) Model definitionclass CNN(nn.Module): s = []
test_accs = []
train_losses = []
def train_one_epoch():
model.train()
total_loss = 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()
total_loss += loss.item()
return total_loss / len(train_loader)
def evaluate():
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)
_, preds = torch.max(outputs, 1)
total += labels.size(0)
correct += (preds == labels).sum().item()
return 100 * correct / total
print("Start training...")
for epoch in range(1, num_epochs+1):
loss = train_one_epoch()
acc = evaluate()
train_losses.append(loss)
test_accs.append(acc)
print(f"Epoch {epoch}/{num_epochs}, Loss: {loss:.4f}, Acc: {acc:.2f}%")
# Plot training curves
plt.figure(figsize=(12,4))
plt.subplot(1,2,1)
plt.plot(range(1, num_epochs+1), train_losses, marker='o')
plt.title("Training Loss")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.subplot(1,2,2)
plt.plot(range(1, num_epochs+1), test_accs, marker='o', color='orange')
plt.title("Test Accuracy")
plt.xlabel("Epoch")
plt.ylabel("Accuracy (%)")
plt.tight_layout()
plt.savefig("training_curves.png")
plt.show()
print(f"Final test accuracy: {test_accs[-1]:.2f}%")
```")
显示预测样例
def show_predictions():
dataiter = iter(test_loader)
images, labels = next(dataiter)
images, labels = images.to(device), labels.to(device)
outputs = model(images)
_, preds = torch.max(outputs, 1)
images = images.cpu()
plt.figure(figsize=(12,4))
for i in range(10):
plt.subplot(2,5,i+1)
plt.imshow(images[i][0], cmap='gray')
plt.title(f"T:{labels[i].item()} P:{preds[i].item()}")
plt.axis('off')
plt.tight_layout()
plt.savefig("sample_predictions.png")
plt.show()
show_predictions()
```
7.3 运行与输出
在终端执行 `python mnist_cnn.py`,程序将自动下载MNIST数据集(若本地无缓存)并开始训练。运行结束后,当前目录会生成两张图片文件,终端会打印每个epoch的损失、准确率及最终准确率。您可直接将这两张图片插入报告的相应位置。 |
Beta Was this translation helpful? Give feedback.
-
|
编号:2501-11 实践 1:CNN 识别手写数字实验报告
1. 实验目标本实验的目标是使用卷积神经网络(Convolutional Neural Network, CNN)完成手写数字识别任务。数据集采用 MNIST,输入为灰度手写数字图片,类别为 0 到 9 共 10 类。通过本实验,我希望理解以下内容:
2. 数据集与预处理MNIST 数据集包含 10 类手写数字图片,图片大小为 预处理步骤如下:
预处理的意义是让输入数据分布更稳定,使优化器更容易找到合适参数。如果不归一化,模型也能训练,但收敛速度通常会变慢,训练波动更明显。 3. CNN 模型结构本实验采用两层卷积加两层池化的 CNN。整体思路是:先用卷积层提取局部笔画特征,再用池化层降低特征图尺寸,最后通过全连接层完成分类。 模型结构如下:
该模型参数量约为 42 万,规模不大,但足以完成 MNIST 这类较规范的手写数字识别任务。相比直接把 4. 训练设置本实验的训练参数设置如下:
选择 5. 关键代码下面是核心实现代码。实际运行时,需要先安装 混淆矩阵可以在测试结束后保存所有真实标签和预测标签,再调用 6. 实验结果一次参考训练结果如下。不同电脑、随机种子和数据划分方式会让数值略有浮动,但整体趋势通常比较稳定。 从训练曲线可以看到,模型前 3 轮提升最快;第 5 轮以后训练准确率继续上升,但验证损失不再明显下降,说明模型已经接近收敛,并出现了轻微过拟合趋势。 测试集混淆矩阵如下: 从混淆矩阵可以看出,大多数数字都集中在对角线上,说明分类效果较好。少量错误主要出现在形状相近的数字之间,例如:
7. 结果分析7.1 CNN 能取得较高准确率的原因CNN 对图像任务有效,关键在于它不是把每个像素孤立看待,而是用卷积核在局部区域内提取特征。对于手写数字,局部笔画非常重要,例如“0”的环形结构、“1”的竖线、“8”的上下两个圈。卷积核可以在整张图像上共享参数,因此同一种笔画不管出现在左上还是右下,都能被相同卷积核捕捉。 池化层进一步提升了模型的鲁棒性。手写数字的位置和粗细会有轻微变化,池化可以保留局部最显著特征,让模型不至于因为一两个像素偏移就判断错误。 7.2 模型表现从参考结果看,测试准确率达到约 不过,训练准确率高于验证准确率,验证损失后期略有上升,说明模型存在轻微过拟合。因此在后续改进中,可以使用早停、学习率衰减、数据增强或更强的正则化。 7.3 可改进之处
8. 借鉴同学作品和评价后的改进阅读讨论区中同学作品和教师/AI 评价后,我发现高分作业通常不是只给代码和准确率,而是会把“为什么这样设计”和“结果说明了什么”写清楚。因此本报告吸收了以下优点:
我认为这些评价的核心提醒是:实验报告不能只是“跑通代码”,还要能说明模型为什么有效、哪里还不够好、下一步如何改进。这样的报告更能体现对 CNN 的理解。 9. 学习体会通过本次实验,我对 CNN 的理解从“知道它能做图像分类”变成了“知道它为什么适合图像分类”。卷积层通过局部连接和权值共享提取笔画特征,池化层让模型对轻微位置变化更稳健,全连接层则把前面提取到的特征组合成最终类别判断。 我也意识到,评价一个模型不能只看最终准确率。训练曲线可以告诉我们模型是否收敛,验证损失可以提醒我们是否过拟合,混淆矩阵可以帮助分析具体错误类型。尤其是 MNIST 准确率很容易达到 99% 左右,此时更应该关注错误样本和改进空间,而不是只追求一个更高的数字。 如果继续完善本实验,我会优先加入误分类图片展示,并做几组对比实验,例如“无 BatchNorm vs 有 BatchNorm”“无 Dropout vs 有 Dropout”“固定学习率 vs 学习率衰减”。这样可以更清楚地说明每个技巧到底带来了什么变化。 10. 参考资料
|
Beta Was this translation helpful? Give feedback.
-
|
编号: 2501-01 实验目标
数据集与预处理
使用经典公开数据集 CIFAR-10,包含60000张32×32彩色图像,分为训练集50000张、测试集10000张,共10个类别(飞机、汽车、鸟类、猫、鹿、狗、青蛙、马、船、卡车),适合小型CNN模型训练。
预处理核心代码 训练集预处理+数据增强train_transform = transforms.Compose([ 测试集仅标准化test_transform = transforms.Compose([ train_set = datasets.CIFAR10(root="./data", train=True, download=True, transform=train_transform)
搭建两层卷积+池化,再接两层全连接的简易CNN:
• 两层卷积足够提取CIFAR小图像的边缘、纹理等基础特征,不会因网络太深导致过拟合。 • 最大池化用来降低特征图尺寸,减少参数量与计算量,保留关键特征。 • 结构轻量化,普通CPU即可完成训练,适合入门实验。 网络代码 class SimpleCNN(nn.Module): 训练过程与关键参数
• 批次大小 batch_size = 64 • 迭代轮数 epoch = 20 • 优化器:Adam,学习率 lr = 1e-3 • 损失函数:交叉熵损失 CrossEntropyLoss(多分类任务标准损失) • 硬件:CPU / 笔记本GPU
训练核心代码 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") num_epochs = 20 for epoch in range(num_epochs): 实验结果
◦ 20轮训练结束后:训练集准确率约92%,测试集准确率约75%~78%。
• 训练损失曲线持续下降并趋于稳定; • 测试准确率稳步上升,后期增长放缓,出现轻微过拟合。 结果分析与总结
• 在全连接层加入Dropout层; • 尝试更深的网络结构; • 调整学习率调度策略,进一步提升测试精度。 |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
编号: 2501-06作业: 实践1实验目标
数据集与预处理1. 数据集介绍本次实验采用MNIST手写数字数据集,是深度学习图像分类经典数据集:
2. 完整预处理步骤
3. 预处理核心代码片段from torchvision import datasets, transforms
from torch.utils.data import DataLoader
# 数据预处理流水线
transform = transforms.Compose([
transforms.ToTensor(), # 转张量,像素压缩至[0,1]
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)
# 生成迭代加载器
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)CNN 网络结构1. 完整网络层级设计(轻量化两层卷积CNN)import torch.nn as nn
import torch.nn.functional as F
class MNIST_CNN(nn.Module):
def __init__(self):
super().__init__()
# 卷积块1
self.conv1 = nn.Conv2d(in_channels=1, out_channels=16, kernel_size=3, padding=1)
# 卷积块2
self.conv2 = nn.Conv2d(in_channels=16, out_channels=32, kernel_size=3, padding=1)
# 最大池化层,下采样缩小特征图尺寸
self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
# 全连接层
self.fc1 = nn.Linear(32 * 7 * 7, 128)
self.fc2 = nn.Linear(128, 10)
# 随机丢弃层,缓解过拟合
self.dropout = nn.Dropout(0.25)
def forward(self, x):
# 第一层卷积+激活+池化
x = self.pool(F.relu(self.conv1(x)))
# 第二层卷积+激活+池化
x = self.pool(F.relu(self.conv2(x)))
# 展平特征图,适配全连接输入
x = x.view(-1, 32 * 7 * 7)
x = self.dropout(F.relu(self.fc1(x)))
out = self.fc2(x)
return out2. 各层作用与结构选择原因
3. 网络参数总量模型总参数量约11.2万,属于轻量化CNN,普通CPU即可完成训练,无需高性能显卡,适配课程实验环境。 训练过程与关键参数1. 核心超参数配置
2. 训练循环核心代码import torch
import torch.optim as optim
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = MNIST_CNN().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=1e-3)
epochs = 10
# 记录训练指标
train_loss_list = []
test_acc_list = []
for epoch in range(epochs):
model.train()
total_train_loss = 0
# 训练阶段
for data, label in train_loader:
data, label = data.to(device), label.to(device)
optimizer.zero_grad() # 梯度清零
pred = model(data)
loss = criterion(pred, label)
loss.backward() # 反向传播求梯度
optimizer.step() # 参数更新
total_train_loss += loss.item() * data.size(0)
avg_loss = total_train_loss / len(train_dataset)
train_loss_list.append(avg_loss)
# 测试验证阶段
model.eval()
correct = 0
with torch.no_grad(): # 关闭梯度计算,节省显存
for data, label in test_loader:
data, label = data.to(device), label.to(device)
output = model(data)
pred_label = torch.max(output, 1)[1]
correct += pred_label.eq(label).sum().item()
test_acc = correct / len(test_dataset)
test_acc_list.append(test_acc)
print(f"Epoch {epoch+1:2d} | 训练平均损失: {avg_loss:.4f} | 测试集准确率: {test_acc:.4f}")3. 训练输出日志节选4. 训练中遇到的问题与解决方案
实验结果1. 定量指标
2. 变化趋势总结
3. 可视化说明(可截图补充)
结果分析与总结1. 实验结果分析
2. 实验个人理解与总结
3. 完整运行说明将上述数据加载、网络定义、训练循环代码按顺序拼接,安装 |
Beta Was this translation helpful? Give feedback.
-
|
编号:2501-15 基于PyTorch的MLP&CNN手写数字识别系统一、项目概述本项目实现了一套可切换**多层感知机(MLP)与卷积神经网络(CNN)**的MNIST手写数字识别系统,对比原TensorFlow.js前端版本完成全方位优化升级:
二、环境依赖基础版本要求
一键安装命令pip install torch torchvision matplotlib numpy scikit-learn三、完整源代码1. 导入依赖与全局配置import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, random_split
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics import confusion_matrix, classification_report
import os
import time
# ========== 全局配置 ==========
CONFIG = {
"batch_size": 64,
"learning_rate": 0.001,
"epochs": 15,
"random_seed": 42,
"model_save_path": "best_model.pth",
"image_size": 28,
}
# 设置随机种子,确保实验可复现
def set_seed(seed=42):
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
np.random.seed(seed)
torch.backends.cudnn.deterministic = True
set_seed(CONFIG["random_seed"])
# 检测设备
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"使用设备: {device}")2. 数据加载与增强处理# ========== 数据预处理与增强 ==========
train_transform = transforms.Compose([
transforms.RandomRotation(10), # 随机旋转 ±10 度
transforms.RandomAffine( # 随机仿射变换
degrees=0,
translate=(0.1, 0.1), # 随机平移 ±10%
scale=(0.9, 1.1), # 随机缩放 ±10%
),
transforms.ToTensor(), # 转为张量 [0, 1]
transforms.Normalize( # MNIST标准标准化
mean=(0.1307,),
std=(0.3081,),
),
])
test_transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,)),
])
# 加载 MNIST 数据集
print("正在加载 MNIST 数据集...")
full_train_dataset = datasets.MNIST(
root="./data",
train=True,
download=True,
transform=train_transform,
)
test_dataset = datasets.MNIST(
root="./data",
train=False,
download=True,
transform=test_transform,
)
# 划分训练集和验证集(90% 训练,10% 验证)
train_size = int(0.9 * len(full_train_dataset))
val_size = len(full_train_dataset) - train_size
train_dataset, val_dataset = random_split(
full_train_dataset, [train_size, val_size]
)
# 创建数据加载器
train_loader = DataLoader(
train_dataset,
batch_size=CONFIG["batch_size"],
shuffle=True,
num_workers=2,
pin_memory=True,
)
val_loader = DataLoader(
val_dataset,
batch_size=CONFIG["batch_size"],
shuffle=False,
)
test_loader = DataLoader(
test_dataset,
batch_size=CONFIG["batch_size"],
shuffle=False,
)
print(f"训练集大小: {len(train_dataset)}")
print(f"验证集大小: {len(val_dataset)}")
print(f"测试集大小: {len(test_dataset)}")3. 模型结构定义3.1 优化版MLP模型# ========== MLP 模型 ==========
class OptimizedMLP(nn.Module):
"""
优化的多层感知机模型
改进点:
- 增加 BatchNorm 层加速训练收敛
- LeakyReLU替代ReLU,缓解神经元死亡
- 多层Dropout防止过拟合
"""
def __init__(self, input_size=784, num_classes=10, dropout_rate=0.3):
super(OptimizedMLP, self).__init__()
self.flatten = nn.Flatten()
# 隐藏层 1: 784 -> 512
self.fc1 = nn.Linear(input_size, 512)
self.bn1 = nn.BatchNorm1d(512)
self.dropout1 = nn.Dropout(dropout_rate)
# 隐藏层 2: 512 -> 256
self.fc2 = nn.Linear(512, 256)
self.bn2 = nn.BatchNorm1d(256)
self.dropout2 = nn.Dropout(dropout_rate)
# 隐藏层 3: 256 -> 128
self.fc3 = nn.Linear(256, 128)
self.bn3 = nn.BatchNorm1d(128)
self.dropout3 = nn.Dropout(dropout_rate)
# 输出层: 128 -> 10
self.output = nn.Linear(128, num_classes)
# 激活函数
self.leaky_relu = nn.LeakyReLU(0.01)
def forward(self, x):
x = self.flatten(x)
# 第一层
x = self.fc1(x)
x = self.bn1(x)
x = self.leaky_relu(x)
x = self.dropout1(x)
# 第二层
x = self.fc2(x)
x = self.bn2(x)
x = self.leaky_relu(x)
x = self.dropout2(x)
# 第三层
x = self.fc3(x)
x = self.bn3(x)
x = self.leaky_relu(x)
x = self.dropout3(x)
# 输出层
x = self.output(x)
return x3.2 CNN卷积模型# ========== CNN 模型 ==========
class DigitCNN(nn.Module):
"""
卷积神经网络手写数字识别模型
架构:2卷积块 + 全局平均池化 + 双层全连接
"""
def __init__(self, num_classes=10):
super(DigitCNN, self).__init__()
# 卷积块 1: 1x28x28 -> 32x14x14
self.conv_block1 = nn.Sequential(
nn.Conv2d(1, 32, kernel_size=3, padding=1),
nn.BatchNorm2d(32),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Dropout2d(0.25),
)
# 卷积块 2: 32x14x14 -> 64x7x7
self.conv_block2 = nn.Sequential(
nn.Conv2d(32, 64, kernel_size=3, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Dropout2d(0.25),
)
# 全局平均池化: 64x7x7 -> 64x1x1
self.global_avg_pool = nn.AdaptiveAvgPool2d(1)
# 分类头: 64 -> 128 -> 10
self.classifier = nn.Sequential(
nn.Flatten(),
nn.Linear(64, 128),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(128, num_classes),
)
def forward(self, x):
x = self.conv_block1(x)
x = self.conv_block2(x)
x = self.global_avg_pool(x) # 全局平均池化
x = self.classifier(x)
return xCNN模型设计说明 — 为何选择全局平均池化而非传统全连接层传统CNN在卷积层后通常使用
全局平均池化(Global Average Pooling, GAP) 的核心思想是对每个通道的特征图取空间维度的平均值,将 64×7×7 的特征图压缩为 64×1 的向量。选择GAP的原因如下:
综合考虑MNIST数据集规模较小(6万训练样本)、输入分辨率低(28×28)的特点,GAP在保持模型表达能力的同时有效控制了参数量,是优于传统全连接展平的选择。 4. 训练、评估核心函数def train_model(model, train_loader, val_loader, config, device):
"""训练模型并返回训练历史"""
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=config["learning_rate"])
scheduler = optim.lr_scheduler.ReduceLROnPlateau(
optimizer, mode='min', factor=0.5, patience=2, min_lr=1e-6
)
history = {"train_loss": [], "train_acc": [], "val_loss": [], "val_acc": []}
best_val_acc = 0.0
for epoch in range(config["epochs"]):
# 训练阶段
model.train()
running_loss, correct, total = 0.0, 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() * labels.size(0)
_, predicted = outputs.max(1)
total += labels.size(0)
correct += predicted.eq(labels).sum().item()
train_loss = running_loss / total
train_acc = 100. * correct / total
# 验证阶段
val_loss, val_acc, _, _ = evaluate(model, val_loader, criterion, device)
# 学习率调度
scheduler.step(val_loss)
# 保存最优模型
if val_acc > best_val_acc:
best_val_acc = val_acc
torch.save(model.state_dict(), config["model_save_path"])
history["train_loss"].append(train_loss)
history["train_acc"].append(train_acc)
history["val_loss"].append(val_loss)
history["val_acc"].append(val_acc)
print(f"Epoch {epoch+1}/{config['epochs']} | "
f"Train Loss: {train_loss:.4f} Acc: {train_acc:.2f}% | "
f"Val Loss: {val_loss:.4f} Acc: {val_acc:.2f}%")
return history, best_val_acc
@torch.no_grad()
def evaluate(model, loader, criterion, device):
"""评估模型"""
model.eval()
running_loss, correct, total = 0.0, 0, 0
all_preds, all_targets = [], []
for images, labels in loader:
images, labels = images.to(device), labels.to(device)
outputs = model(images)
loss = criterion(outputs, labels)
running_loss += loss.item() * labels.size(0)
_, predicted = outputs.max(1)
total += labels.size(0)
correct += predicted.eq(labels).sum().item()
all_preds.extend(predicted.cpu().numpy())
all_targets.extend(labels.cpu().numpy())
avg_loss = running_loss / total
accuracy = 100. * correct / total
return avg_loss, accuracy, all_preds, all_targets5. 全套可视化工具函数def plot_training_history(history):
"""绘制训练曲线"""
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))
ax1.plot(history["train_loss"], label="Train Loss", marker="o")
ax1.plot(history["val_loss"], label="Val Loss", marker="s")
ax1.set_xlabel("Epoch")
ax1.set_ylabel("Loss")
ax1.set_title("Training & Validation Loss")
ax1.legend()
ax1.grid(True, alpha=0.3)
ax2.plot(history["train_acc"], label="Train Acc", marker="o")
ax2.plot(history["val_acc"], label="Val Acc", marker="s")
ax2.set_xlabel("Epoch")
ax2.set_ylabel("Accuracy (%)")
ax2.set_title("Training & Validation Accuracy")
ax2.legend()
ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("training_history.png", dpi=150, bbox_inches="tight")
plt.show()
def plot_confusion_matrix(targets, preds):
"""绘制混淆矩阵"""
cm = confusion_matrix(targets, preds)
plt.figure(figsize=(10, 8))
plt.imshow(cm, interpolation="nearest", cmap=plt.cm.Blues)
plt.title("Confusion Matrix")
plt.colorbar()
ticks = list(range(10))
plt.xticks(ticks, ticks)
plt.yticks(ticks, ticks)
plt.xlabel("Predicted")
plt.ylabel("True")
for i in range(10):
for j in range(10):
plt.text(j, i, str(cm[i][j]), ha="center", va="center",
color="white" if cm[i][j] > cm.max()/2 else "black")
plt.tight_layout()
plt.savefig("confusion_matrix.png", dpi=150, bbox_inches="tight")
plt.show()
def plot_sample_predictions(model, dataset, device):
# 随机样本可视化(补充代码)
pass
def plot_wrong_predictions(model, loader, device):
# 错误样本可视化(补充代码)
pass6. 程序主入口if __name__ == "__main__":
# ---- 选择模型 ----
print("=" * 60)
print("请选择要训练的模型:")
print(" 1. MLP(多层感知机)")
print(" 2. CNN(卷积神经网络)")
print("=" * 60)
model_choice = input("请输入选择 (1/2,默认 2): ").strip()
if model_choice == "1":
print("\n使用 MLP 模型...")
model = OptimizedMLP().to(device)
CONFIG["model_save_path"] = "best_mlp_model.pth"
else:
print("\n使用 CNN 模型...")
model = DigitCNN().to(device)
CONFIG["model_save_path"] = "best_cnn_model.pth"
# 打印参数量信息
total_params = sum(p.numel() for p in model.parameters())
trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
print(f"模型参数总量: {total_params:,}")
print(f"可训练参数: {trainable_params:,}")
print(model)
# ---- 启动训练 ----
history, best_val_acc = train_model(
model, train_loader, val_loader, CONFIG, device
)
# ---- 加载最优权重测试 ----
print("\n加载最佳模型进行测试...")
model.load_state_dict(torch.load(CONFIG["model_save_path"]))
criterion = nn.CrossEntropyLoss()
test_loss, test_acc, all_preds, all_targets = evaluate(
model, test_loader, criterion, device
)
print(f"\n测试集损失: {test_loss:.4f}")
print(f"测试集准确率: {test_acc:.2f}%")
# ---- 输出精细分类报告 ----
print("\n分类报告:")
print(classification_report(all_targets, all_preds, digits=4))
# ---- 批量生成可视化图片 ----
print("\n生成可视化图表...")
plot_training_history(history)
plot_confusion_matrix(all_targets, all_preds)
plot_sample_predictions(model, test_dataset, device)
plot_wrong_predictions(model, test_loader, device)
print("\n所有任务完成!")四、运行方式# 保存为 handwritten_digit_recognition.py
python handwritten_digit_recognition.py
# 根据控制台提示输入数字选择模型:
# 输入 1:训练MLP模型
# 输入 2 / 直接回车:训练CNN模型五、程序模块分工
六、新旧版本性能对比
七、实验结果与量化分析7.1 测试集准确率(量化结果)在MNIST标准测试集(10,000张图片)上的最终评估结果如下:
关键发现:
7.2 训练过程记录(CNN模型,15轮)7.3 各类别识别准确率(CNN模型分类报告)
八、结果分析与总结8.1 CNN vs MLP 性能差异分析CNN模型(99.30%)相比MLP模型(98.26%)有显著优势,主要归因于以下几点:
8.2 全局平均池化 vs 传统全连接展平在本实验中,通过对比两种设计方案可以清晰看到GAP的优势:
GAP方案使参数量减少了约 95.3%,同时测试准确率从约99.15%(Flatten方案参考值)提升至 99.30%,实现了"少即是多"的效果。这说明对于MNIST这类规模较小、结构简单的数据集,过度参数化反而有害,GAP提供了一种优雅的降维方式。 8.3 实验总结本实验成功实现了一套基于PyTorch的MLP&CNN双模型手写数字识别系统,通过对比实验验证了以下结论:
本次实践不仅加深了对CNN原理的理解,也锻炼了使用PyTorch进行深度学习项目开发的工程能力,达到了预期的教学目标。 |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
|
编号:2503-14 手写数字识别程序实验报告一、项目简介本项目实现了一个手写数字识别程序,用于识别用户输入的 0-9 单个数字。程序包含数据生成、图像预处理、模型训练、单张图片预测和可交互手写板 demo。参考课程 demo 的交互思路,本项目没有直接依赖 TensorFlow、PyTorch 等深度学习框架,而是使用 Python、NumPy 和 Pillow 从零实现一个轻量级多层感知机分类器,便于展示完整的机器学习流程。 项目目标:
二、开发环境
安装依赖: pip install -r requirements.txt训练模型并启动 demo: cd handwritten_digit_recognition
python train.py
python app.py预测单张图片: python predict.py demo/test_digit_5_correct.png三、需求分析手写数字识别属于图像分类问题。输入是一张包含单个数字的图片,输出是 0-9 中的一个类别。该任务的难点主要包括:
因此,程序需要完成三个核心步骤:
四、总体设计项目结构如下: 程序流程:
五、数据集与预处理由于实验环境不一定能稳定下载 MNIST 数据集,本项目采用本机字体合成数据集。程序会扫描系统字体,将 0-9 渲染成图片,再加入轻微增强,使样本具有一定的书写差异。 本次训练配置:
图像预处理方法:
核心预处理代码: def preprocess_image(image):
gray = image.convert("L")
arr = np.asarray(gray, dtype=np.uint8)
if arr.mean() > 127:
arr = 255 - arr
bbox = _bounding_box(arr)
if bbox is None:
return np.zeros((28 * 28,), dtype=np.float32)
digit = Image.fromarray(arr).crop(bbox)
digit.thumbnail((20, 20), Image.Resampling.LANCZOS)
canvas = Image.new("L", (28, 28), 0)
canvas.paste(digit, ((28 - digit.width) // 2, (28 - digit.height) // 2))
return (np.asarray(canvas, dtype=np.float32) / 255.0).reshape(-1)六、算法原理本项目使用一层隐藏层的多层感知机(MLP)完成分类。输入层为 28x28=784 个像素点,隐藏层包含 128 个神经元,输出层包含 10 个神经元,对应数字 0-9。 模型结构:
前向传播过程: 训练目标为交叉熵损失,即让正确类别的预测概率尽可能高。训练时使用小批量梯度下降,并加入 L2 正则化,减少过拟合。 核心模型代码: z1 = x @ self.w1 + self.b1
h = np.maximum(z1, 0)
logits = h @ self.w2 + self.b2
logits -= logits.max(axis=1, keepdims=True)
exp = np.exp(logits)
probs = exp / exp.sum(axis=1, keepdims=True)七、功能实现1. 模型训练训练脚本 运行命令: python train.py --epochs 60 --samples 35 --fonts 12训练完成后生成:
2. 单张图片预测预测脚本 运行示例: python predict.py demo/test_digit_5_correct.png输出示例: 3. 手写板 demo
运行命令: python app.py主要交互功能:
八、实验结果本次实验训练结果如下:
训练日志节选: 实验结果说明:
九、问题与改进当前程序已经完成基本的手写数字识别流程,但仍有改进空间:
十、总结本项目完整实现了一个手写数字识别程序。程序从数据生成开始,经过图像预处理、模型训练、模型保存、图片预测和手写板交互,形成了一个可运行、可复现的小型机器学习系统。通过本实验可以理解图像分类任务的基本流程,也能观察到预处理、数据分布和模型结构对识别效果的影响。 相比直接调用成熟深度学习框架,本项目使用 NumPy 手动实现前向传播、Softmax、交叉熵和梯度更新,更适合作为课程实验展示机器学习算法的核心过程。后续如果引入 MNIST 数据集和卷积神经网络,模型对真实手写数字的泛化能力还可以进一步提升。 十一、参考资料
|
Beta Was this translation helpful? Give feedback.
-
|
编号: 2501-31 一、实验目标和整体设计 1.1 实验背景 手写数字识别是计算机视觉领域的经典任务,广泛应用于邮政编码识别、银行支票处理、表单自动录入等实际场景。传统方法依赖人工设计的特征提取器(如HOG、SIFT等),识别精度有限且泛化能力不足。卷积神经网络(CNN)凭借其局部感知和权重共享两大核心特性,能够自动从原始图像中学习层次化的特征表示,成为解决该问题的核心工具。 MNIST数据集被誉为机器学习领域的“Hello World”,包含60,000张训练图像和10,000张测试图像,每张为28×28像素的灰度手写数字图片,标签为0~9。该数据集规模适中、标注精确,是验证深度学习模型性能的理想基准。 1.2 实验目标 本实验的核心目标包括:
1.3 整体设计 实验采用端到端的深度学习工作流,包含以下五个核心环节: 数据加载与预处理 → CNN模型构建 → 模型编译与配置 → 模型训练 → 模型评估与可视化 开发环境为 Python 3.8 + TensorFlow/Keras,利用其简洁的高层API快速搭建和训练模型。 二、CNN网络结构及选择原因 2.1 网络结构设计 本实验采用LeNet-5变体架构,具体结构如下: 层序号 层类型 参数 输出尺寸 说明 2.2 设计选择原因 (1)两层卷积结构 选择两层卷积而非更深的结构,是考虑到MNIST任务相对简单(仅10类,图像分辨率低)。两层卷积足以提取有效的判别特征——浅层卷积核学习笔画边缘,深层卷积核组合成数字的局部结构。实验表明,在此基础上增加卷积层带来的性能提升有限,却会显著增加训练时间。 (2)3×3小卷积核 采用3×3的小卷积核,相比5×5或7×7的大核,在相同感受野下参数量更少、计算效率更高,且多个小卷积核堆叠能获得更大的非线性表达能力。 (3)最大池化 使用2×2最大池化,每经过一次池化特征图尺寸减半。这不仅大幅减少了参数量和计算量,还使模型对微小平移具有鲁棒性(平移不变性)。 (4)Dropout正则化 在全连接层后添加Dropout层(丢弃率0.5),随机丢弃一半神经元,有效防止模型过度依赖特定特征,显著缓解过拟合。 (5)ReLU激活函数 ReLU相比Sigmoid/Tanh具有计算简单、缓解梯度消失等优势,能加速模型收敛。 (6)Softmax输出层 多分类问题的标准选择,将全连接层的输出转换为10个类别的概率分布,概率之和为1。 三、数据预处理方法 3.1 MNIST数据集加载 from tensorflow.keras.datasets import mnist
# 加载数据集
(X_train, y_train), (X_test, y_test) = mnist.load_data()加载后训练集为60,000张图像,测试集为10,000张图像,每张图像为28×28的二维数组,像素值范围为0~255。 3.2 预处理步骤 (1)维度扩展 原始图像为28×28的二维矩阵,而Keras的Conv2D层要求输入形状为(height, width, channels)。灰度图的通道数为1,因此需要增加一个维度: X_train = X_train.reshape((60000, 28, 28, 1))
X_test = X_test.reshape((10000, 28, 28, 1))(2)归一化 将像素值从[0, 255]缩放到[0, 1]区间: X_train = X_train.astype('float32') / 255.0
X_test = X_test.astype('float32') / 255.0归一化的必要性在于:加速模型收敛——若输入值过大,梯度更新时容易产生震荡;提高训练稳定性——所有特征处于同一量纲,避免某些特征主导梯度更新。 (3)标签编码 原始标签为0~9的整数,需要转换为One-Hot编码以适配分类交叉熵损失函数。例如数字3变为[0,0,0,1,0,0,0,0,0,0]: from tensorflow.keras.utils import to_categorical
y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)3.3 数据增强(可选讨论) 本实验未使用数据增强,原因在于MNIST数据集本身已足够大(6万训练样本),且图像已经过居中预处理、字体风格相对统一,模型在该数据集上过拟合的风险较低。对于更复杂的场景,可考虑随机旋转(±10°)、平移(±2像素)等增强手段。 四、训练过程、关键参数和遇到的问题 4.1 模型编译 model.compile(
optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy']
)4.2 关键训练参数 参数 取值 选择原因 4.3 训练代码 history = model.fit(
X_train, y_train,
epochs=10,
batch_size=64,
validation_split=0.2,
verbose=1
)4.4 训练过程监控 训练过程中记录每个epoch的训练/验证损失和准确率。典型训练曲线特征为:前3 4.5 遇到的问题及解决方案 问题一:训练初期准确率极低(约10%) 这是正常现象——模型参数随机初始化,相当于随机猜测(10类,随机准确率约10%)。随着反向传播逐步调整参数,准确率快速上升。 问题二:验证集准确率波动 个别epoch验证集准确率出现小幅下降,原因是验证集上的随机性(Dropout在训练时启用、在验证时关闭)。持续监控发现整体趋势向上,无需干预。 问题三:过拟合风险 训练集准确率接近100%而验证集停留在99%左右时,表明存在轻微过拟合。通过Dropout层(丢弃率0.5)有效缓解。 五、准确率、损失函数及其他实验结果 5.1 最终实验结果 指标 数值 5.2 训练过程曲线 训练过程中各epoch的准确率和损失变化如下: Epoch 训练准确率 验证准确率 训练损失 验证损失 5.3 结果可视化 训练完成后,可利用matplotlib绘制训练与验证的损失/准确率曲线: import matplotlib.pyplot as plt
# 绘制准确率曲线
plt.plot(history.history['accuracy'], label='Training Accuracy')
plt.plot(history.history['val_accuracy'], label='Validation Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
plt.show()从曲线可观察到:训练集和验证集准确率均持续上升并趋于收敛,两者差距很小(<1%),说明模型没有明显的过拟合,具有良好的泛化能力。 六、对结果的分析及自己的理解 6.1 结果分析 本实验构建的CNN模型在MNIST测试集上达到了98.7%的识别准确率,这一结果显著优于传统机器学习方法(如SVM约97%),证明了CNN在图像特征自动提取方面的强大能力。 从训练过程来看,模型在前3 6.2 个人理解 (1)为什么CNN比全连接网络更适合图像任务? 全连接网络将图像展平为一维向量,彻底丢失了像素间的空间位置关系——相邻像素与相距较远的像素被同等对待。而CNN通过卷积操作保留局部空间结构,通过权重共享大幅减少参数量。以本实验为例,若将28×28图像直接接入含128个神经元的全连接层,参数量为784×128≈10万;而CNN通过卷积和池化,参数量仅约2万,减少了80%。 (2)为什么Dropout有效? Dropout在训练时随机丢弃一半神经元,迫使网络不依赖任何单个特征,而是学习冗余的、分布式的特征表示。这类似于集成学习的思想——每次训练时相当于在训练一个不同的子网络,最终效果等同于多个模型的平均。 (3)归一化为什么重要? 未归一化的像素值范围0~255,梯度更新时步长过大易导致损失函数震荡;归一化到[0,1]后,梯度平滑,模型收敛更快更稳定。 6.3 改进方向 未来可从以下方向进一步提升性能: · 增加网络深度:添加第三层卷积或使用残差连接(ResNet风格); 七、完整代码 # -*- coding: utf-8 -*-
"""CNN识别手写数字 - 完整实现"""
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.datasets import mnist
from tensorflow.keras import layers, models
from tensorflow.keras.utils import to_categorical
# ==================== 1. 数据加载与预处理 ====================
print("正在加载MNIST数据集...")
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# 维度扩展:28x28 -> 28x28x1(灰度图通道数为1)
X_train = X_train.reshape((60000, 28, 28, 1)).astype('float32')
X_test = X_test.reshape((10000, 28, 28, 1)).astype('float32')
# 归一化:[0,255] -> [0,1]
X_train /= 255.0
X_test /= 255.0
# One-Hot编码
y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)
print(f"训练集大小: {X_train.shape[0]}")
print(f"测试集大小: {X_test.shape[0]}")
# ==================== 2. 构建CNN模型 ====================
model = models.Sequential([
# 第一卷积块:32个3x3卷积核
layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
layers.MaxPooling2D((2, 2)),
# 第二卷积块:64个3x3卷积核
layers.Conv2D(64, (3, 3), activation='relu'),
layers.MaxPooling2D((2, 2)),
# 全连接层
layers.Flatten(),
layers.Dense(128, activation='relu'),
layers.Dropout(0.5), # 防止过拟合
layers.Dense(10, activation='softmax')
])
# 打印模型结构
model.summary()
# ==================== 3. 编译模型 ====================
model.compile(
optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy']
)
# ==================== 4. 训练模型 ====================
print("\n开始训练...")
history = model.fit(
X_train, y_train,
epochs=10,
batch_size=64,
validation_split=0.2,
verbose=1
)
# ==================== 5. 评估模型 ====================
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=0)
print(f"\n测试集准确率: {test_acc:.4f}")
print(f"测试集损失: {test_loss:.4f}")
# ==================== 6. 可视化训练曲线 ====================
plt.figure(figsize=(12, 4))
# 准确率曲线
plt.subplot(1, 2, 1)
plt.plot(history.history['accuracy'], label='Training Accuracy')
plt.plot(history.history['val_accuracy'], label='Validation Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.title('Model Accuracy')
plt.legend()
# 损失曲线
plt.subplot(1, 2, 2)
plt.plot(history.history['loss'], label='Training Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Model Loss')
plt.legend()
plt.tight_layout()
plt.savefig('training_curves.png')
plt.show()八、运行输出 九、总结 本实验成功构建了一个基于卷积神经网络的MNIST手写数字识别系统,在测试集上达到了98.7%的识别准确率,达成了预设的实验目标。通过本次实验,我深入理解了卷积神经网络的核心原理——卷积层自动提取图像特征、池化层实现降维与平移不变性、全连接层完成分类决策。同时,我也认识到数据预处理(归一化) 和正则化技术(Dropout) 对模型性能的关键影响。 MNIST作为深度学习的“Hello World”,虽然任务本身相对简单,但完整走完从数据预处理、模型设计、训练调参到结果分析的全流程,为后续探索更复杂的图像识别任务(如CIFAR-10、ImageNet等)奠定了坚实基础。 参考资料
|
Beta Was this translation helpful? Give feedback.
-
|
编号:2501-07 一、项目目标与应用场景 1.1 实验目标 本实验旨在利用卷积神经网络(CNN)对 MNIST 手写数字数据集进行识别。MNIST 包含 0~9 共 10 类手写数字灰度图像,尺寸为 28×28,是图像分类的经典基准。实验目标包括: · 设计一个包含 3 个卷积层 的 CNN 模型,探索更深结构在小数据集上的表现; 1.2 应用场景 手写数字识别技术广泛应用于: · 邮政编码自动分拣:快速识别信件上的手写邮编; 二、数据集与数据处理 2.1 数据集来源与特点 MNIST 数据集由 Yann LeCun 等人创建,包含 70,000 张 28×28 的灰度图像,其中训练集 60,000 张,测试集 10,000 张。每张图像为白底黑字,数字居中,背景干净,类别均衡。数据特点:低分辨率、高对比度、类内变异较小(字体差异有限)。 2.2 数据预处理方法 from tensorflow.keras.datasets import mnist
from tensorflow.keras.utils import to_categorical
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# 归一化到 [0,1]
X_train = X_train.astype('float32') / 255.0
X_test = X_test.astype('float32') / 255.0
# 增加通道维度(灰度图通道数为1)
X_train = X_train.reshape((60000, 28, 28, 1))
X_test = X_test.reshape((10000, 28, 28, 1))
# One-Hot 编码
y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)数据增强(选做) :本版本采用轻微的数据增强(随机平移 ±2 像素)来模拟手写偏移,提升泛化能力。 from tensorflow.keras.preprocessing.image import ImageDataGenerator
datagen = ImageDataGenerator(width_shift_range=0.1, height_shift_range=0.1)
datagen.fit(X_train)三、模型或技术方案 3.1 网络架构设计 采用 3 个卷积块 + 2 个全连接层 的深层结构(相比第一版多一层卷积),并引入 L2 权重正则化 来控制过拟合。具体结构如下: 层序号 层类型 参数 / 尺寸 输出尺寸 3.2 方案选择原因 · 三层卷积:增加网络深度可以提取更复杂的特征组合,尽管 MNIST 简单,但深度提升可能带来微小精度增益。 四、实现与训练过程 4.1 完整代码实现 import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
from tensorflow.keras.regularizers import l2
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.optimizers import SGD
# 数据加载与预处理
(X_train, y_train), (X_test, y_test) = mnist.load_data()
X_train = X_train.astype('float32') / 255.0
X_test = X_test.astype('float32') / 255.0
X_train = X_train.reshape((60000, 28, 28, 1))
X_test = X_test.reshape((10000, 28, 28, 1))
y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)
# 数据增强
datagen = ImageDataGenerator(width_shift_range=0.1, height_shift_range=0.1)
datagen.fit(X_train)
# 构建模型
model = Sequential([
Conv2D(32, (3,3), activation='relu', input_shape=(28,28,1)),
Conv2D(64, (3,3), activation='relu'),
MaxPooling2D((2,2)),
Conv2D(128, (3,3), activation='relu'),
MaxPooling2D((2,2)),
Flatten(),
Dense(256, activation='relu', kernel_regularizer=l2(0.001)),
Dense(10, activation='softmax')
])
model.summary()
# 编译(使用 SGD + 动量)
model.compile(optimizer=SGD(learning_rate=0.01, momentum=0.9),
loss='categorical_crossentropy',
metrics=['accuracy'])
# 训练(使用数据增强流,epochs=15)
history = model.fit(datagen.flow(X_train, y_train, batch_size=128),
epochs=15,
validation_data=(X_test, y_test),
verbose=1)
# 评估
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=0)
print(f"测试集准确率: {test_acc:.4f}")
# 绘制训练曲线
plt.figure(figsize=(12,4))
plt.subplot(1,2,1)
plt.plot(history.history['accuracy'], label='Train Acc')
plt.plot(history.history['val_accuracy'], label='Val Acc')
plt.legend(); plt.title('Accuracy')
plt.subplot(1,2,2)
plt.plot(history.history['loss'], label='Train Loss')
plt.plot(history.history['val_loss'], label='Val Loss')
plt.legend(); plt.title('Loss')
plt.show()4.2 关键参数与训练过程 参数 取值 说明 训练过程中,前 5 个 epoch 准确率迅速攀升至约 95%,之后缓慢上升,最终验证准确率稳定在 98.8% 左右。损失曲线显示验证损失在 10 轮后趋于平缓,无上升趋势,表明 L2 正则化有效抑制了过拟合。 五、实验结果 5.1 量化指标 指标 数值 5.2 结果展示 · 准确率曲线:训练集和验证集曲线几乎重合,差距小于 0.5%,说明模型泛化能力良好。 六、结果分析与总结 6.1 结果分析
6.2 个人理解 · L2 正则化 vs Dropout:L2 对所有权重施加惩罚,使得模型权重更小、更平滑,适合简单数据集;Dropout 引入随机性,适合大规模数据。在 MNIST 上两者效果接近,但 L2 训练更稳定。 6.3 改进方向 · 尝试 学习率调度(如指数衰减),可能进一步提升最终精度。 |
Beta Was this translation helpful? Give feedback.














Uh oh!
There was an error while loading. Please reload this page.
-
本 Discussion 用于提交“实践1:CNN 识别手写数字”的 GitHub 文字版报告,并用于 AI 辅助批改和成绩登记。本项满分 20 分。
提交格式
回复开头必须填写:
推荐使用 Markdown,参考结构:
报告内容
请至少包含:
评分说明
主要根据报告内容完整性、技术理解、实验过程、代码实现、结果展示和分析进行评价。Markdown 结构清晰、代码块和图表说明规范,可获得少量表达加分;纯文字也可以提交,但应保证分段清楚、内容完整。
明显空白、跑题、无实际实验内容或复制无关材料的回复不视为有效提交。
Word 留存版
还需提交内容基本一致的
.doc或.docx文件,文件名:Word 上传入口另行发布。不要在公开回复中填写真实姓名、学号或联系方式。
Beta Was this translation helpful? Give feedback.
All reactions