当前位置: 首页 > 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.xdnf.cn/news/1131373.html

相关文章:

  • 基于Hadoop与LightFM的美妆推荐系统设计与实现
  • 前端网络性能优化
  • STM32 GPIO的八种工作模式
  • Fluent许可问题常见解答
  • 分布式弹性故障处理框架——Polly(1)
  • JobSet:Kubernetes 分布式任务编排的统一解决方案
  • 为什么要用erc165识别erc721或erc1155
  • LIN通信协议入门
  • 面试问题:
  • AI治AI:大语言模型自检新法
  • ARCGIS PRO DSK 颜色选择控件(ColorPickerControl)的调用
  • Java设计模式之-组合模式
  • Haproxy代理服务(小白的“升级打怪”成长之路)
  • 微信小程序141~150
  • rustdesk远控电脑替代todesk,平替向日葵等软件
  • 【云原生网络】Istio基础篇
  • 实时调度类
  • 鸿蒙网络编程系列58-仓颉版TLS数字证书查看及验签示例
  • JavaScript进阶篇——第五章 对象成员管理与数组遍历优化
  • uniapp+vue3+鸿蒙系统的开发
  • 查看.bin二进制文件的方式(HxD十六进制编辑器的安装)
  • 从缓存 CAS 看Kimi K2使用的MuonClip优化器
  • Mybatis07-缓存
  • 【LLM】OpenRouter调用Anthropic Claude上下文缓存处理
  • Jenkins Pipeline 中使用 JsonSlurper 报错:cannot find current thread
  • 55. 跳跃游戏
  • 2025年中国品牌全球化发展分析:中国品牌在社交渠道、电商平台及官网流量方面显著增长
  • 语音增强论文汇总
  • IIS网站间歇性打不开暴力解决方法
  • 【数据结构】栈与链表的区别