当前位置: 首页 > news >正文

pytorch | minist手写数据集

一、神经网络

神经网络(Neural Network)是一种受生物神经系统(尤其是大脑神经元连接方式)启发的机器学习模型,是深度学习的核心基础。它通过模拟大量 “人工神经元” 的互联结构,学习数据中的复杂模式和规律,从而实现分类、预测、生成等任务。

本项目采用的是全连接神经网络(Fully Connected Network)

每一层的神经元与下一层所有神经元连接。

应用:简单分类 / 回归任务(如房价预测、鸢尾花分类)。

大概模型如下图所示:

1.输入层(Input Layer): 

  1. 接收原始数据(如图像的像素值、文本的词向量),不进行计算,仅传递数据。

  2. 神经元数量 = 输入数据的维度(例如:28*28 的彩色图像输入层有 28*28=784个神经元)。

2.隐藏层(Hidden Layer)

  1. 位于输入层和输出层之间,负责提取数据的特征(如边缘、纹理、语义等)。
  2. 共有2层,其中第一层设置了250个节点,第二层设置了200层。

3.输出层(Output Layer)

  1. 输出模型的最终结果(如分类任务的类别概率、回归任务的预测值)。
  2. 神经元数量 = 任务目标的维度(10 类分类任务输出层有 10 个神经元)。

4.激活函数

激活函数是神经网络能拟合复杂模式的关键,其核心作用是引入非线性变换(否则多层网络等价于单层线性模型)。本项目所使用的激活函数是relu函数:

\text{ReLU}(z) = \max(0, z)

5.计算损失(Loss Calculation)

  1. 损失函数(Loss Function)衡量预测结果与真实标签的差距(例如:分类任务用交叉熵损失,回归任务用均方误差)。
  2. 损失越小,模型预测越准。

在 PyTorch 中,CrossEntropyLoss是用于分类任务的常用损失函数,尤其适用于多类别分类(也可用于二分类)。它的设计非常灵活,内部集成了log_softmaxNLLLoss的功能,简化了模型输出与损失计算的流程。

CrossEntropyLoss = NLLLoss(log_softmax(logits), targets)

NLLLoss(y, \hat{y})=-\frac{1}{N}ylog \hat{y}

log\, softmax=log\frac{e^{y_{i}}}{\sum {j} e^{y_{j}}}

6.正则化

用于防止模型过拟合,提高泛化能力。

L2 正则化(Ridge Regression):倾向于减小参数值

  • 参数平滑性:L2 正则化会使参数值变小,但不会完全为 0,从而使模型更加平滑。
  • 几何解释:L2 的约束区域是一个圆形,与损失函数的等高线相交时,参数更可能落在非零的位置。

在损失函数中添加参数的平方和作为惩罚项:损失函数= 原始损失 +\lambda \sum_{i} w_i^2

7.优化器

Adam(Adaptive Moment Estimation)是深度学习中最流行的优化算法之一,结合了 Adagrad 和 RMSProp 的优点,能够自适应地调整每个参数的学习率。它在实践中表现出色,广泛应用于各种神经网络训练任务。

二、代码

网络模型

单独新建一个Python文件用于存储网络模型,其中定义了两个隐藏层,都使用全连接神经网络,第一个隐藏层有250个节点,第二隐藏层有200个节点,从最后一个隐藏层到输出层同样使用全连接神经网络

self.fc1=nn.Linear(28*28,250)
self.fc2=nn.Linear(250,200)
self.fc3=nn.Linear(200,10)

 前两层(输入层->第一个隐藏层->第二个隐藏层)都使用relu激活函数,第二个隐藏层到输出层暂不使用激活函数,这样做可以减少loss的计算误差

x =F.relu(self.fc1(x))
x=F.relu(self.fc2(x))
x=self.fc3(x)

 完整代码如下:

class network1(nn.Module):def __init__(self):super(network1, self).__init__()self.fc1=nn.Linear(28*28,250)self.fc2=nn.Linear(250,200)self.fc3=nn.Linear(200,10)def forward(self, x):x =F.relu(self.fc1(x))x=F.relu(self.fc2(x))x=self.fc3(x)return x

训练模型

工具模块

import torchvisionfrom model import *
from torch import nn
from torch.utils.tensorboard import SummaryWriter
from torch.utils.data import DataLoader

数据处理,将图片数据转换成tensor数据类型

trans=torchvision.transforms.Compose([torchvision.transforms.ToTensor()
])

 导入数据,并获取数据长度

train_dataset=torchvision.datasets.MNIST("./data",train=True,transform=trans,download=True)
test_dataset=torchvision.datasets.MNIST("./data",train=False,transform=trans,download=True)train_data_size=len(train_dataset)
test_data_size=len(test_dataset)

加载数据,并设置批量大小为64,设置 打乱数据顺序,因为数据集大小不能被64整除,设置丢弃多余数据

train_dataloader=DataLoader(train_dataset,batch_size=64,shuffle=True,drop_last=True)
test_dataloader=DataLoader(test_dataset,batch_size=64,shuffle=True,drop_last=True)

声明网络模型变量,设置损失函数,使用adam优化,设置l2正则

model=network1()loss_fn=nn.CrossEntropyLoss()learning_rate=1e-2
l2_lambda=1e-5
optimizer=torch.optim.Adam(model.parameters(),lr=learning_rate,weight_decay=l2_lambda)

 设置训练过程中可能用到的变量

total_train_step=0
total_test_step=0
epoch=50

  创建SummaryWriter,指定日志保存目录

writer=SummaryWriter("./mini_logs")

 在迭代器中取出数据和标签,将数据展成一维的,使其符合网络模型的输入,将其放入模型中

    for data in train_dataloader:imgs,targets=dataimgs=torch.reshape(imgs,(64,-1))outputs=model(imgs)

计算损失值

loss = loss_fn(outputs, targets)
total_train_loss+=loss

 计算准确率

accuracy = ((outputs.argmax(1) == targets).sum())
total_train_accuracy += accuracy
total_train_step+=1

更新梯度,进行参数优化

optimizer.zero_grad()
loss.backward()
optimizer.step()

 输出训练数据,并将训练误差和准确率添加到tensorboard上

# 100轮输出一次,防止数据太多        if total_train_step % 100 == 0:print('训练次数:{},Loss:{}'.format(total_train_step, loss.item()))  print("整体训练集上的Loss为:{}".format(total_train_loss))print("整体训练集上的正确率为:{}".format(total_train_accuracy / train_data_size))writer.add_scalar("Loss/train_loss", total_train_loss, total_test_step)#使用test_step是为了对齐测试误差,下同writer.add_scalar("Ac/train_accuracy", total_train_accuracy / train_data_size, total_test_step)

 在test数据集上测试参数效果,过程与训练过程相似,需要注意的是,在测试过程中可以不计算梯度,加快计算效率

total_test_loss=0total_test_accuracy=0with torch.no_grad():for data in test_dataloader:imgs,targets=dataimgs = torch.reshape(imgs, (64, -1))outputs=model(imgs)loss=loss_fn(outputs,targets)total_test_loss+=lossaccuracy = ((outputs.argmax(1) == targets).sum())total_test_accuracy += accuracyprint("整体测试集上的Loss为:{}".format(total_test_loss))print("整体测试集上的正确率为:{}".format(total_test_accuracy / test_data_size))writer.add_scalar("Loss/test_loss", total_test_loss, total_test_step)writer.add_scalar("Ac/test_accuracy", total_test_accuracy / test_data_size, total_test_step)

最后保存模型并关闭SummaryWriter

torch.save(model,"minst_weight/net_{}.pth".format(i))print("模型已保存")writer.close()

 完整代码如下:

import torchvisionfrom model import *
from torch import nn
from torch.utils.tensorboard import SummaryWriter
from torch.utils.data import DataLoadertrans=torchvision.transforms.Compose([torchvision.transforms.ToTensor()
])train_dataset=torchvision.datasets.MNIST("./data",train=True,transform=trans,download=True)
test_dataset=torchvision.datasets.MNIST("./data",train=False,transform=trans,download=True)train_data_size=len(train_dataset)
test_data_size=len(test_dataset)train_dataloader=DataLoader(train_dataset,batch_size=64,shuffle=True,drop_last=True)
test_dataloader=DataLoader(test_dataset,batch_size=64,shuffle=True,drop_last=True)model=network1()loss_fn=nn.CrossEntropyLoss()learning_rate=1e-2
l2_lambda=1e-5
optimizer=torch.optim.Adam(model.parameters(),lr=learning_rate,weight_decay=l2_lambda)total_train_step=0
total_test_step=0
epoch=50writer=SummaryWriter("./mini_logs")for i in range(epoch):print('--------第{}轮训练开始--------'.format(i))total_train_loss = 0total_train_accuracy=0for data in train_dataloader:imgs,targets=dataimgs=torch.reshape(imgs,(64,-1))outputs=model(imgs)loss = loss_fn(outputs, targets)total_train_loss+=lossaccuracy = ((outputs.argmax(1) == targets).sum())total_train_accuracy += accuracytotal_train_step+=1optimizer.zero_grad()loss.backward()optimizer.step()if total_train_step % 100 == 0:print('训练次数:{},Loss:{}'.format(total_train_step, loss.item()))  # 100轮输出一次,防止数据太多print("整体训练集上的Loss为:{}".format(total_train_loss))print("整体训练集上的正确率为:{}".format(total_train_accuracy / train_data_size))writer.add_scalar("Loss/train_loss", total_train_loss, total_test_step)#使用test_step是为了对齐测试误差,下同writer.add_scalar("Ac/train_accuracy", total_train_accuracy / train_data_size, total_test_step)total_test_loss=0total_test_accuracy=0with torch.no_grad():for data in test_dataloader:imgs,targets=dataimgs = torch.reshape(imgs, (64, -1))outputs=model(imgs)loss=loss_fn(outputs,targets)total_test_loss+=lossaccuracy = ((outputs.argmax(1) == targets).sum())total_test_accuracy += accuracyprint("整体测试集上的Loss为:{}".format(total_test_loss))print("整体测试集上的正确率为:{}".format(total_test_accuracy / test_data_size))writer.add_scalar("Loss/test_loss", total_test_loss, total_test_step)writer.add_scalar("Ac/test_accuracy", total_test_accuracy / test_data_size, total_test_step)total_test_step += 1torch.save(model,"minst_weight/net_{}.pth".format(i))print("模型已保存")writer.close()

训练结果如下图所示:

可以看到在test数据集上,该模型的准确率还是非常高的

模型测试

在网页上随便截取几张手写数字,测试一下其效果,效果可能与test数据集测试的效果相差较大,是因为网上的数据与训练的数据相差太大,所以这个实验可能并没有什么参考价值,可以练练手

数据描述:在网上截取了0-9的图片,并命名为img_0这种格式

第一步:获取数据

    image_path= 'imgs/img_{}.png'.format(i)image=Image.open(image_path)

第二步:数据预处理,将彩色图转为灰度图,裁剪其尺寸为28*28,然后将其转换成tensor数据类型

image=image.convert("L")trans=torchvision.transforms.Compose([torchvision.transforms.Resize((28,28)),torchvision.transforms.ToTensor()])image=trans(image)

第三步:可以查看一下处理完的数据,由于add_image要求数据是三维的,所以需要先处理一下数据

    image=torch.reshape(image,(1,28,-1))writer=SummaryWriter("mini_show")writer.add_image("{}".format(i),image)writer.close()

第四步:加载模型,并输出训练结果

    image=torch.reshape(image,(1,-1))model=torch.load('minst_weight/net_40.pth')model.eval()with torch.no_grad():output=model(image)print('{}预测的值是:{}'.format(i,output.argmax(1).item()))

完整代码如下: 

import torch
import torchvision
from PIL import Image
from torch.utils.tensorboard import SummaryWriterfrom model import *
for i in range(10):image_path= 'imgs/img_{}.png'.format(i)image=Image.open(image_path)image=image.convert("L")trans=torchvision.transforms.Compose([torchvision.transforms.Resize((28,28)),torchvision.transforms.ToTensor()])image=trans(image)image=torch.reshape(image,(1,28,-1))writer=SummaryWriter("mini_show")writer.add_image("{}".format(i),image)writer.close()image=torch.reshape(image,(1,-1))model=torch.load('minst_weight/net_40.pth')model.eval()with torch.no_grad():output=model(image)print('{}预测的值是:{}'.format(i,output.argmax(1).item()))

截取并预处理后的图片: 

http://www.dtcms.com/a/281917.html

相关文章:

  • 防止应用调试分析IP被扫描加固实战教程
  • react19+nextjs+antd切换主题颜色
  • 【python学习】windows使用conda管理python虚拟环境
  • RNN循环神经网络
  • 面试问题:
  • STM32硬件I2C的注意事项
  • CCK-8 实验详解及 Graphpad 作图指南
  • 阿里云 RabbitMQ 可观测性最佳实践
  • 恶补DSP:1.F28335的时钟系统
  • Swarm Network 选择 Walrus 实现可验证 AI
  • 网络安全(初级)(Python实现sql自动化布尔盲注)
  • JWT基础详解
  • 【云原生网络】Istio基础篇
  • 使用 CrewAI 进行股票分析:自动化投资决策的新途径
  • Capture One24下载与保姆级安装教程!
  • 解决“Windows 无法启动服务”问题指南
  • 数据库询问RAG框架Vanna的总体架构
  • 线上崩溃复盘
  • Unity Android Logcat插件 输出日志中文乱码解决
  • FPGA基础 -- Verilog 访问寄存器数组的指定位示例
  • 第六章 OBProxy 路由与使用运维
  • [Linux入门] Linux 账号和权限管理入门:从基础到实践
  • Linux实现进程之间Socket通信详解
  • 30 天自制 C++ 服务器--Day3
  • NO.6数据结构树|二叉树|满二叉树|完全二叉树|顺序存储|链式存储|先序|中序|后序|层序遍历
  • 【SpringBoot】实战-开发接口-用户-注册
  • 参数检验?非参数检验?
  • 【openbmc3】时间相关
  • 代码随想录算法训练营第五十一天|图论part2
  • 【FreeRTOS】03任务管理