【深度学习】智能手写数字识别系统

news2024/11/20 0:40:47

文章目录

  • 一.实验课题背景说明
    • 1.1实验目的
    • 1.2实验环境
      • 1.2.1安装PyTorch
      • 1.2.2安装其他必要的库
  • 二.模型说明
    • 2.1模型概述
    • 2.2模型结构
  • 三.数据说明
    • 3.1 输入数据
        • 3.1.1输入数据特征
        • 3.1.2输入数据维度
        • 3.1.3输入数据预处理
    • 3.2 数据格式
        • 3.2.1输出数据特征
        • 3.2.2输出数据维度
        • 3.2.3输出数据的意义
        • 3.2.4输出数据的生成
    • 3.3 训练集与测试集
      • 3.3.1数据集规模和组成
      • 3.3.2图像特点
      • 3.3.3数据集的获取
  • 四.实验代码
    • 4.1数据加载
    • 4.2模型定义
    • 4.3训练过程
    • 4.4测试评估
  • 五.实验结果说明
    • 5.1实验结果概述
    • 5.2训练过程
    • 5.4性能评估
    • 5.5结果分析
    • 5.6实战测试
  • 六.实验总结
    • 6.1测试集准确率较高的原因
    • 6.2实际拍照测试准确率较低的原因
    • 6.3后面的改进方法
  • 附录
    • 附录A main.py
    • 附录B test.py
    • 附录C sampled_data.py
    • 附录D model_architecture.py

一.实验课题背景说明

1.1实验目的

在人工智能和机器学习的浪潮中,手写数字识别作为计算机视觉领域的经典问题,一直吸引着研究者和开发者的广泛关注。这项技术在实际应用中也展现出巨大的潜力,如自动化数据录入、银行支票处理、邮政编码识别等。随着深度学习技术的兴起,特别是卷积神经网络(CNN)在图像识别领域的突破性进展,手写数字识别的准确性和效率得到了显著提升。
本项目旨在构建一个基于深度学习的手写数字识别模型,将会使用Python 编程语言,结合强大的 PyTorch 库来实现。PyTorch 提供了灵活的计算图和自动微分机制等功能,使得模型的构建、训练和优化变得简单而高效。模型将从读取图像开始,通过一系列图像预处理步骤,包括灰度化、尺寸调整、归一化等,以确保输入数据的一致性和模型的泛化能力。
在模型设计上,模型采用了一个多层前馈神经网络,其中包括全连接层和ReLU 激活函数,以及用于提高模型性能的特定技术,如 Otsu 的阈值处理和形态学膨胀。这些技术的应用,旨在增强数字的可识别性,降低背景噪声的影响。通过精心设计的网络结构和训练策略,本文的模型能够在MNIST 等标准数据集上实现高准确率的手写数字识别。
在实验部分,本文将详细介绍数据的加载和预处理过程、模型的初始化和训练过程、以及模型性能的评估。本文还将展示模型结构的可视化,使读者能够直观地理解模型的工作原理。通过这些详细的实验步骤和结果分析,本文期望为读者提供一种清晰、系统的方法来理解和实现手写数字识别。

1.2实验环境

·硬件环境:AMD Ryzen 7 5800H ,16GB DDR4内存,NVIDIA GTX 3060显卡
·软件环境:Python 3.9,PyTorch 2.3.0+cpu,torchvision 0.18.0+cpu,NumPy 1.24.2
·开发工具:PyCharm 2023.2.1

1.2.1安装PyTorch

打开命令行工具(在Windows上是CMD或PowerShell,在macOS或Linux上是Terminal),执行以下命令安装PyTorch。我们将使用清华大学的镜像源以加快下载速度。

pip install torch torchvision -i https://pypi.tuna.tsinghua.edu.cn/simple

1.2.2安装其他必要的库

我们还将使用NumPy和Pillow等库,同样使用清华源进行安装:

pip install numpy pillow -i https://pypi.tuna.tsinghua.edu.cn/simple

二.模型说明

2.1模型概述

本次实验中使用的模型是一个自定义的多层前馈神经网络(Multilayer Feedforward Neural Network),专为手写数字识别任务设计。该模型利用深度学习的原理,通过学习输入图像的特征来实现对数字的有效分类。

2.2模型结构

模型结构由以下几个主要部分组成:
·输入层:接收28x28像素的手写数字图像。
·隐藏层:包含两个线性层,其中第一个线性层后接ReLU激活函数,第二个线性层同样后接ReLU激活函数。
·输出层:最后一个线性层映射到10个输出节点,代表数字0到9。
下方表格展示模型的结构,使用了torchsummary 库进行转化。
Layer (type) Output Shape Param #

Linear-1 [-1, 128] 100,480
Linear-2 [-1, 64] 8,256
Linear-3 [-1, 10] 650

Total params: 109,386
Trainable params: 109,386
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.00
Forward/backward pass size (MB): 0.00
Params size (MB): 0.42
Estimated Total Size (MB): 0.42
----------------------------------------------------------------

三.数据说明

3.1 输入数据

模型的输入是标准化后的灰度图像,维度为(1, 28, 28),其中1代表批次大小,28x28代表图像的尺寸
官方提供的数据集训练集索引等文件无法直接查看,MNIST数据集的训练集索引文件(例如train-images-idx3-ubyte)是一种特定格式的文件。这个文件是一个二进制文件,包含了训练集中所有图像的索引信息,每个图像的像素数据和标签信息在文件内按顺序排列。
要查看这些二进制文件中的内容,需要使用专门的程序来解析文件格式,本文提供了转化的程序,具体见附录sampled_data.py 代码。转化之后部分样本图片见下图。
1718591435374.jpg

3.1.1输入数据特征

模型的输入数据是灰度图像,这些图像已经被预处理并标准化,以适应模型的输入要求。具体来说,每张图像的尺寸是28x28像素,代表了一个手写数字的形状和边缘细节。

3.1.2输入数据维度

1:这个数字代表批次大小(batch size),即每次输入到模型中的图像数量。在这里,批次大小为1,意味着模型将逐个处理图像
28:图像的高度,以像素为单位
28:图像的宽度,以像素为单位

3.1.3输入数据预处理

图像在输入到模型之前,会经过以下预处理步骤:
灰度转换:将彩色图像转换为灰度图像,以减少不必要的颜色信息,降低计算复杂度。
尺寸调整:将图像大小调整为28x28像素,以符合模型输入的固定尺寸要求。
标准化:将图像像素值从[0, 255]线性缩放到[0.0, 1.0]范围内,以提高模型训练的稳定性和收敛速度。

3.2 数据格式

图像数据以NumPy数组的形式进行处理,数据类型为float32,像素值归一化到[0.0, 1.0]范围内。模型的输出是一个10维的概率分布向量,每个维度对应一个数字类别的预测概率。
该模型是本文根据实验目的自行设计和实现的。虽然它基于常见的多层感知机(MLP)架构,但本文根据MNIST数据集的特点对网络结构进行了调整,以优化识别性能。

3.2.1输出数据特征

模型的输出是一个10维的概率分布向量。这个向量中的每个维度对应一个数字类别(0到9),表示模型对输入图像表示该数字的预测概率。

3.2.2输出数据维度

10:这个数字代表输出向量的维度,即模型预测的类别数。在MNIST数据集中,共有10个类别,分别对应数字0到9。

3.2.3输出数据的意义

输出向量中的每个元素值表示模型对输入图像属于对应数字的置信度。例如,如果输出向量中索引为2的元素值最高,那么模型预测输入图像表示数字2。

3.2.4输出数据的生成

模型的最后一层是一个线性层,它将前一层的输出映射到10维空间。然后,使用log_softmax激活函数生成最终的输出向量。log_softmax不仅能够将模型输出转换为概率分布,还能够提高数值稳定性,使得模型在训练过程中更加稳定。

3.3 训练集与测试集

3.3.1数据集规模和组成

MNIST数据集包含60,000张训练图像和10,000张测试图像。训练集用于模型的训练,测试集用于评估模型的性能。
·训练集(Training Set):包含60,000张图像,用于模型的学习过程。这些图像提供了大量的数据,使模型能够学习到数字的特征和模式。
·测试集(Test Set):包含10,000张图像,用于评估模型在未见过的数据上的表现。测试集提供了一个衡量模型泛化能力的标准。

3.3.2图像特点

训练集和测试集中每个图像都是灰度的,像素值范围从0(黑色)到255(白色)。同时图像已经被大小标准化,即所有图像都调整为28*28像素,这简化了模型输入的处理。图像中的数字没有额外的背景,通常是白色背景上的黑色数字。

3.3.3数据集的获取

MNIST数据集可以在多个平台上获取,包括官方网站和各种机器学习库。可以使用 torchvision 库加载 MNIST 数据集,如果本地没有找到模型,这段代码会自动下载并加载 MNIST 数据集,使其准备好用于模型的训练和测试。

from torchvision import datasetstrain_dataset = datasets.MNIST(root='./data', train=True, download=True)
test_dataset = datasets.MNIST(root='./data', train=False, download=True)

四.实验代码

4.1数据加载

本文使用PyTorch的DataLoader和datasets来加载MNIST数据集。

from torchvision
import datasets, transforms# 定义图像预处理的转换
transform = transforms.Compose([    transforms.ToTensor(),  # 将图像转换为张量
transforms.Normalize((0.1307,), (0.3081,))  # 标准化
])
# 加载训练集和测试集
train_dataset = datasets.MNIST(root='./data', train=True,
transform=transform, download=True)test_dataset = datasets.MNIST(root='./data', train=False, transform=transform)
# 创建DataLoader实例
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=64, shuffle=False)

4.2模型定义

本文定义了一个多层前馈神经网络,如下所示:

import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(28 * 28, 128)  # 第一个隐藏层
self.fc2 = nn.Linear(128, 64)       # 第二个隐藏层
self.fc3 = nn.Linear(64, 10)        # 输出层
def forward(self, x):
x = x.view(-1, 28 * 28)  # 展平图像
x = F.relu(self.fc1(x))  # 第一个隐藏层的ReLU激活
x = F.relu(self.fc2(x))  # 第二个隐藏层的ReLU激活
x = self.fc3(x)         # 输出层
return F.log_softmax(x, dim=1)  # log_softmax输出

4.3训练过程

训练模型时,本文使用交叉熵损失函数和随机梯度下降优化器:

import torch.optim as optim
# 实例化模型、损失函数和优化器
model = Net()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
# 训练模型的函数
def train(model, train_loader, criterion, optimizer):
model.train()  # 设置模型为训练模式
for data, target in train_loader:
optimizer.zero_grad()  # 清除梯度
output = model(data)   # 前向传播
loss = criterion(output, target)  # 计算损失
loss.backward()  # 反向传播
optimizer.step()  # 更新参数

4.4测试评估

在测试阶段,本文评估模型在测试集上的性能:

# 测试模型的函数
def test(model, test_loader, criterion):
model.eval()  # 设置模型为评估模式
correct = 0
total = 0
with torch.no_grad():  # 在测试阶段不计算梯度
for data, target in test_loader:
output = model(data)
_, predicted = torch.max(output.data, 1)
total += target.size(0)
correct += (predicted == target).sum().item()
accuracy = 100 * correct / total
print(f'Accuracy of the model on the test images: {accuracy}%')
# 调用训练和测试函数
train(model, train_loader, criterion, optimizer)
test(model, test_loader, criterion)

五.实验结果说明

5.1实验结果概述

经过一系列的训练周期(epochs),本文的手写数字识别模型在MNIST数据集上表现出了令人满意的性能。实验结果不仅展示了模型的准确性,还包括了模型对于测试集的响应情况。

5.2训练过程

在训练过程中,本文观察到损失函数值逐渐减小,这表明模型正在学习并逐渐适应训练数据。通过每个epoch后的输出,本文可以监控模型的进展情况:
Train Epoch: 4 表示当前是第4个训练周期
每一行输出对应于训练集中的一个批次(batch)的损失(loss)值。在这个例子中,训练集有60,000个样本,假设每个批次(batch)包含64个样本,那么将有60,000 / 64 = 937.5,即大约938个批次
方括号内的[0/60000 (0%)] 表示当前处理的样本数和总样本数以及完成的百分比。例如,[0/60000 (0%)] 表示训练刚开始,还没有处理任何样本
Loss: 0.011370 显示了当前批次的损失值,损失值越小表示模型的预测越接近真实标签
Test Accuracy: 97.72% 表示模型在测试集上的准确度为97.72%。这是衡量模型泛化能力的一个重要指标,即模型对未见过的数据的预测能力
1718591914039.jpg
5.3测试结果
在测试阶段,模型对10,000张未见过的测试图像进行了分类。以下是模型性能的具体数字:
准确率(Accuracy):模型在测试集上的准确率达到了97.53%,这意味着模型能够正确识别出约9753张图像中的数字。
结果可视化
为了更直观地展示模型的识别效果,本文随机选取了一些测试图像,并展示了模型的预测结果:

Image| True LabelPredicted Label
012333
256366
325411

5.4性能评估

模型的性能评估不仅基于准确率,本文还考虑了模型的泛化能力、收敛速度和稳健性。通过实验,本文发现模型在多次迭代后能够快速收敛到较低的损失值,并且在不同的测试图像上表现出了很好的泛化能力。

5.5结果分析

实验结果表明,本文的模型能够有效地识别手写数字。然而,本文也注意到在某些情况下,如图像质量较差或手写风格独特时,模型的识别准确率可能会有所下降。这提示本文在未来的工作中需要进一步优化模型结构,探索数据增强技术,以及可能的模型集成策略。

5.6实战测试

本部分将会使用个人的手写图片进行测试,相较于官方所提供的测试集,本文使用的测试图片不再局限于大小标准化28*28像素,也不再局限于只有像素值范围从0(黑色)到255(白色),本文直接使用日常生活中手写的图片进行识别。
具体步骤如下:
· 使用 OpenCV 和 PIL 库读取和处理手写图像。
· 应用图像增强技术,包括灰度转换、高斯模糊、二值化和反转。
· 应用一系列图像预处理转换,包括调整大小、转换为张量和标准化。
· 加载并显示原始图像及其增强版本。
· 创建模型实例并加载预训练模型的状态。
· 对预处理后的图像进行推理,并输出预测结果。
下方从左到右边分别为原始拍摄图像,图像增强处理后图像,调整大小后图像
1718591999665.jpg 1718592012397.jpg1718592029628.jpg
最终处理结果:
1718592041192.jpg

六.实验总结

在本实验中,我训练了一个神经网络模型用于手写数字识别,并在标准测试集上取得了较高的准确率。然而,当我们使用实际拍摄的手写数字图片进行测试时,模型的准确率明显下降。以下是对此现象的分析和总结。

6.1测试集准确率较高的原因

数据一致性:标准测试集(如MNIST)中的图片都是经过标准化处理的,尺寸为28x28像素,且都是灰度图像,背景干净,数字清晰。这使得模型可以轻松地提取特征并进行分类。
数据规模:标准测试集通常包含大量的样本,确保了模型在训练过程中可以学到更多的特征,具备更好的泛化能力。
无噪声数据:标准测试集中的图片通常没有噪声,图像质量高,数字的边缘清晰,这大大降低了分类的难度。

6.2实际拍照测试准确率较低的原因

1、图像预处理不足:实际拍摄的图片可能会受到光照、角度、背景复杂度等因素的影响。如果图像预处理(如去噪、灰度转换、二值化等)不到位,会导致模型输入的图片质量差,从而影响识别效果。
2、图像尺寸不一致:实际拍摄的图片尺寸不统一,可能会导致模型在调整尺寸过程中失去一些重要的特征信息。
3、图像噪声和失真:实际拍摄的图片可能存在噪声、模糊、光影变化等问题,这些都会干扰模型的特征提取过程,导致识别错误。
4、数据分布差异:训练和测试使用的数据集分布不同。标准测试集中的图片与实际拍摄的图片在数据分布上可能存在较大差异,模型在实际场景中无法有效泛化。
5、背景干扰:实际拍摄的图片背景复杂度高,可能包含各种干扰信息,而标准测试集中的图片背景干净,这也是模型在实际场景中表现不佳的原因之一。

6.3后面的改进方法

为了提升模型在实际拍摄图片中的准确率,可以从以下几个方面进行改进:
1、增强图像预处理
采用更高级的图像处理技术,如自适应阈值、形态学变换等,增强数字的可识别性。增加图像去噪处理,如中值滤波、双边滤波等。
2、数据增强
在训练过程中使用数据增强技术,如旋转、缩放、平移、加噪声等,增强模型的鲁棒性。收集更多实际拍摄的手写数字图片,扩充训练集,提升模型对实际场景的适应性。
3、模型改进
尝试使用更复杂的模型结构,如卷积神经网络(CNN),更好地捕捉图像的空间特征。引入正则化技术,如Dropout,防止过拟合,提升模型的泛化能力。

附录

附录A main.py

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader


#定义网络结构
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(28 * 28, 128)  # 一个线性层
self.fc2 = nn.Linear(128, 64)      # 另一个线性层
self.fc3 = nn.Linear(64, 10)       # 输出层

def forward(self, x):
x = x.view(-1, 28 * 28)  # 展平图像
x = F.relu(self.fc1(x))    # 应用ReLU激活函数
x = F.relu(self.fc2(x))
x = self.fc3(x)
return F.log_softmax(x, dim=1)

#初始化网络、损失函数和优化器
net = Net()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9)

'''
加载数据集(PyTorch的一个内置数据集,MNIST数据集:是一个公开的、广泛使用的数据集,用于机器学习和计算机视觉领域的基准测试。它包含60,000个训练样本和10,000个测试样本,每个样本都是一个28x28像素的手写数字图像,以及对应的数字标签(0到9))
'''
transform = transforms.Compose([
transforms.ToTensor(),# 将PIL图片或NumPy `ndarray`转为`FloatTensor`(将图像转换为PyTorch的张量格式,并将图像的像素值从0到255归一化到0到1之间。)
transforms.Normalize((0.1307,), (0.3081,))#(对数据进行标准化处理,使数据的均值和标准差分别接近0和1。这里的参数 (0.1307,) 和 (0.3081,) 是MNIST数据集的均值和标准差)
])

train_dataset = datasets.MNIST(root='./data', train=True, transform=transform, download=True)   #预处理的MNIST训练集
test_dataset = datasets.MNIST(root='./data', train=False, transform=transform)                  #预处理的MNIST测试集

train_loader = DataLoader(dataset=train_dataset, batch_size=64, shuffle=True)                   #创建了训练集 DataLoader 实例
test_loader = DataLoader(dataset=test_dataset, batch_size=64, shuffle=False)                    #创建了测试集 DataLoader 实例

#训练网络
def train(epoch):
for batch_idx, (data, target) in enumerate(train_loader):
optimizer.zero_grad()
output = net(data)
loss = criterion(output, target)
loss.backward()
optimizer.step()
if batch_idx % 100 == 0:
print(f'Train Epoch: {epoch} [{batch_idx * len(data)}/{len(train_loader.dataset)} ({100.0 * batch_idx / len(train_loader):.0f}%)]\tLoss: {loss.item():.6f}')

#训练和测试循环
def test():
with torch.no_grad():
net.eval()
correct = 0
total = 0
for data, target in test_loader:
output = net(data)
_, predicted = torch.max(output.data, 1)
total += target.size(0)
correct += (predicted == target).sum().item()
print(f'Test Accuracy: {100 * correct / total:.2f}%')
'''
Train Epoch: 5 表示当前是第5个训练周期
每一行输出对应于训练集中的一个批次(batch)的损失(loss)值。在这个例子中,训练集有60,000个样本,假设每个批次(batch)包含64个样本,那么将有60,000 / 64 = 937.5,即大约938个批次
方括号内的[0/60000 (0%)] 表示当前处理的样本数和总样本数以及完成的百分比。例如,[0/60000 (0%)] 表示训练刚开始,还没有处理任何样本
Loss: 0.011370 显示了当前批次的损失值,损失值越小表示模型的预测越接近真实标签
Test Accuracy: 97.72% 表示模型在测试集上的准确度为97.72%。这是衡量模型泛化能力的一个重要指标,即模型对未见过的数据的预测能力
'''

for epoch in range(1, 10):  # 训练10个epoch
train(epoch)
test()
#模型保存
PATH = './models/mnist_net.pth'
torch.save(net.state_dict(), PATH)

附录B test.py

import os
import cv2
import numpy as np
import torch
import torchvision
from PIL import Image
import torchvision.transforms as transforms
#from main import Net  # 确保导入模型定义
import torch.nn as nn
import torch.nn.functional as F


print(np.__version__)

#——————————————————————————————————————————————————————————————————————————————————————————————
#图片增强功能
def process_image(image_path):
# 读取图像
image = cv2.imread(image_path)
# 转换为灰度图像
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 应用高斯模糊,去除噪声
blurred_image = cv2.GaussianBlur(gray_image, (1, 1), 0)
# 使用 Otsu's thresholding 自动确定阈值进行二值化
_, binary_image = cv2.threshold(blurred_image, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
# 可选:形态学膨胀,让数字笔画更粗
kernel = np.ones((1, 1), np.uint8)
#dilated_image = cv2.dilate(binary_image, kernel, iterations=1)#进行膨胀操作
dilated_image = binary_image.copy()# 不进行膨胀操作
# 反转图像,使得数字突出(如果需要)
#Image.fromarray(dilated_image).show()
inverted_image = cv2.bitwise_not(dilated_image)
#Image.fromarray(inverted_image).show()
# 可选:调整图像尺寸
#inverted_image = cv2.resize(inverted_image, (28, 28))
if np.mean(inverted_image) >= 128:          #像素值越大对应图片越亮
print(np.mean(inverted_image))
print("识别为:浅色背景深色数字")
return dilated_image
else:
print(np.mean(inverted_image))
print("识别为:深色背景浅色数字")
return inverted_image
#——————————————————————————————————————————————————————————————————————————————————————————————————

class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(28 * 28, 128)  # 一个线性层
self.fc2 = nn.Linear(128, 64)      # 另一个线性层
self.fc3 = nn.Linear(64, 10)       # 输出层

def forward(self, x):
x = x.view(-1, 28 * 28)  # 展平图像
x = F.relu(self.fc1(x))    # 应用ReLU激活函数
x = F.relu(self.fc2(x))
x = self.fc3(x)
return F.log_softmax(x, dim=1)
#-----------------------------------------------------------------------------------------
# 定义图像预处理的转换
transform = transforms.Compose([
transforms.Grayscale(num_output_channels=1),            #转换将图像转换为灰度图像
transforms.Resize((28, 28)),                            #将图像的大小调整为 28x28 像素
transforms.ToTensor(),                                  #将 PIL 图像或 NumPy 数组转换为 FloatTensor,并将像素值从 [0, 255] 归一化到 [0.0, 1.0] 的范围
transforms.Normalize((0.1307,), (0.3081,))   #对图像数据进行标准化处理
])

# 加载原始图像
image_path = 'test_image4.png'
original_path = 'original_image.png'
image_image = Image.open(image_path)
original_image = Image.open(original_path)
Image.open(image_path).show()  # 显示图像
print("现在展示原图像:")
#input("Press Enter to continue...")
#original_image = Image.open(image_path).convert("L")  # 直接确保图像是灰度的
original_image = Image.fromarray(process_image(image_path))  # 未确保图像是灰度的,数字增强版本
original_image.show()  # 显示强化之后的图像
print("现在展示原图像强化处理之后的结果:")
#input("Press Enter to continue...")

# 逐步应用转换并显示结果,展示转换的过程
for t in transform.transforms:
original_image = t(original_image)  # 应用转换并更新 original_image
if t.__class__.__name__ == "Grayscale":
continue
if t.__class__.__name__ == "Resize":
print("现在展示将图像的大小调整为 28x28 像素之后的结果:")
original_image.show()  # 显示图像
#input("Press Enter to continue...")
os.system('cls')
#-----------------------------------------------------------------------------------------

# 创建模型实例
model = Net()  #Net 是模型类名

# 加载保存的模型状态
# 保存的模型文件路径
model_path = './models/mnist_net.pth'
model.load_state_dict(torch.load(model_path))

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

image_path = 'test_image4.png'
image = Image.open(image_path).convert("L")  # 确保图像是灰度的
#preprocessed_image = original_image.unsqueeze(0)  # 增加一个批次维度
preprocessed_image = transform(image).unsqueeze(0)  # 增加一个批次维度

# 推理
with torch.no_grad():
output = model(preprocessed_image)
_, predicted = torch.max(output, 1)
print(f'Predicted number: {predicted.item()}')


#for t in transform.transforms:
#    original_image = t()

附录C sampled_data.py

import matplotlib.pyplot as plt
import numpy as np

import torchvision.transforms as transforms
from torchvision.datasets import MNIST
from torch.utils.data import DataLoader

# 定义图像的转换(将图像转换为Tensor)
transform = transforms.Compose([transforms.ToTensor()])

# 加载MNIST数据集
mnist_dataset = MNIST(root='./data', train=True, download=True, transform=transform)

# 创建数据加载器(批量大小设置为64)
data_loader = DataLoader(dataset=mnist_dataset, batch_size=64, shuffle=True)

# 从数据加载器中获取一个批次的图像和标签
images, labels = next(iter(data_loader))

# 计算图像数据的平均值
mean_value = np.mean(images.numpy())
print("图像数据的平均值:", mean_value)

# 设置要展示的图像数量
num_images_to_show = 6

# 创建一个图形和子图阵列
fig, axes = plt.subplots(1, num_images_to_show, figsize=(15, 15))

# 遍历要展示的图像和标签
for i in range(num_images_to_show):
ax = axes[i]
ax.imshow(images[i].squeeze(), cmap='gray')  # squeeze()用于去掉多余的维度
ax.set_title(f'Label: {labels[i].item()}')
ax.axis('off')  # 关闭坐标轴

# 显示图形
plt.show()

附录D model_architecture.py

import torch
from torchsummary import summary

# 定义模型
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = torch.nn.Linear(28 * 28, 128)  # 全连接层
self.fc2 = torch.nn.Linear(128, 64)
self.fc3 = torch.nn.Linear(64, 10)

def forward(self, x):
x = x.view(-1, 28 * 28)  # 展平图像
x = torch.nn.functional.relu(self.fc1(x))  # ReLU激活函数
x = torch.nn.functional.relu(self.fc2(x))
x = self.fc3(x)
return torch.nn.functional.log_softmax(x, dim=1)

# 实例化模型
model = Net()

# 生成模型结构的可视化
summary(model, (1, 28, 28))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1855162.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

两个方法,批量替换PPT中的字体

经常制作ppt的朋友可能会遇到需要批量替换字体的情况,如果我们想要更换ppt中的字体,今天分享PPT批量替换字体的两个方法。 方法一: 找到功能栏中的编辑选项卡,点击替换 – 替换字体,在里面选择我们想要替换的字体就可…

【因果推断python】51_去偏/正交机器学习3

目录 What is Non-Parametric About? What is Non-Parametric About? 在我们继续之前,我只想强调一个常见的误解。当我们考虑使用非参数 Double-ML 模型来估计 CATE 时,我们似乎会得到一个非线性治疗效果。例如,让我们假设一个非常简单的数…

LeetCode665.非递减数列

LeetCode刷题记录 文章目录 📜题目描述💡解题思路⌨C代码 📜题目描述 给你一个长度为 n 的整数数组 nums ,请你判断在 最多 改变 1 个元素的情况下,该数组能否变成一个非递减数列。 我们是这样定义一个非递减数列的&am…

昆明理工大学24计算机考研各专业复试线大幅下降,B区国家线即可复试!

昆明理工大学(Kunming University of Science and Technology),位于云南省昆明市,是云南省综合性重点大学,由国防科技工业局与云南省人民政府共建高校,入选“中西部高校基础能力建设工程”、国家建设高水平…

第10关:视图1 、第11关:视图2 、第12关:用户。

目录 第10关:视图1 任务描述 知识补充 答案 第11关:视图2 任务描述 知识补充 答案 第12关:用户 任务描述 知识补充 答案 本篇博客声明:所有题的答案不在一起,可以去作者博客专栏寻找其它文章。 第10关&…

Phi-3 模型手机部署教程(微软发布的可与GPT-3.5媲美的小模型)

前面几篇博文,老牛同学和大家一起在个人电脑部署了Qwen2、GLM4、Llama3、ChatTTS和Stable Diffusion等 LLM 大模型,也通过 API 和 WebUI 的方式完成了体验。 但是这些大模型因为部署在个人电脑本地,不能够随时携带。如果能在手机上部署大模型…

EtherCAT笔记(三) —— 主站与从站的硬件组成

1. EtherCAT 主站的硬件组成 EtherCAT主站使用标准以太网控制器,也即EtherCAT主站可以使用以太网控制器的任何设备。当我们有一台带网口的笔记本、工控机,甚至是树莓派也可以作为EtherCAT主站。 EtherCAT协议是对Ethernet协议在实时控制等方面的优化&am…

一篇文章带你快速入门java

文章目录 一、一个简单的java代码1.1 Java程序的结构由三个不成组成:1.2 运行java程序1.3 JDK,JRE,JVM之间的关系?(面试题)1.4 标识符1.5 注释1.6 关键字 一、一个简单的java代码 public class HelloJava {public static void main(String[] args) {Sys…

【建议收藏】Android中高级大厂面试源码秘籍,为你备战2021金三银四,直通大厂

首先来说下为什么要读源码,有学习源码的必要吗? 为什么要阅读源码? 关于为什么阅读和学习源码,我个人认为可能有以下几点: (一)吊打面试官,应对面试 为了找到更好的工作&#xff…

Linux配置中文环境

文章目录 前言中文语言包中文输入法中文字体 前言 在Linux系统中修改为中文环境,通常涉及以下几个步骤: 中文语言包 更新源列表: 更新系统的软件源列表和语言环境设置,确保可以安装所需的语言包。 sudo apt update sudo apt ins…

Python+Pytest+Yaml+Request+Allure框架源代码之(一)common公共方法封装

common模块: get_path.py:获取路径方法 # -*- coding: UTF-8 -*- import os# 项目根目录 BASE_DIR os.path.dirname(os.path.dirname(os.path.abspath(__file__)))# 配置文件目录 CONFIG_DIR os.path.join(BASE_DIR,config)# 测试用例文件目录 TESTCA…

康奈尔大学之论文审稿模型Reviewer2及我司七月对其的实现(含PeerRead)

前言 自从我司于23年7月开始涉足论文审稿领域之后「截止到24年6月份,我司的七月论文审稿GPT已经迭代到了第五版,详见此文的8.1 七月论文审稿GPT(从第1版到第5版)」,在业界的影响力越来越大,所以身边朋友如发现业界有相似的工作&a…

年薪50w+的项目经理,手把手教你如何复盘

复盘是一种重要的学习和改进工具,对于项目经理来说,能帮助识别项目中的成功与失败,为未来的项目管理提供宝贵经验。 理论部分 定义目标。在开始复盘之前,明确复盘的目标是什么。是为了找出项目中的问题并提出解决方案&#xff0c…

自动驾驶规划中使用 OSQP 进行二次规划 代码原理详细解读

目录 1 问题描述 什么是稀疏矩阵 CSC 形式 QP Path Planning 问题 1. Cost function 1.1 The first term: 1.2 The second term: 1.3 The thrid term: 1.4 The forth term: 对 Qx 矩阵公式的验证 整体 Q 矩阵(就是 P 矩阵,二次项的权重矩阵&…

Android开发:自定义TabLayout,神奇效果竟是如此简单

此时有的小伙伴可能会想,自定义view太麻烦,不如让UI直接把这个弧度切出来,不是一共就三个tab项嘛,Textview,ImageView… 这样横着排起来,然后做适当的显示和隐藏不就行啦。 是的,确实是可以&am…

人工智能在数字病理切片虚拟染色以及染色标准化领域的研究进展|顶刊速递·24-06-23

小罗碎碎念 本期推文主题:人工智能在数字病理切片虚拟染色以及染色标准化领域的研究进展 这一期的推文是我发自内心觉得为数不多,特别宝贵的一篇推文,原因很简单——可参考的文献相对较少&方向非常具有研究意义&现在不卷。 数字病理…

nginx服务器连接数告警

序言 只要系统之间有交互,那么就会有连接数,连接数的告警阈值一般设置个几万,当连接数开始告警之后,怎么来排查呢? 连接数过多,会消耗cpu,内存,文件句柄等资源,其实也还好…

《算法笔记》总结No.2——模拟

一.简单模拟 考察代码能力,不涉及算法:一类题目怎么说你就怎么做的类型~ 巴音布鲁克比赛,以车队为基准评选冠军。业务要求是:第一行输入正整数N,代表车手的总个数;接下来的N行每行键入两个数字&#xff1a…

【TOOL】ceres学习笔记(二) —— 自定义函数练习

文章目录 一、曲线方程1. 问题描述2. 实现方案 一、曲线方程 1. 问题描述 现有数学模型为 f ( x ) A e x B s i n ( x ) C x D f(x)Ae^xBsin(x)Cx^D f(x)AexBsin(x)CxD ,但不知道 A A A 、 B B B 、 C C C 、 D D D 各参数系数,实验数据中含有噪声…

Windows程序设计课程作业-3(文件并发下载)

目录 目录 1.作业内容 2.作业要求 3.主要思路 1)窗体和组件初始化 2)下载管理器实例化 3)按钮点击事件处理 4)窗体加载事件处理 5)下载消息处理 4.主要难点 1)多线程管理: 2&#xff09…