手写数据集的深度学习

import numpy as np

import torch

import torchvision

from torchvision.datasets import mnist

import torchvision.transforms as transforms

from torch.utils.data import DataLoader

import torch.nn.functional as F

import torch.optim as optim

from torch import nn

from torch.utils.tensorboard import SummaryWriter

import matplotlib.pyplot as plt

==================== 定义超参数 ====================

train_batch_size = 64 # 训练时每个批次的样本数量

test_batch_size = 128 # 测试时每个批次的样本数量

learning_rate = 0.01 # 初始学习率

num_epoches = 20 # 训练的总轮数

momentum = 0.9 # SGD优化器的动量参数

==================== 数据准备和预处理 ====================

定义预处理函数

transform = transforms.Compose([

transforms.ToTensor(), # 将PIL图像转换为Tensor,并自动归一化到0,1范围

transforms.Normalize(0.5, 0.5) # 标准化到-1,1范围,公式:(x-0.5)/0.5

])

下载数据,并对数据进行预处理

train_dataset = mnist.MNIST('../data/', train=True, transform=transform, download=True)

训练数据集:存储在../data/目录,训练模式,应用预处理变换,如果不存在则下载

test_dataset = mnist.MNIST('../data/', train=False, transform=transform)

测试数据集:存储在../data/目录,测试模式,应用相同的预处理变换

得到数据加载器

train_loader = DataLoader(train_dataset, batch_size=train_batch_size, shuffle=True)

训练数据加载器:批次大小64,打乱数据顺序

test_loader = DataLoader(test_dataset, batch_size=test_batch_size, shuffle=False)

测试数据加载器:批次大小128,不打乱数据顺序

==================== 可视化源数据 ====================

获取一批测试数据用于可视化

examples = enumerate(test_loader) # 枚举测试数据加载器,返回索引和批次

batch_idx, (example_data, example_targets) = next(examples) # 获取第一个批次

print(f"示例数据形状: {example_data.shape}") # 打印数据形状,应该是 128, 1, 28, 28

显示前6个图像

fig = plt.figure(figsize=(10, 6)) # 创建图形,尺寸10x6英寸

for i in range(6):

plt.subplot(2, 3, i+1) # 创建2行3列的子图,当前是第i+1个

plt.tight_layout() # 自动调整子图参数,使之填充整个图像区域

plt.imshow(example_datai0, cmap='gray', interpolation='none') # 显示灰度图像

plt.title('真实标签: {}'.format(example_targetsi)) # 设置标题为真实标签

plt.xticks(\[\]) # 移除x轴刻度

plt.yticks(\[\]) # 移除y轴刻度

plt.savefig('mnist_samples.png') # 保存图像到文件

print("MNIST样本图像已保存到: mnist_samples.png")

==================== 构建模型 ====================

class Net(nn.Module): # 定义神经网络类,继承自nn.Module

def init(self, in_dim, n_hidden_1, n_hidden_2, out_dim):

super(Net, self).init() # 调用父类构造函数

self.flatten = nn.Flatten() # 展平层,将多维输入一维化

使用Sequential构建网络层

self.layer1 = nn.Sequential( # 第一个隐藏层序列

nn.Linear(in_dim, n_hidden_1), # 全连接层,输入维度in_dim,输出维度n_hidden_1

nn.BatchNorm1d(n_hidden_1) # 批归一化层,加速训练并提高稳定性

)

self.layer2 = nn.Sequential( # 第二个隐藏层序列

nn.Linear(n_hidden_1, n_hidden_2), # 全连接层

nn.BatchNorm1d(n_hidden_2) # 批归一化层

)

self.out = nn.Sequential( # 输出层序列

nn.Linear(n_hidden_2, out_dim) # 输出层,输出维度out_dim(10个类别)

)

def forward(self, x): # 定义前向传播过程

x = self.flatten(x) # 展平输入,从batch,1,28,28变为batch,784

x = F.relu(self.layer1(x)) # 第一层:线性变换+批归一化+ReLU激活

x = F.relu(self.layer2(x)) # 第二层:线性变换+批归一化+ReLU激活

x = F.softmax(self.out(x), dim=1) # 输出层:线性变换+softmax,按行计算概率分布

return x

==================== 模型实例化和配置 ====================

设置设备

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

如果有GPU则使用GPU,否则使用CPU

print(f"使用设备: {device}")

实例化模型

model = Net(28 * 28, 300, 100, 10) # 输入28x28=784,隐藏层300和100,输出10个类别

model.to(device) # 将模型移动到指定设备(GPU或CPU)

定义损失函数和优化器

criterion = nn.CrossEntropyLoss() # 交叉熵损失函数,适用于多分类问题

optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=momentum)

SGD优化器:传入模型参数、学习率、动量

打印模型结构

print("模型结构:")

print(model)

==================== 训练模型 ====================

def main(): # 定义主函数,封装训练流程

初始化记录列表

losses = \[\] # 记录每个epoch的训练损失

acces = \[\] # 记录每个epoch的训练准确率

eval_losses = \[\] # 记录每个epoch的测试损失

eval_acces = \[\] # 记录每个epoch的测试准确率

创建TensorBoard写入器

writer = SummaryWriter(log_dir='logs', comment='train-loss')

创建SummaryWriter对象,日志目录为'logs',注释为'train-loss'

print("开始训练...")

for epoch in range(num_epoches): # 遍历每个训练轮次

train_loss = 0 # 初始化当前epoch的训练损失

train_acc = 0 # 初始化当前epoch的训练准确率

设置为训练模式

model.train() # 启用dropout和batch normalization的训练模式

动态修改参数学习率

if epoch % 5 == 0: # 每5个epoch调整一次学习率

optimizer.param_groups0'lr' *= 0.9 # 学习率乘以0.9(衰减)

print("学习率: {:.6f}".format(optimizer.param_groups0'lr'))

训练阶段

for img, label in train_loader: # 遍历训练数据加载器中的每个批次

img = img.to(device) # 将图像数据移动到指定设备

label = label.to(device) # 将标签数据移动到指定设备

前向传播

out = model(img) # 模型预测输出

loss = criterion(out, label) # 计算损失

反向传播

optimizer.zero_grad() # 清空之前的梯度

loss.backward() # 反向传播计算梯度

optimizer.step() # 更新模型参数

记录误差

train_loss += loss.item() # 累加批次损失

计算分类的准确率

_, pred = out.max(1) # 获取预测类别(最大概率的索引)

num_correct = (pred == label).sum().item() # 计算正确预测的数量

acc = num_correct / img.shape0 # 计算准确率

train_acc += acc # 累加批次准确率

记录训练损失和准确率

avg_train_loss = train_loss / len(train_loader) # 计算平均训练损失

avg_train_acc = train_acc / len(train_loader) # 计算平均训练准确率

losses.append(avg_train_loss) # 添加到训练损失列表

acces.append(avg_train_acc) # 添加到训练准确率列表

保存到TensorBoard

writer.add_scalar('Train/Loss', avg_train_loss, epoch) # 记录训练损失

writer.add_scalar('Train/Accuracy', avg_train_acc, epoch) # 记录训练准确率

在测试集上检验结果

eval_loss = 0 # 初始化当前epoch的测试损失

eval_acc = 0 # 初始化当前epoch的测试准确率

将模型改为预测模式

model.eval() # 禁用dropout和使用训练阶段的batch normalization统计量

with torch.no_grad(): # 测试阶段不需要计算梯度,节省内存和计算资源

for img, label in test_loader: # 遍历测试数据加载器中的每个批次

img = img.to(device) # 将图像数据移动到指定设备

label = label.to(device) # 将标签数据移动到指定设备

前向传播

out = model(img) # 模型预测输出

loss = criterion(out, label) # 计算损失

记录误差

eval_loss += loss.item() # 累加批次损失

记录准确率

_, pred = out.max(1) # 获取预测类别

num_correct = (pred == label).sum().item() # 计算正确预测的数量

acc = num_correct / img.shape0 # 计算准确率

eval_acc += acc # 累加批次准确率

记录测试损失和准确率

avg_eval_loss = eval_loss / len(test_loader) # 计算平均测试损失

avg_eval_acc = eval_acc / len(test_loader) # 计算平均测试准确率

eval_losses.append(avg_eval_loss) # 添加到测试损失列表

eval_acces.append(avg_eval_acc) # 添加到测试准确率列表

保存到TensorBoard

writer.add_scalar('Test/Loss', avg_eval_loss, epoch) # 记录测试损失

writer.add_scalar('Test/Accuracy', avg_eval_acc, epoch) # 记录测试准确率

打印每个epoch的结果

print('epoch: {}, Train Loss: {:.4f}, Train Acc: {:.4f}, Test Loss: {:.4f}, Test Acc: {:.4f}'

.format(epoch, avg_train_loss, avg_train_acc, avg_eval_loss, avg_eval_acc))

关闭TensorBoard写入器

writer.close()

print('训练完成!')

==================== 可视化训练结果 ====================

绘制训练损失

plt.figure(figsize=(12, 4)) # 创建图形,尺寸12x4英寸

plt.subplot(1, 2, 1) # 创建1行2列的子图,当前是第1个

plt.title('训练损失') # 设置子图标题

plt.plot(np.arange(len(losses)), losses, label='Train Loss') # 绘制训练损失曲线

plt.plot(np.arange(len(eval_losses)), eval_losses, label='Test Loss') # 绘制测试损失曲线

plt.xlabel('Epoch') # 设置x轴标签

plt.ylabel('Loss') # 设置y轴标签

plt.legend() # 显示图例

plt.subplot(1, 2, 2) # 创建1行2列的子图,当前是第2个

plt.title('准确率') # 设置子图标题

plt.plot(np.arange(len(acces)), acces, label='Train Accuracy') # 绘制训练准确率曲线

plt.plot(np.arange(len(eval_acces)), eval_acces, label='Test Accuracy') # 绘制测试准确率曲线

plt.xlabel('Epoch') # 设置x轴标签

plt.ylabel('Accuracy') # 设置y轴标签

plt.legend() # 显示图例

plt.tight_layout() # 自动调整子图参数

plt.savefig('training_results.png') # 保存训练结果图

print("训练结果图已保存到: training_results.png")

==================== 最终测试 ====================

model.eval() # 设置为评估模式

final_test_acc = 0 # 初始化最终测试准确数

total_samples = 0 # 初始化总样本数

with torch.no_grad(): # 不计算梯度

for img, label in test_loader: # 遍历测试集

img = img.to(device) # 移动数据到设备

label = label.to(device) # 移动标签到设备

out = model(img) # 模型预测

_, pred = out.max(1) # 获取预测结果

final_test_acc += (pred == label).sum().item() # 累加正确预测数

total_samples += label.size(0) # 累加总样本数

final_accuracy = 100 * final_test_acc / total_samples # 计算最终准确率百分比

print(f'\n最终测试准确率: {final_accuracy:.2f}%') # 打印最终准确率

==================== 显示一些预测结果 ====================

model.eval() # 设置为评估模式

with torch.no_grad():

获取一批测试数据

dataiter = iter(test_loader) # 创建测试数据迭代器

images, labels = next(dataiter) # 获取下一个批次

images, labels = images.to(device), labels.to(device) # 移动数据到设备

进行预测

outputs = model(images) # 模型预测

_, predicted = torch.max(outputs, 1) # 获取预测类别

显示前12个预测结果

fig, axes = plt.subplots(3, 4, figsize=(12, 9)) # 创建3行4列的子图

axes = axes.ravel() # 将子图数组展平为一维

for i in range(12): # 遍历前12个样本

axesi.imshow(imagesi.cpu().numpy()0, cmap='gray') # 显示图像

axesi.set_title(f'预测: {predictedi.item()}, 真实: {labelsi.item()}') # 设置标题

axesi.axis('off') # 关闭坐标轴

如果预测错误,用红色标题突出显示

if predictedi != labelsi:

axesi.title.set_color('red') # 预测错误时标题变为红色

plt.tight_layout() # 自动调整布局

plt.savefig('prediction_results.png') # 保存预测结果图

print("预测结果图已保存到: prediction_results.png")

使用if name == 'main'保护主程序入口

if name == 'main':

设置matplotlib后端为Agg,避免显示问题(不显示图形窗口,只保存到文件)

import matplotlib

matplotlib.use('Agg')

main() # 调用主函数开始训练

相关推荐
老饼讲解-BP神经网络1 分钟前
BP神经网络用什么训练算法(traingd、traingdm、trainlm)
人工智能·神经网络·算法
xiezhr2 分钟前
Hermes官方桌面版发布了
人工智能·ai·agent·codex·hermes
Gavynlee4 分钟前
ubuntu22.04 配置cluade code & 硅基流动API
人工智能
jinxindeep7 分钟前
Bi-Adapt:基于语义对应实现跨类别双臂操作的高效泛化
人工智能·机器人
Godspeed Zhao1 小时前
Level 4自动驾驶系统设计2——功能与场景2
人工智能·机器学习·自动驾驶
Jerry.张蒙1 小时前
AI工具Opencode助力SAP提质增效实践
大数据·运维·服务器·人工智能·运维开发
老徐聊GEO1 小时前
AI搜索流量转化率实测分享:我的案例与复盘
人工智能·python
草莓熊Lotso1 小时前
【LangChain】流式传输原理与 LangSmith 应用监控全解析
人工智能·python·langchain·gpt-3
十里春风_jzh1 小时前
打造自己的 AI 知识库
人工智能
一次旅行8 小时前
HyperTool:突破传统工具调用限制,让Agent更高效执行复杂任务
人工智能