深度学习入门教程:用全连接神经网络识别手写数字
深度学习入门教程:用全连接神经网络识别手写数字
1. 引言
1.1 什么是深度学习?
深度学习是机器学习的一个分支,它通过模拟人脑的神经网络结构,让计算机能够从数据中自动学习特征和规律。
就像我们人类通过不断学习来提高自己的能力一样,深度学习模型也可以通过大量的数据训练来提高自己的性能。
1.2 为什么要学习深度学习?
深度学习已经在很多领域取得了突破性的进展,比如:
- 图像识别:自动驾驶、人脸识别、医疗影像分析
- 自然语言处理:机器翻译、语音识别、聊天机器人
- 推荐系统:电商推荐、视频推荐
学习深度学习可以让你掌握这些前沿技术,为未来的职业发展打下坚实的基础。
1.3 本教程的目标
在本教程中,我们将:
- 在WSL Ubuntu上安装GPU版的PyTorch
- 学习全连接深度神经网络的基本原理
- 用PyTorch实现一个手写数字识别模型
- 训练和测试模型,分析结果
2. 环境搭建
2.1 WSL Ubuntu安装
首先,我们需要在Windows上安装WSL(Windows Subsystem for Linux)。请按照微软官方文档的步骤进行安装:安装WSL
2.2 GPU驱动安装
要使用GPU加速深度学习,我们需要安装NVIDIA GPU驱动。请从NVIDIA官网下载并安装适合你GPU型号的驱动:NVIDIA驱动下载
2.3 安装Python环境
-
升级系统环境
sudo apt update && sudo apt -y dist-upgrade -
安装Python 3.12
sudo apt -y install --upgrade python3 python3-pip python3.12-venv -
设置国内镜像源(加速下载)
pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
2.4 创建虚拟环境
虚拟环境可以隔离不同项目的依赖,避免版本冲突。
-
创建项目目录
mkdir pytorch-code && cd pytorch-code -
创建并激活虚拟环境
python3 -m venv .venv && source .venv/bin/activate -
升级基础依赖
python -m pip install --upgrade pip setuptools wheel -i https://pypi.tuna.tsinghua.edu.cn/simple
2.5 安装PyTorch
PyTorch是一个流行的深度学习框架,它提供了丰富的工具和API,方便我们构建和训练深度学习模型。
pip install torch torchvision torchaudio -i https://pypi.tuna.tsinghua.edu.cn/simple
# cuda13预览版可使用以下命令 生产环境切勿使用以下命令
pip install --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/nightly/cu130
本案例使用到的其它依赖库
pip install matplotlib seaborn scikit-learn -i https://pypi.tuna.tsinghua.edu.cn/simple
2.6 验证安装
安装完成后,我们可以运行以下命令来验证PyTorch和CUDA是否正确安装:
import torch
print(f"PyTorch版本: {torch.__version__}")
print(f"CUDA是否可用: {torch.cuda.is_available()}")
if torch.cuda.is_available():
print(f"GPU型号: {torch.cuda.get_device_name(0)}")
print(f"CUDA版本: {torch.version.cuda}")
如果输出显示CUDA可用,并且显示了你的GPU型号,说明安装成功!
3. 神经网络原理大白话
3.1 什么是神经网络?
生活场景类比:神经网络就像一个工厂流水线,每个"工人"(神经元)负责一项特定的任务,将输入的"原材料"(数据)一步步加工成最终的"产品"(预测结果)。
3.2 全连接神经网络结构
生活场景类比:全连接神经网络就像一个多层流水线,每层有多个工人,每个工人都和下一层的所有工人有联系,信息可以在层与层之间自由流动。
- 输入层:接收原始数据,比如一张手写数字图片的像素值
- 隐藏层:对输入数据进行处理和特征提取
- 输出层:输出最终的预测结果,比如手写数字的类别
3.3 神经元的工作原理
每个神经元都可以看作是一个简单的函数,它接收一些输入,经过处理后输出一个结果。
让我们用一个生活场景来理解神经元:
假设你想决定今天是否去公园玩。你会考虑几个因素:天气、温度、是否有朋友一起。每个因素都会影响你的决定:
- 如果天气好(晴天),你更可能去公园
- 如果温度适宜(20-25℃),你更可能去公园
- 如果有朋友一起,你更可能去公园
你会给每个因素一个权重,然后综合考虑这些因素,做出最终决定。
神经元的工作原理类似:
- 接收多个输入(比如天气、温度、是否有朋友)
- 给每个输入分配一个权重(比如天气的权重是0.4,温度的权重是0.3,是否有朋友的权重是0.3)
- 计算所有输入和对应权重的乘积之和
- 将结果输入到激活函数中,得到最终输出
3.4 激活函数
激活函数的作用是给神经网络引入非线性,让神经网络可以学习更复杂的特征。
常见的激活函数有:
- ReLU:如果输入大于0,输出等于输入;否则输出0
- Sigmoid:将输入映射到[0, 1]之间
- Tanh:将输入映射到[-1, 1]之间
4. 全连接深度神经网络原理
4.1 手写数字识别问题
MNIST数据集是一个经典的手写数字识别数据集,它包含60,000个训练样本和10,000个测试样本,每个样本是一张28×28像素的灰度图像,对应的标签是0-9的数字。
我们的目标是构建一个神经网络,能够正确识别这些手写数字。
4.2 全连接神经网络架构
对于MNIST手写数字识别,我们将构建一个包含3个隐藏层的全连接神经网络:
- 输入层:28×28=784个神经元,对应图像的每个像素
- 隐藏层1:256个神经元,使用ReLU激活函数
- 隐藏层2:128个神经元,使用ReLU激活函数
- 隐藏层3:64个神经元,使用ReLU激活函数
- 输出层:10个神经元,对应0-9的数字,使用Softmax激活函数
4.3 前向传播
前向传播是指数据从输入层流向输出层的过程:
- 输入层接收图像的像素值
- 每个神经元计算输入和权重的乘积之和,再加上偏置项
- 将结果输入到激活函数中
- 输出传递给下一层,直到到达输出层
- 输出层使用Softmax激活函数,得到每个类别的概率
4.4 损失函数
损失函数用于衡量模型的预测结果与真实标签之间的差距。对于分类问题,我们通常使用交叉熵损失函数:
Loss = − 1 N ∑ i = 1 N ∑ j = 1 C y i j log ( p i j ) \text{Loss} = -\frac{1}{N} \sum_{i=1}^{N} \sum_{j=1}^{C} y_{ij} \log(p_{ij}) Loss=−N1i=1∑Nj=1∑Cyijlog(pij)
其中:
- N N N 是样本数量
- C C C 是类别数量
- y i j y_{ij} yij 是第 i i i个样本属于第 j j j类的真实标签(0或1)
- p i j p_{ij} pij 是第 i i i个样本属于第 j j j类的预测概率
4.5 反向传播
反向传播是指梯度从输出层流向输入层的过程,它用于更新神经网络的权重和偏置,以减少损失函数的值。
- 计算输出层的梯度
- 将梯度反向传播到隐藏层
- 根据梯度更新权重和偏置
- 重复这个过程,直到损失函数的值足够小
4.6 优化器
优化器用于根据梯度更新神经网络的权重和偏置。常见的优化器有:
- SGD(随机梯度下降):每次使用一个批次的数据来计算梯度
- Adam:结合了动量和自适应学习率,收敛速度更快
5. 代码实现与解读
5.1 项目结构
我们的项目按照以下结构组织:
module4/
├── model.py # 模型定义
├── data_loader.py # 数据加载
├── utils.py # 工具函数
├── train.py # 模型训练
├── test.py # 模型测试
├── models/ # 模型保存目录
├── data/ # 数据保存目录
└── results/ # 结果可视化目录
代码架构图
代码流程图
flowchart TD
A[开始] --> B[加载数据<br>data_loader.py]
B --> C[创建模型<br>model.py]
C --> D[训练模型<br>train.py]
D --> E[保存最佳模型<br>models/]
D --> F[绘制训练曲线<br>results/]
E --> G[测试模型<br>test.py]
F --> G
G --> H[生成混淆矩阵<br>results/]
G --> I[生成错误分类样本<br>results/]
G --> J[随机样本测试<br>results/]
H --> K[结束]
I --> K
J --> K
代码关系图
代码时序图
5.2 模型定义(model.py)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
模块4:全连接深度神经网络(手写数字识别)
# 开发思路
1. **问题分析**:
- 任务:MNIST手写数字识别,属于多分类问题
- 输入:28×28像素的灰度图像
- 输出:0-9共10个数字类别
- 挑战:需要从像素级数据中提取有效特征,实现高精度分类
2. **技术选型**:
- 框架:选择PyTorch,因其动态计算图特性适合深度学习入门学习
- 模型:采用多层感知器(MLP),结构简单清晰,便于理解神经网络基本原理
- 激活函数:使用ReLU,解决传统Sigmoid函数的梯度消失问题
- 正则化:引入Dropout,防止模型过拟合
3. **网络架构设计**:
- 输入层:将28×28图像展平为784维向量
- 隐藏层:设计3层全连接隐藏层,神经元数量依次为256、128、64
- 逐层减少神经元数量,实现特征降维和抽象
- 每层后添加ReLU激活和Dropout正则化
- 输出层:10个神经元,对应10个数字类别
4. **损失与优化**:
- 损失函数:交叉熵损失,适合多分类问题
- 优化器:Adam优化器,具有自适应学习率,收敛速度快
# 开发过程
1. **环境配置**:
- 安装PyTorch框架
- 准备MNIST数据集(训练集60,000张,测试集10,000张)
2. **模型设计**:
- 定义MLP类,继承自nn.Module
- 实现__init__方法,初始化网络层和激活函数
- 实现forward方法,定义数据前向传播路径
3. **代码实现**:
- 编写模型类代码
- 添加测试代码,验证模型输入输出形状
- 编写详细注释,提高代码可读性
4. **功能验证**:
- 运行测试代码,检查模型基本功能
- 验证输入输出形状是否符合预期
- 检查是否存在语法错误或运行时异常
5. **后续扩展**:
- 添加模型训练代码
- 实现模型评估功能
- 优化超参数,提高模型准确率
- 可视化训练过程和结果
"""
# 导入PyTorch核心库,用于张量操作和自动微分
import torch
# 导入PyTorch神经网络模块,包含各种层、激活函数等组件
import torch.nn as nn
# 定义多层感知器(MLP)类,继承自nn.Module基类
class MLP(nn.Module):
"""
多层感知器模型类,用于MNIST手写数字识别
参数:
input_size: int, 输入层神经元数量,默认784(28×28)
hidden_sizes: list, 隐藏层神经元数量列表,默认[256, 128, 64]
output_size: int, 输出层神经元数量,默认10(0-9数字)
属性:
fc1: nn.Linear, 第一层全连接层
fc2: nn.Linear, 第二层全连接层
fc3: nn.Linear, 第三层全连接层
fc4: nn.Linear, 输出层
relu: nn.ReLU, ReLU激活函数
dropout: nn.Dropout, Dropout层,防止过拟合
"""
# 类初始化方法,定义网络结构
def __init__(self, input_size=784, hidden_sizes=[256, 128, 64], output_size=10):
# 调用父类nn.Module的初始化方法
super(MLP, self).__init__()
# 定义第一层全连接层:输入层→第一个隐藏层
# 输入维度:input_size,输出维度:hidden_sizes[0]
self.fc1 = nn.Linear(input_size, hidden_sizes[0])
# 定义第二层全连接层:第一个隐藏层→第二个隐藏层
# 输入维度:hidden_sizes[0],输出维度:hidden_sizes[1]
self.fc2 = nn.Linear(hidden_sizes[0], hidden_sizes[1])
# 定义第三层全连接层:第二个隐藏层→第三个隐藏层
# 输入维度:hidden_sizes[1],输出维度:hidden_sizes[2]
self.fc3 = nn.Linear(hidden_sizes[1], hidden_sizes[2])
# 定义输出层:第三个隐藏层→输出层
# 输入维度:hidden_sizes[2],输出维度:output_size
self.fc4 = nn.Linear(hidden_sizes[2], output_size)
# 定义ReLU激活函数,用于隐藏层
self.relu = nn.ReLU()
# 定义Dropout层,随机失活50%神经元,防止过拟合
self.dropout = nn.Dropout(0.5)
# 前向传播方法,定义数据流动路径
def forward(self, x):
"""
前向传播方法,计算模型输出
参数:
x: torch.Tensor, 输入张量,形状为[batch_size, 1, 28, 28]
- batch_size: 批次大小
- 1: 通道数(灰度图像)
- 28×28: 图像尺寸
返回:
x: torch.Tensor, 输出张量,形状为[batch_size, 10]
- 每个元素表示对应类别的预测分数
"""
# 将输入张量展平为一维向量
# 形状转换:[batch_size, 1, 28, 28] → [batch_size, 784]
# -1表示自动计算该维度大小,保持总元素数不变
x = x.view(-1, 784)
# 第一层全连接层计算 → ReLU激活
# 先经过全连接层fc1,再通过ReLU激活函数
x = self.relu(self.fc1(x))
# 应用Dropout,随机失活50%神经元
# 训练时启用,测试时自动关闭
x = self.dropout(x)
# 第二层全连接层计算 → ReLU激活
x = self.relu(self.fc2(x))
# 应用Dropout,随机失活50%神经元
x = self.dropout(x)
# 第三层全连接层计算 → ReLU激活
x = self.relu(self.fc3(x))
# 应用Dropout,随机失活50%神经元
x = self.dropout(x)
# 输出层计算,不使用激活函数
# 后续会使用Softmax转换为概率
x = self.fc4(x)
# 返回模型输出
return x
# 主程序入口,用于测试模型基本功能
if __name__ == "__main__":
# 创建MLP模型实例,使用默认参数
# input_size=784, hidden_sizes=[256, 128, 64], output_size=10
model = MLP()
# 创建随机测试输入,模拟MNIST图像
# 形状:[1, 1, 28, 28]
# - 1: 批次大小
# - 1: 通道数
# - 28×28: 图像尺寸
test_input = torch.randn(1, 1, 28, 28)
# 执行前向传播,获取模型输出
# 调用model.forward(test_input)的简化写法
output = model(test_input)
# 打印输入形状,验证输入格式是否正确
print(f"模型输入形状: {test_input.shape}")
# 打印输出形状,验证模型输出是否符合预期
# 预期形状:[1, 10],对应1个样本的10个类别预测
print(f"模型输出形状: {output.shape}")
# 打印输出值,查看模型初始预测结果
# 初始权重随机,输出值无实际意义,仅用于验证模型功能
print(f"模型输出: {output}")
5.3 数据加载器开发(data_loader.py)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
模块4:数据加载器(MNIST数据集)
# 开发思路
1. **问题分析**:
- MNIST数据集是手写数字识别的经典数据集,包含60,000张训练图片和10,000张测试图片
- 每张图片是28×28像素的灰度图像,标签为0-9的数字
- 需要将原始数据转换为模型可处理的格式,并按批次加载
2. **技术选型**:
- 使用torchvision.datasets.MNIST直接加载数据集
- 使用transforms进行数据预处理
- 使用DataLoader实现批量加载和多进程加速
- 使用random_split将训练集划分为训练集和验证集
3. **数据预处理设计**:
- ToTensor():将PIL图像转换为PyTorch张量,像素值范围从[0, 255]转换为[0, 1]
- Normalize():使用MNIST数据集的均值(0.1307)和标准差(0.3081)进行归一化
- 归一化后的数据分布更接近标准正态分布,有助于模型收敛
4. **数据集划分策略**:
- 训练集:90%(54,000张),用于模型训练
- 验证集:10%(6,000张),用于训练过程中的模型评估
- 测试集:10,000张,用于最终模型性能评估
# 开发过程
1. **环境配置**:
- 安装PyTorch和torchvision库
- 确保网络连接正常,以便下载MNIST数据集
2. **代码设计**:
- 定义get_mnist_data_loaders函数,封装数据加载逻辑
- 设计灵活的参数,支持批量大小、验证集比例和进程数的调整
- 添加测试代码,验证数据加载器功能
3. **实现步骤**:
- 导入必要的库和模块
- 定义数据预处理转换
- 加载MNIST训练集和测试集
- 划分训练集和验证集
- 创建DataLoader实例
- 返回三个数据加载器
4. **功能验证**:
- 运行测试代码,检查数据集样本数是否正确
- 验证数据批次的形状和类型是否符合预期
- 确保数据加载过程没有错误
"""
# 导入PyTorch核心库,用于张量操作
import torch
# 从torchvision导入数据集和数据转换模块
from torchvision import datasets, transforms
# 从torch.utils.data导入数据加载器和随机划分工具
from torch.utils.data import DataLoader, random_split
# 定义获取MNIST数据加载器的函数
def get_mnist_data_loaders(batch_size=64, val_split=0.1, num_workers=4):
"""
获取MNIST数据集的训练集、验证集和测试集数据加载器
参数说明:
batch_size: int, 每次加载的样本数量,默认64
val_split: float, 验证集占训练集的比例,默认0.1(10%)
num_workers: int, 数据加载使用的进程数,默认4
返回值:
tuple: 包含三个DataLoader对象
- train_loader: 训练集数据加载器
- val_loader: 验证集数据加载器
- test_loader: 测试集数据加载器
"""
# 定义数据预处理转换流水线
# transforms.Compose将多个转换操作组合成一个
transform = transforms.Compose([
# 将PIL图像转换为PyTorch张量,像素值范围[0,255]→[0,1]
transforms.ToTensor(),
# 对张量进行归一化,使用MNIST数据集的均值和标准差
# 公式:output = (input - mean) / std
transforms.Normalize((0.1307,), (0.3081,))
])
# 加载MNIST训练集
# root: 数据集保存路径
# train: True表示加载训练集
# download: True表示如果本地没有数据集则自动下载
# transform: 应用数据预处理转换
train_dataset = datasets.MNIST(
root='data',
train=True,
download=True,
transform=transform
)
# 加载MNIST测试集
# train: False表示加载测试集
test_dataset = datasets.MNIST(
root='data',
train=False,
download=True,
transform=transform
)
# 计算验证集大小
# val_split为验证集比例,乘以训练集总长度得到验证集样本数
val_size = int(len(train_dataset) * val_split)
# 计算训练集大小
# 原始训练集减去验证集大小
train_size = len(train_dataset) - val_size
# 随机划分训练集和验证集
# random_split将数据集随机划分为指定大小的子集
train_subset, val_subset = random_split(train_dataset, [train_size, val_size])
# 创建训练集数据加载器
# shuffle: True表示每个epoch打乱数据顺序,提高模型泛化能力
# num_workers: 使用4个进程加载数据,提高效率
train_loader = DataLoader(
train_subset,
batch_size=batch_size,
shuffle=True,
num_workers=num_workers
)
# 创建验证集数据加载器
# shuffle: False表示不打乱数据顺序,验证集不需要
val_loader = DataLoader(
val_subset,
batch_size=batch_size,
shuffle=False,
num_workers=num_workers
)
# 创建测试集数据加载器
# shuffle: False表示不打乱数据顺序,测试集不需要
test_loader = DataLoader(
test_dataset,
batch_size=batch_size,
shuffle=False,
num_workers=num_workers
)
# 返回三个数据加载器
return train_loader, val_loader, test_loader
# 主程序入口,用于测试数据加载器功能
if __name__ == "__main__":
# 调用函数获取数据加载器,设置批量大小为32
train_loader, val_loader, test_loader = get_mnist_data_loaders(batch_size=32)
# 打印训练集样本数
# len(train_loader.dataset)获取数据集总样本数
print(f"训练集样本数: {len(train_loader.dataset)}")
# 打印验证集样本数
print(f"验证集样本数: {len(val_loader.dataset)}")
# 打印测试集样本数
print(f"测试集样本数: {len(test_loader.dataset)}")
# 遍历训练集数据加载器,获取第一个批次的数据
# 每次迭代返回一个批次的图像和对应的标签
for images, labels in train_loader:
# 打印图像批次形状:[batch_size, channels, height, width]
# 对于MNIST,channels=1(灰度图像),height=28,width=28
print(f"图像批次形状: {images.shape}")
# 打印标签批次形状:[batch_size]
# 每个标签是0-9的整数
print(f"标签批次形状: {labels.shape}")
# 打印图像数据类型,应为torch.float32
print(f"图像数据类型: {images.dtype}")
# 打印标签数据类型,应为torch.int64(即long类型)
print(f"标签数据类型: {labels.dtype}")
# 只打印一个批次的数据,然后退出循环
break
5.4 工具函数(utils.py)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
模块4:工具函数集合(MLP训练和评估)
# 开发思路
1. **问题分析**:
- 需要将模型训练、评估和可视化功能模块化,提高代码复用性
- 实现通用的训练和评估函数,支持不同模型和数据集
- 提供结果可视化功能,便于分析模型性能
- 实现模型保存和加载功能,便于模型复用
2. **技术选型**:
- 使用PyTorch框架实现模型训练和评估
- 使用matplotlib和seaborn进行结果可视化
- 使用scikit-learn计算混淆矩阵
- 采用模块化设计,每个函数负责单一功能
3. **功能设计**:
- 准确率计算:实现分类准确率的计算
- 训练函数:实现一个epoch的训练逻辑
- 评估函数:实现模型评估逻辑,返回损失和准确率
- 可视化功能:
- 绘制训练曲线,显示损失和准确率变化
- 绘制混淆矩阵,显示各类别预测情况
- 绘制错误分类样本,分析模型错误
- 模型管理:实现模型保存和加载功能
4. **设计原则**:
- 高内聚低耦合:每个函数负责单一功能,函数之间依赖关系清晰
- 通用性:函数设计支持不同模型和数据集
- 可扩展性:便于添加新的功能和修改现有功能
- 可读性:代码结构清晰,注释详细
# 开发过程
1. **环境配置**:
- 确保PyTorch、matplotlib、seaborn和scikit-learn已正确安装
- 确保已创建results目录,用于保存可视化结果
2. **代码设计**:
- 导入必要的库和模块
- 实现准确率计算函数
- 实现训练一个epoch的函数
- 实现模型评估函数
- 实现训练曲线绘制函数
- 实现混淆矩阵绘制函数
- 实现错误分类样本绘制函数
- 实现模型保存和加载函数
3. **实现步骤**:
- 导入依赖库
- 实现calculate_accuracy函数
- 实现train_epoch函数
- 实现evaluate_model函数
- 实现plot_training_curve函数
- 实现plot_confusion_matrix函数
- 实现plot_misclassified_samples函数
- 实现save_model和load_model函数
4. **功能验证**:
- 与train.py和test.py集成,测试各函数功能
- 验证训练过程中各函数是否正常工作
- 检查生成的可视化结果是否正确
- 验证模型保存和加载功能是否正常
"""
# 导入PyTorch核心库
import torch
# 导入matplotlib,用于结果可视化
import matplotlib.pyplot as plt
# 导入numpy,用于数值计算
import numpy as np
# 从sklearn.metrics导入混淆矩阵计算函数
from sklearn.metrics import confusion_matrix
# 导入seaborn,用于绘制热力图形式的混淆矩阵
import seaborn as sns
# 定义计算准确率的函数
def calculate_accuracy(outputs, labels):
"""
计算分类准确率
参数说明:
outputs: torch.Tensor, 模型输出,形状为[batch_size, num_classes]
labels: torch.Tensor, 真实标签,形状为[batch_size]
返回值:
accuracy: float, 准确率,范围为[0, 1]
"""
# 使用torch.max获取预测标签,返回最大值和索引,索引即为预测类别
_, predicted = torch.max(outputs.data, 1)
# 获取总样本数
total = labels.size(0)
# 计算正确预测的样本数
# (predicted == labels)返回布尔张量,sum()计算True的数量,item()转换为Python数值
correct = (predicted == labels).sum().item()
# 计算准确率:正确样本数 / 总样本数
accuracy = correct / total
return accuracy
# 定义训练一个epoch的函数
def train_epoch(model, train_loader, criterion, optimizer, device):
"""
训练模型一个epoch
参数说明:
model: torch.nn.Module, 要训练的模型
train_loader: torch.utils.data.DataLoader, 训练集数据加载器
criterion: torch.nn.Module, 损失函数
optimizer: torch.optim.Optimizer, 优化器
device: torch.device, 计算设备(CPU或GPU)
返回值:
avg_loss: float, 平均训练损失
avg_accuracy: float, 平均训练准确率
"""
# 设置模型为训练模式,启用dropout和batch normalization
model.train()
# 初始化累计损失和准确率
running_loss = 0.0
running_accuracy = 0.0
total_samples = 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()
# 计算当前批次的准确率
accuracy = calculate_accuracy(outputs, labels)
# 获取当前批次的样本数
batch_size = images.size(0)
# 累计损失,乘以批次大小以保持总损失的正确性
running_loss += loss.item() * batch_size
# 累计准确率,乘以批次大小以保持总准确率的正确性
running_accuracy += accuracy * batch_size
# 累计总样本数
total_samples += batch_size
# 计算平均损失
avg_loss = running_loss / total_samples
# 计算平均准确率
avg_accuracy = running_accuracy / total_samples
return avg_loss, avg_accuracy
# 定义评估模型的函数
def evaluate_model(model, val_loader, criterion, device):
"""
评估模型在验证集或测试集上的性能
参数说明:
model: torch.nn.Module, 要评估的模型
val_loader: torch.utils.data.DataLoader, 验证集或测试集数据加载器
criterion: torch.nn.Module, 损失函数
device: torch.device, 计算设备(CPU或GPU)
返回值:
avg_loss: float, 平均损失
avg_accuracy: float, 平均准确率
all_preds: numpy.ndarray, 所有样本的预测标签,形状为[num_samples]
all_labels: numpy.ndarray, 所有样本的真实标签,形状为[num_samples]
"""
# 设置模型为评估模式,禁用dropout和batch normalization
model.eval()
# 初始化累计损失和准确率
running_loss = 0.0
running_accuracy = 0.0
total_samples = 0
# 初始化存储所有预测结果和真实标签的列表
all_preds = []
all_labels = []
# 使用torch.no_grad()上下文管理器,禁用梯度计算,节省内存和计算资源
with torch.no_grad():
# 遍历验证集或测试集数据加载器
for images, labels in val_loader:
# 将图像和标签移到指定设备
images, labels = images.to(device), labels.to(device)
# 前向传播,获取模型输出
outputs = model(images)
# 计算损失
loss = criterion(outputs, labels)
# 计算当前批次的准确率
accuracy = calculate_accuracy(outputs, labels)
# 获取当前批次的预测标签
_, preds = torch.max(outputs.data, 1)
# 将预测结果和真实标签添加到列表中
# 注意:需要将张量转换为numpy数组并移到CPU
all_preds.extend(preds.cpu().numpy())
all_labels.extend(labels.cpu().numpy())
# 获取当前批次的样本数
batch_size = images.size(0)
# 累计损失
running_loss += loss.item() * batch_size
# 累计准确率
running_accuracy += accuracy * batch_size
# 累计总样本数
total_samples += batch_size
# 计算平均损失
avg_loss = running_loss / total_samples
# 计算平均准确率
avg_accuracy = running_accuracy / total_samples
# 将预测结果和真实标签转换为numpy数组
all_preds = np.array(all_preds)
all_labels = np.array(all_labels)
return avg_loss, avg_accuracy, all_preds, all_labels
# 定义绘制训练曲线的函数
def plot_training_curve(train_losses, val_losses, train_accuracies, val_accuracies):
"""
绘制训练曲线,包括损失曲线和准确率曲线
参数说明:
train_losses: list, 训练损失列表,长度为训练轮数
val_losses: list, 验证损失列表,长度为训练轮数
train_accuracies: list, 训练准确率列表,长度为训练轮数
val_accuracies: list, 验证准确率列表,长度为训练轮数
"""
# 生成轮数列表,从1开始
epochs = range(1, len(train_losses) + 1)
# 创建画布,包含2个子图(损失曲线和准确率曲线)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5))
# 绘制损失曲线
# 训练损失用蓝色线,验证损失用红色线
ax1.plot(epochs, train_losses, 'b', label='Training Loss')
ax1.plot(epochs, val_losses, 'r', label='Validation Loss')
# 设置子图标题
ax1.set_title('Training and Validation Loss')
# 设置x轴标签
ax1.set_xlabel('Epochs')
# 设置y轴标签
ax1.set_ylabel('Loss')
# 显示图例
ax1.legend()
# 绘制准确率曲线
# 训练准确率用蓝色线,验证准确率用红色线
ax2.plot(epochs, train_accuracies, 'b', label='Training Accuracy')
ax2.plot(epochs, val_accuracies, 'r', label='Validation Accuracy')
# 设置子图标题
ax2.set_title('Training and Validation Accuracy')
# 设置x轴标签
ax2.set_xlabel('Epochs')
# 设置y轴标签
ax2.set_ylabel('Accuracy')
# 显示图例
ax2.legend()
# 调整子图间距
plt.tight_layout()
# 保存图像到results目录
plt.savefig('results/training_curves.png')
# 关闭图像,释放内存
plt.close()
# 定义绘制混淆矩阵的函数
def plot_confusion_matrix(all_labels, all_preds, class_names):
"""
绘制混淆矩阵
参数说明:
all_labels: numpy.ndarray, 所有样本的真实标签,形状为[num_samples]
all_preds: numpy.ndarray, 所有样本的预测标签,形状为[num_samples]
class_names: list, 类别名称列表,长度为类别数
"""
# 使用scikit-learn计算混淆矩阵
cm = confusion_matrix(all_labels, all_preds)
# 创建画布
plt.figure(figsize=(10, 8))
# 使用seaborn绘制热力图形式的混淆矩阵
# annot=True:显示数值
# fmt='d':使用整数格式
# cmap='Blues':使用蓝色配色方案
# xticklabels和yticklabels:设置坐标轴标签为类别名称
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=class_names, yticklabels=class_names)
# 设置图像标题
plt.title('Confusion Matrix')
# 设置x轴标签
plt.xlabel('Predicted Label')
# 设置y轴标签
plt.ylabel('True Label')
# 调整布局
plt.tight_layout()
# 保存图像到results目录
plt.savefig('results/confusion_matrix.png')
# 关闭图像,释放内存
plt.close()
# 定义绘制错误分类样本的函数
def plot_misclassified_samples(model, test_loader, device, num_samples=10):
"""
绘制模型错误分类的样本
参数说明:
model: torch.nn.Module, 已训练好的模型
test_loader: torch.utils.data.DataLoader, 测试集数据加载器
device: torch.device, 计算设备(CPU或GPU)
num_samples: int, 要显示的错误分类样本数量,默认10
"""
# 设置模型为评估模式
model.eval()
# 初始化存储错误分类样本的列表
misclassified = []
# 使用torch.no_grad()上下文管理器,禁用梯度计算
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)
# 找出错误分类的样本
for i in range(len(preds)):
if preds[i] != labels[i]:
# 将错误分类的样本添加到列表中
misclassified.append({
'image': images[i].cpu().numpy(), # 图像转换为numpy数组并移到CPU
'true_label': labels[i].item(), # 真实标签转换为Python整数
'predicted_label': preds[i].item() # 预测标签转换为Python整数
})
# 如果已收集到足够的错误分类样本,退出循环
if len(misclassified) >= num_samples:
break
# 如果已收集到足够的错误分类样本,退出外层循环
if len(misclassified) >= num_samples:
break
# 创建画布,包含2行5列共10个子图
fig, axes = plt.subplots(2, 5, figsize=(15, 6))
# 将axes转换为一维数组,方便遍历
axes = axes.ravel()
# 遍历错误分类样本并绘制
for i, sample in enumerate(misclassified):
# 绘制图像,使用灰度色彩映射
# squeeze()去除通道维度,从[1,28,28]变为[28,28]
axes[i].imshow(sample['image'].squeeze(), cmap='gray')
# 设置子图标题,显示真实标签和预测标签
axes[i].set_title(f"True: {sample['true_label']}\nPred: {sample['predicted_label']}")
# 隐藏坐标轴
axes[i].axis('off')
# 调整子图间距
plt.tight_layout()
# 保存图像到results目录
plt.savefig('results/misclassified_samples.png')
# 关闭图像,释放内存
plt.close()
# 定义保存模型的函数
def save_model(model, path):
"""
保存模型的状态字典
参数说明:
model: torch.nn.Module, 要保存的模型
path: str, 模型保存路径
"""
# 保存模型的状态字典
torch.save(model.state_dict(), path)
# 打印保存成功的信息
print(f"模型已保存到 {path}")
# 定义加载模型的函数
def load_model(model, path):
"""
加载模型的状态字典
参数说明:
model: torch.nn.Module, 模型实例
path: str, 模型文件路径
返回值:
model: torch.nn.Module, 加载了权重的模型实例
"""
# 加载模型的状态字典
model.load_state_dict(torch.load(path))
# 打印加载成功的信息
print(f"模型已从 {path} 加载")
return model
5.5 训练脚本(train.py)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
模块4:模型训练脚本(MLP训练)
# 开发思路
1. **问题分析**:
- 需要训练一个多层感知器(MLP)模型,用于MNIST手写数字识别
- 训练过程包括数据加载、模型创建、损失计算、梯度更新和模型评估
- 需要保存最佳模型,并生成训练曲线和评估结果
2. **技术选型**:
- 使用PyTorch框架进行模型训练
- 采用交叉熵损失函数,适合多分类问题
- 使用Adam优化器,具有自适应学习率特性
- 采用早停策略,保存验证集上表现最好的模型
3. **训练流程设计**:
- 环境准备:创建结果和模型保存目录
- 设备选择:自动检测GPU或使用CPU
- 数据加载:调用data_loader模块加载数据集
- 模型创建:实例化MLP模型并移至指定设备
- 训练循环:
- 训练一个epoch,计算训练损失和准确率
- 在验证集上评估模型
- 记录训练历史
- 保存最佳模型
- 结果可视化:生成训练曲线、混淆矩阵和错误分类样本图
4. **超参数设计**:
- 批量大小:64,平衡内存占用和训练效率
- 学习率:0.001,适合Adam优化器的默认学习率
- 训练轮数:15,足够模型收敛,避免过拟合
- 验证集比例:10%,用于训练过程中的模型评估
# 开发过程
1. **环境配置**:
- 确保PyTorch和相关库已正确安装
- 创建results和models目录,用于保存结果和模型
2. **代码设计**:
- 导入必要的库和模块
- 实现目录创建和设备检测
- 设计超参数配置
- 实现模型创建和训练循环
- 添加结果可视化和模型保存功能
3. **实现步骤**:
- 导入依赖库
- 创建目录结构
- 检测计算设备
- 设置超参数
- 加载数据
- 创建模型
- 定义损失函数和优化器
- 训练模型
- 可视化结果
- 评估模型
4. **功能验证**:
- 运行训练脚本,检查是否能正常执行
- 验证模型是否能保存到指定目录
- 检查是否能生成预期的可视化结果
- 确认模型在测试集上的准确率是否符合预期
"""
# 导入PyTorch核心库,用于张量操作和自动微分
import torch
# 导入PyTorch神经网络模块,包含各种层和激活函数
import torch.nn as nn
# 导入PyTorch优化器模块,包含各种优化算法
import torch.optim as optim
# 导入os模块,用于文件和目录操作
import os
# 从model模块导入MLP模型类
from model import MLP
# 从data_loader模块导入获取MNIST数据加载器的函数
from data_loader import get_mnist_data_loaders
# 从utils模块导入工具函数
from utils import (
train_epoch, # 训练一个epoch的函数
evaluate_model, # 模型评估函数
plot_training_curve, # 绘制训练曲线的函数
plot_confusion_matrix, # 绘制混淆矩阵的函数
plot_misclassified_samples, # 绘制错误分类样本的函数
save_model # 保存模型的函数
)
# 创建结果保存目录,如果不存在则创建
if not os.path.exists('results'):
os.makedirs('results')
# 创建模型保存目录,如果不存在则创建
if not os.path.exists('models'):
os.makedirs('models')
# 检测是否有GPU可用,优先使用GPU,否则使用CPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 打印使用的设备
print(f"使用设备: {device}")
# 设置超参数
batch_size = 64 # 批量大小,每次训练的样本数
val_split = 0.1 # 验证集比例,10%
num_workers = 4 # 数据加载的进程数
learning_rate = 0.001 # 学习率,控制模型参数更新的步长
epochs = 15 # 训练轮数,模型将在训练集上迭代15次
# 获取数据加载器
train_loader, val_loader, test_loader = get_mnist_data_loaders(
batch_size=batch_size, # 设置批量大小
val_split=val_split, # 设置验证集比例
num_workers=num_workers # 设置数据加载进程数
)
# 创建MLP模型实例,并将模型移至指定设备
model = MLP().to(device)
# 打印模型结构,查看网络架构
print(model)
# 定义损失函数,使用交叉熵损失函数,适合多分类问题
criterion = nn.CrossEntropyLoss()
# 定义优化器,使用Adam优化器,学习率为0.001
optimizer = optim.Adam(model.parameters(), lr=learning_rate)
# 初始化训练历史记录列表
train_losses = [] # 存储每轮训练的损失值
train_accuracies = [] # 存储每轮训练的准确率
val_losses = [] # 存储每轮验证的损失值
val_accuracies = [] # 存储每轮验证的准确率
# 初始化最佳验证准确率
best_val_accuracy = 0.0
# 打印开始训练的提示信息
print("开始训练...")
# 训练循环,共训练epochs轮
for epoch in range(epochs):
# 打印当前训练轮次信息
print(f"\n第 {epoch+1}/{epochs} 轮训练:")
# 训练一个epoch,返回训练损失和准确率
train_loss, train_accuracy = train_epoch(
model, train_loader, criterion, optimizer, device
)
# 在验证集上评估模型,返回验证损失和准确率
val_loss, val_accuracy, _, _ = evaluate_model(
model, val_loader, criterion, device
)
# 将当前轮次的训练损失和准确率添加到历史记录
train_losses.append(train_loss)
train_accuracies.append(train_accuracy)
# 将当前轮次的验证损失和准确率添加到历史记录
val_losses.append(val_loss)
val_accuracies.append(val_accuracy)
# 打印当前轮次的训练和验证结果
print(f"训练损失: {train_loss:.4f}, 训练准确率: {train_accuracy:.4f}")
print(f"验证损失: {val_loss:.4f}, 验证准确率: {val_accuracy:.4f}")
# 如果当前验证准确率高于最佳验证准确率,则保存模型
if val_accuracy > best_val_accuracy:
# 更新最佳验证准确率
best_val_accuracy = val_accuracy
# 保存模型到指定路径
save_model(model, './models/mlp_model.pth')
# 打印保存模型的信息
print(f"保存最佳模型,验证准确率: {best_val_accuracy:.4f}")
# 打印训练完成的提示信息
print("\n训练完成!")
# 绘制训练曲线,包括损失曲线和准确率曲线
plot_training_curve(train_losses, val_losses, train_accuracies, val_accuracies)
# 打印训练曲线生成完成的信息
print("已生成训练曲线")
# 打印在测试集上评估模型的提示信息
print("\n在测试集上评估模型:")
# 在测试集上评估模型,返回测试损失、准确率和预测结果
test_loss, test_accuracy, all_preds, all_labels = evaluate_model(
model, test_loader, criterion, device
)
# 打印测试结果
print(f"测试损失: {test_loss:.4f}, 测试准确率: {test_accuracy:.4f}")
# 生成类别名称列表,0-9的数字
class_names = [str(i) for i in range(10)]
# 绘制混淆矩阵
plot_confusion_matrix(all_labels, all_preds, class_names)
# 打印混淆矩阵生成完成的信息
print("已生成混淆矩阵")
# 绘制错误分类的样本,显示10个错误分类的样本
plot_misclassified_samples(model, test_loader, device, num_samples=10)
# 打印错误分类样本图生成完成的信息
print("已生成错误分类样本图")
# 打印所有评估完成的提示信息
print("\n所有评估完成!")
5.6 测试脚本(test.py)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
模块4:模型测试脚本(MLP测试)
# 开发思路
1. **问题分析**:
- 需要测试已训练好的MLP模型在MNIST测试集上的性能
- 测试过程包括数据加载、模型加载、模型评估和结果可视化
- 需要支持单张图像预测和随机样本测试功能
2. **技术选型**:
- 使用PyTorch框架进行模型测试
- 采用交叉熵损失函数评估模型性能
- 使用matplotlib进行结果可视化
- 使用PIL处理单张图像输入
3. **测试流程设计**:
- 环境准备:检测GPU或使用CPU
- 数据加载:加载MNIST测试集
- 模型加载:加载训练好的模型权重
- 模型评估:在测试集上评估模型,计算损失和准确率
- 结果可视化:
- 生成混淆矩阵,显示各类别预测情况
- 生成错误分类样本图,展示模型预测错误的样本
- 功能扩展:
- 实现单张图像预测功能
- 实现随机样本测试功能
4. **功能设计**:
- 批量测试:在整个测试集上评估模型性能
- 单张图像预测:支持预测指定路径的图像
- 随机样本测试:从测试集中随机抽取样本进行测试
- 结果可视化:生成混淆矩阵和错误分类样本图
# 开发过程
1. **环境配置**:
- 确保PyTorch和相关库已正确安装
- 确保已训练好的模型文件存在于指定路径
2. **代码设计**:
- 导入必要的库和模块
- 实现设备检测和数据加载
- 实现模型加载和评估
- 实现结果可视化功能
- 实现单张图像预测和随机样本测试功能
3. **实现步骤**:
- 导入依赖库
- 检测计算设备
- 设置超参数
- 加载测试数据
- 创建模型并加载权重
- 评估模型
- 可视化结果
- 实现单张图像预测函数
- 实现随机样本测试函数
- 调用测试函数
4. **功能验证**:
- 运行测试脚本,检查是否能正常加载模型
- 验证模型评估结果是否合理
- 检查生成的可视化结果是否正确
- 测试单张图像预测功能是否正常工作
"""
# 导入PyTorch核心库,用于张量操作
import torch
# 导入PyTorch神经网络模块,包含损失函数
import torch.nn as nn
# 导入PIL库,用于图像加载和处理
from PIL import Image
# 导入numpy,用于数值计算
import numpy as np
# 导入matplotlib,用于结果可视化
import matplotlib.pyplot as plt
# 从model模块导入MLP模型类
from model import MLP
# 从data_loader模块导入获取MNIST数据加载器的函数
from data_loader import get_mnist_data_loaders
# 从utils模块导入工具函数
from utils import (
evaluate_model, # 模型评估函数
load_model, # 加载模型的函数
plot_confusion_matrix, # 绘制混淆矩阵的函数
plot_misclassified_samples # 绘制错误分类样本的函数
)
# 检测是否有GPU可用,优先使用GPU,否则使用CPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 打印使用的设备
print(f"使用设备: {device}")
# 设置超参数
batch_size = 64 # 批量大小,每次测试的样本数
val_split = 0.1 # 验证集比例,10%
num_workers = 4 # 数据加载的进程数
# 获取数据加载器,只使用测试集
# 前两个返回值为训练集和验证集数据加载器,这里用下划线占位
_, _, test_loader = get_mnist_data_loaders(
batch_size=batch_size, # 设置批量大小
val_split=val_split, # 设置验证集比例
num_workers=num_workers # 设置数据加载进程数
)
# 创建MLP模型实例,并将模型移至指定设备
model = MLP().to(device)
# 训练好的模型文件路径
model_path = './models/mlp_model.pth'
# 加载训练好的模型权重
model = load_model(model, model_path)
# 定义损失函数,使用交叉熵损失函数
criterion = nn.CrossEntropyLoss()
# 打印开始测试模型的提示信息
print("\n开始测试模型...")
# 在测试集上评估模型,返回测试损失、测试准确率、所有预测结果和真实标签
test_loss, test_accuracy, all_preds, all_labels = evaluate_model(
model, test_loader, criterion, device
)
# 打印测试结果
print(f"测试损失: {test_loss:.4f}")
print(f"测试准确率: {test_accuracy:.4f}")
# 生成类别名称列表,0-9的数字
class_names = [str(i) for i in range(10)]
# 绘制混淆矩阵
plot_confusion_matrix(all_labels, all_preds, class_names)
# 打印混淆矩阵生成完成的信息
print("已生成混淆矩阵")
# 绘制错误分类的样本,显示10个错误分类的样本
plot_misclassified_samples(model, test_loader, device, num_samples=10)
# 打印错误分类样本图生成完成的信息
print("已生成错误分类样本图")
# 定义预测单张图像的函数
def predict_single_image(image_path):
"""
预测单张图像的数字类别
参数说明:
image_path: str, 图像文件路径
返回值:
predicted_label: int, 预测的数字类别(0-9)
probabilities: numpy.ndarray, 各类别的概率分布,形状为[10]
"""
# 导入torchvision.transforms,用于图像预处理
from torchvision import transforms
# 定义图像预处理转换流水线
# 与训练时的预处理保持一致
transform = transforms.Compose([
transforms.Grayscale(), # 将图像转换为灰度图像
transforms.Resize((28, 28)), # 将图像调整为28×28像素
transforms.ToTensor(), # 转换为PyTorch张量
transforms.Normalize((0.1307,), (0.3081,)) # 归一化处理
])
# 使用PIL加载图像
image = Image.open(image_path)
# 应用预处理转换,并添加批次维度(从[1,28,28]变为[1,1,28,28])
image_tensor = transform(image).unsqueeze(0).to(device)
# 设置模型为评估模式
model.eval()
# 使用torch.no_grad()上下文管理器,禁用梯度计算
with torch.no_grad():
# 前向传播,获取模型输出
output = model(image_tensor)
# 计算各类别的概率,使用softmax函数
probabilities = torch.softmax(output, dim=1)
# 获取预测标签,即概率最大的类别
_, predicted_label = torch.max(output, 1)
# 返回预测标签(转换为Python原生整数)和概率分布(转换为numpy数组)
return predicted_label.item(), probabilities.squeeze().cpu().numpy()
# 定义使用随机样本测试模型的函数
def test_with_random_samples(num_samples=5):
"""
使用测试集中的随机样本测试模型
参数说明:
num_samples: int, 要测试的样本数量,默认为5
"""
# 打印测试信息
print(f"\n使用测试集中的 {num_samples} 个随机样本进行测试:")
# 导入random模块,用于随机抽样
import random
# 将测试集转换为列表,方便随机抽样
test_data = list(test_loader.dataset)
# 从测试集中随机抽取num_samples个样本
random_samples = random.sample(test_data, num_samples)
# 创建画布,包含num_samples个子图
fig, axes = plt.subplots(1, num_samples, figsize=(15, 3))
# 遍历随机抽取的样本
for i, sample in enumerate(random_samples):
# 获取图像和真实标签
image, true_label = sample
# 设置模型为评估模式
model.eval()
# 禁用梯度计算
with torch.no_grad():
# 添加批次维度,并将图像移到指定设备
image_tensor = image.unsqueeze(0).to(device)
# 前向传播,获取模型输出
output = model(image_tensor)
# 计算各类别的概率
probabilities = torch.softmax(output, dim=1)
# 获取预测标签
_, predicted_label = torch.max(output, 1)
# 绘制图像,使用灰度色彩映射
axes[i].imshow(image.squeeze(), cmap='gray')
# 设置子图标题,显示真实标签和预测标签
axes[i].set_title(f"True: {true_label}\nPred: {predicted_label.item()}")
# 隐藏坐标轴
axes[i].axis('off')
# 打印样本测试结果
print(f"样本 {i+1}: 真实标签={true_label}, 预测标签={predicted_label.item()}, "
f"置信度={probabilities[0][predicted_label.item()]:.4f}")
# 调整子图间距
plt.tight_layout()
# 保存图像到results目录
plt.savefig('results/random_test_samples.png')
# 关闭图像,释放内存
plt.close()
# 打印图像生成完成的信息
print("已生成随机测试样本结果图")
# 调用随机样本测试函数,测试5个样本
test_with_random_samples(num_samples=5)
# 打印模型测试完成的提示信息
print("\n模型测试完成!")
# 打印最终测试准确率
print(f"最终测试准确率: {test_accuracy:.4f}")
# 提供预测单张图像的功能说明
print("\n如果需要预测单张图像,可以使用以下代码:")
print("from test import predict_single_image")
print("predicted_label, probabilities = predict_single_image('path/to/image.png')")
print("print(f'预测结果: {predicted_label}, 概率分布: {probabilities}')")
7. 脚本执行顺序与作用
7.1 脚本执行顺序
- 数据准备:运行
data_loader.py获取数据集(自动下载并预处理MNIST数据) - 模型定义:
model.py中定义了MLP模型结构 - 模型训练:运行
train.py训练模型,生成训练曲线和保存最佳模型 - 模型测试:运行
test.py评估模型性能,生成混淆矩阵和错误分类样本图
7.2 各脚本作用
| 脚本文件 | 主要作用 | 执行命令 |
|---|---|---|
| model.py | 定义MLP模型结构 | python model.py |
| data_loader.py | 加载和预处理MNIST数据 | python data_loader.py |
| utils.py | 提供训练、评估和可视化工具函数 | 被train.py和test.py调用 |
| train.py | 训练模型并保存最佳模型 | python train.py |
| test.py | 评估模型性能并生成可视化结果 | python test.py |
7.3 执行流程图
8. 运行示例
8.1 训练模型
python train.py
8.2 测试模型
python test.py
8.3 单张图像预测
from test import predict_single_image
predicted_label, probabilities = predict_single_image('path/to/image.png')
print(f'预测结果: {predicted_label}')
print(f'概率分布: {probabilities}')
更多推荐
所有评论(0)