【深度学习】多层感知器MLP模型对 MNIST 数据集中的手写数字进行分类

news2024/12/24 0:15:16

本模型是解决一个十分类的问题:
在这之前,可以先看看一个Pytorch的简单的示例:

它展示了如何定义一个简单的神经网络、准备数据、训练模型以及评估模型:

import torch  
import torch.nn as nn  
import torch.optim as optim  
from torch.utils.data import DataLoader, TensorDataset  
  
# 假设我们有一些简单的输入输出数据  
x_data = torch.tensor([[1.0], [2.0], [3.0]])  
y_data = torch.tensor([[2.0], [4.0], [6.0]])  
  
# 定义一个简单的线性模型  
class LinearRegressionModel(nn.Module):  
    def __init__(self):  
        super(LinearRegressionModel, self).__init__()  
        self.linear = nn.Linear(1, 1)  # 输入特征数为1,输出特征数也为1  
  
    def forward(self, x):  
        y_pred = self.linear(x)  
        return y_pred  
  
model = LinearRegressionModel()  
  
# 定义损失函数和优化器  
criterion = nn.MSELoss()  
optimizer = optim.SGD(model.parameters(), lr=0.01)  
  
# 将数据包装为 PyTorch 的 DataLoader  
dataset = TensorDataset(x_data, y_data)  
data_loader = DataLoader(dataset, batch_size=1, shuffle=True)  
  
# 训练模型  
for epoch in range(100):  
    for i, (inputs, targets) in enumerate(data_loader):  
        # 前向传播  
        outputs = model(inputs)  
        loss = criterion(outputs, targets)  
  
        # 反向传播和优化  
        optimizer.zero_grad()  # 清除之前的梯度  
        loss.backward()       # 反向传播计算梯度  
        optimizer.step()      # 更新权重  
  
    if (epoch+1) % 10 == 0:  
        print(f'Epoch [{epoch+1}/{100}], Loss: {loss.item():.4f}')  
  
# 评估模型(这里简单地打印最后一个预测结果)  
with torch.no_grad():  # 不需要计算梯度  
    predictions = model(x_data)  
    print(f'Predictions: {predictions.data}')

定义了一个简单的线性回归模型,并使用均方误差(MSE)作为损失函数。
使用了随机梯度下降(SGD)优化器来更新模型的权重。
数据被包装为 PyTorch 的 DataLoader,它使得批量处理和数据打乱变得简单。
最后,在训练过程中打印了每个 epoch 的损失,并在训练结束后打印了模型的预测结果。


现在正式进行!!!

实现了一个简单的多层感知器(Multi-Layer Perceptron, MLP)模型来对 MNIST 数据集中的手写数字进行分类。主要包括以下内容:

  1. 定义了一个名为 Model 的继承自 nn.Module 的模型类,其中包括三个全连接层:liner_1liner_2liner_3,并在 forward 方法中实现了前向传播逻辑。

  2. 使用 torchvision 加载 MNIST 数据集,并对数据进行处理。

  3. 创建了训练数据加载器 train_dl 和测试数据加载器 test_dl,以及模型和优化器的初始化。

  4. 定义了 train 函数用于训练模型,并且在训练过程中计算损失和精度。

  5. 定义了 test 函数用于测试模型的效果。

  6. 对模型进行了多轮(50 轮)的训练和测试,并在每个 epoch 结束后输出当前 epoch 的损失和准确率。最后输出 “Done!!!” 表示训练完成。

  7. 使用 matplotlib 对训练过程中的损失和正确率进行可视化展示。

下面通过绘图来看一下MNIST数据集中的这些图片是什么样子的。使用Matplotlib库绘图,绘制imgs中的前10张图片:
在这里插入图片描述
创建一个简单的多层感知器,这个模型使用torch.nn.Linear层创建。
torch.nn.Linear层是全连接层,本质上就是对全部输入加权求和,它要求输入数据集的形状为一维的,如果使用批量运算,则增加一个batch维,也就是需要输入数据是二维的形状,第一维是batch维,第二维是数据特征,即(batch_size,feature_length)形式。

训练和测试数据优化器损失函数模型等全部准备好了,再编写训练循环。为了方便以后代码复用,我们将编写一个训练函数train()和一个测试函数test(),在这两个函数中分别对全部训练数据和全部测试数据进行一次训练或测试。

train()函数中,首先使用len(dataloader.dataset)获取训练数据集样本总数量,使用len(dataloader)获取当前dataloader总批次数;然后对传进来的训练数据dataloader进行迭代,在迭代过程中,首先调用模型对当前批次的输入进行预测,并根据真实标签y计算一个批次中样本的平均损失;然后使用反向传播算法,根据损失优化模型参数;最后为了方便了解模型随着训练在数据集上的损失和正确率变化情况,初始化一个correct变量,并用它累计所有批次中预测正确的样本总数;初始化一个train_loss变量,用于累计所有批次的损失之和,这里的train_loss是所有批次的损失之和,所以计算全部样本的平均损失时需要除以总批次数,correct是预测正确的样本总数,计算整个epoch总体正确率,需要除以样本总数量。至此就得到了训练中平均正确率和平均损失值。

test()函数代码与train()函数类似,不过在test()函数代码中,仅仅测试模型在测试数据集的表现,也就是计算模型在测试数据集上的正确率和损失,并没有使用反向传播算法根据损失优化模型参数等部分的代码

所需的完整代码如下:(可运行)

import matplotlib.pyplot as plt
import torchvision
from torchvision.transforms import ToTensor
from torch import nn

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        # 第一层输入展平后的特征长度为28×28,创建120个神经元
        self.linear_1 = nn.Linear(28×28,120)
        # 第二层输入的是前一层的输出,创建84个神经元
        self.linear_2 = nn.Linear(120,84)
        # 输出层接收第二层的输入84,输出分类个数10
        self.linear_3 =  nn.Linear(84,10)

    def forward(self, input):
        # 将输入展平为2维
        x = input.view(-1,28*28)
        # 连接第一层linear_1,并使用ReLU函数激活
        x = torch.relu(self.linear_1(x))
        # 连接第二层linear_2,并使用ReLU函数激活
        x = torch.relu(self.linear_2(x))
        # 输出层,输出张量的长度,与类别数量一致
        x = self.linear_3(x)

        return x



train_ds = torchvision.datasets.MNIST('data/', train=True, download=True, transform=ToTensor())
test_ds = torchvision.datasets.MNIST('data/', train=False, download=True, transform=ToTensor())

train_dl = torch.utils.data.DataLoader(train_ds, batch_size=64,shuffle=True)
test_dl = torch.utils.data.DataLoader(test_ds, batch_size=46)

imgs, labels = next(iter(train_dl))
print(imgs.shape)
print(labels.shape)

# 创建画布
plt.figure(figsize=(10,1))
for i,img in enumerate(imgs[:10]):
    # 将张量转化为ndarray
    npimg = img.numpy()
    # 将图形形状由(1,28,28)转为(28,28)
     npimg = np.squeeze(npimg)
    # 初始化子图
    plt.subplot(1,10,i+1)
    plt.imshow(npimg)
    # 关闭显示子图坐标
    plt.axis('off')


# 首先获取当前环境可用的训练设备(CPU或GPU),然后初始化前面编写的多层感知器模型,并在初始化模型后设置模型使用当前可用的device
device = "cuda" if torch.cuda.is_available() else "cpu"
print("Using {} device".format(device))
model = Model().to(device) # 初始化模型,并设置模型使用device

# 初始化交叉熵损失函数
loss_fn = nn.CrossEntropyLoss()

# 初始化优化器  随机梯度下降优化器
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)


def train(dataloader,model,loss_fn,optimizer):
    size = len(dataloader.dataset) # 获取当前数据集样本的总数量
    num_batches = len(dataloader) # 获取当前dataloader 总批次数
    # train_loss 用于累计所有批次的损失之和,correct 用于累计预测正确的样本总数
    train_loss ,correct = 0,0
    for X,y in dataloader: # 对dataloader进行迭代
        X,y = X.to(device),y.to(device)  # 每一批次的数据设置为使用当前device
        # 进行预测,并计算一个批次的损失
        pred = model(X)
        loss = loss_fn(pred,y) # 返回的是平均损失
        # 使用反向传播算法, 根据损失优化模型参数
        optimizer.zero_grad() # 将模型参数的梯度全部归零
        loss.backward()     # 损失反向传播,计算模型参数梯度
        optimizer.step()    # 根据梯度优化参数

        with torch.no_grad():
            correct += (pred.argmax(dim=1) == y).type(torch.float).sum().item()
            train_loss += loss.item()
    # 由于train_loss 是所有批次的损失之和,所以计算全部样本的平均损失时需要除以总批次数
    train_loss /= num_batches
    # correct 是预测正确的样本总数,若计算整个epoch总体正确率,需除以样本总数量
    correct = correct / size
    return train_loss,correct


def test(dataloader,model):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)
    test_loss ,correct = 0,0
    with torch.no_grad():
        for X,y in dataloader:
            X,y = X.to(device),y.to(device)
            pred = model(X)
            test_loss += loss_fn(pred,y).item()
            correct += (pred.argmax(dim=1) == y).type(torch.float).sum().item()
    test_loss /= num_batches
    correct = correct / size
    return test_loss,correct


epochs = 50 # 一个epoch 代表对全部数据训练一遍

train_loss = [] # 每个epoch训练中训练数据集的平均损失被添加到此列表
train_acc = [] # 每个epoch训练中训练数据集的平均正确率被添加到此列表
test_loss = [] # 每个epoch训练中测试数据集的平均损失被添加到此列表
test_acc = [] # 每个epoch训练中测试数据集的平均正确率被添加到此列表

for epoch in range(epochs):
    # 调用 train() 函数训练
    epoch_loss ,epoch_acc =train(train_dl,model,loss_fn,optimizer)
    # 调用 test() 函数测试
    epoch_test_loss,epoch_test_acc = test(test_dl,model)
    train_loss.append(epoch_loss)
    train_acc.append(epoch_acc)
    test_loss.append(epoch_test_loss)
    test_acc.append(epoch_test_acc)
    # 定义一个打印的模板
    template = ("epoch:{:2d},train_loss:{:.5f},train_acc:{:.1f},test_loss:{:.5f},test_acc:{:.1f}%")
    print(template.format(epoch,epoch_loss,epoch_acc*100,epoch_test_loss,epoch_test_acc*100))

print("Done!!!")


# 可视化直观展示
# 训练过程中损失的变化情况绘图
plt.plot(range(1, epochs+1), train_loss, label='train_loss')
plt.plot(range(1, epochs+1), test_loss, label='test_loss', ls="--")
plt.xlabel('epoch')
plt.legend()
plt.show()

# 正确率变化曲线绘图
plt.plot(range(1, epochs+1), train_acc, label='train_acc')
plt.plot(range(1, epochs+1), test_acc, label='test_acc', ls="--")
plt.xlabel('epoch')
plt.legend()
plt.show()

随着训练epoch数量的增加,刚开始时损失在快速下降,到后面时损失曲线越来越平,下降速度变慢;正确率也有类似的特点,随着epoch增加,正确率的曲线也接近水平,说明模型训练已经接近饱和,继续训练不能更好地优化模型,此时我们可以停止训练

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

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

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

相关文章

私有云和多云管理平台 | Cloudpods v3.10.15 正式发布

功能优化 【主机】裸金属详情页增加部分属性信息【监控】优化告警策略,支持同时设置多监控指标【主机】支持透传设备自动探测【主机】LVM 块存储支持快照【监控】简化 Telegraf 容器的挂载点【主机】新建 VMware 支持同时填写备注信息【存储】KVM 支持对接 LVM 存储…

融汇11款AI工具构建完美应用

本文将为您介绍25个开源项目,分为上下两篇以便您融汇它们来制作自己的AI应用。人工智能(AI)应用在近年来得到了长足的发展。从语音助手到软件开发,人工智能已在我们的生活中无处不在,并得到了广泛应用。 如您所见&…

深入解析内置模块OS:让你的Python代码更懂操作系统

新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一、OS模块简介与基础应用 二、文件与目录操作详解 三、OS模块的高级应用:双色…

【NumPy】关于numpy.mean()函数,看这一篇文章就够了

🧑 博主简介:阿里巴巴嵌入式技术专家,深耕嵌入式人工智能领域,具备多年的嵌入式硬件产品研发管理经验。 📒 博客介绍:分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向…

【竞技宝】西甲:锋霸想和尤文再续前缘,三进宫能否实现?

马竞本赛季的比赛任务已经全部完成,整体来说床单军团的发挥无法让球迷们满意,休赛期球队肯定会有很多补强和调整。根据西班牙媒体报道,球队锋线大将莫拉塔不满自己在球队的出场时间,希望今年夏天离开球队。而西班牙锋霸想要去的球队也已经浮出水面,那就是他曾经效力过的尤文图斯…

【字典树(前缀树) 字符串】2416. 字符串的前缀分数和

本文涉及知识点 字典树(前缀树) 字符串 LeetCode 2416. 字符串的前缀分数和 给你一个长度为 n 的数组 words ,该数组由 非空 字符串组成。 定义字符串 word 的 分数 等于以 word 作为 前缀 的 words[i] 的数目。 例如,如果 words [“a”,…

【NOIP2015普及组复赛】题3:求和

题3:求和 【题目描述】 一条狭长的纸带被均匀划分出了 n n n 个格子,格子编号从 1 1 1 到 n n n。每个格子上都染了一种颜色 c o l o r i color_i colori​ (用 [ 1 , m ] [1,m] [1,m]当中的一个整数表…

【数据结构】排序算法大全(快速、堆、归并、插入、折半、希尔、冒泡、计数、基数)各算法比较、解析+完整代码

文章目录 八、排序1.插入排序1.1 直接插入排序1.2 折半插入排序1.3 希尔排序 2.交换排序2.1 冒泡排序2.2 快速排序 3.选择排序3.1 简单选择排序3.2 堆3.2.1 堆排序3.2.2 堆插入删除*完善代码 堆 4.归并、基数、计数排序4.1 归并排序4.2 基数排序4.3 计数排序 5.内部排序算法的比…

JAVA:Spring Boot整合MyBatis Plus持久层

1、简述 MyBatis Plus是MyBatis的增强工具包,它在MyBatis的基础上进行了扩展,提供了许多便捷的功能,例如通用CRUD操作、分页插件、代码生成器等。使用MyBatis Plus,开发者可以更加方便地进行持久层操作,并且减少了很多…

Python爬虫实战:利用代理IP获取电商数据

文章目录 1.电商数据介绍2.爬取目标3.代理IP推荐4.准备工作4.1 模块安装4.2 代理IP获取 5.爬虫代码实战5.1分析网页5.1.1 获取cookie5.1.2 关键词分析5.1.3 翻页分析5.1.4 数据获取分析 5.2 发送请求5.3 提取数据5.4 保存数据5.5 完整源码5.6 数据分析六、总结 1.电商数据介绍 …

[随笔] 在CSDN的6周年纪念日随笔

纪念 转眼已过6年,大一的时候学习编程,潜水 CSDN 学习各类博文,才学浅薄就没有主动写博文记录自己的学习历程。 过了段时间刚刚到了大二,很喜欢 Todolist,意气风发的写下《一份清爽的编程计划》,哈哈。 …

冷冻式压缩空气干燥机常见几种系统原理图

冷冻式压缩空气干燥机 我们以两种典型的设计流程图为例 1.干式蒸发型,这类冷干机是我们最为常见的设计型式。下图为deltech公司的典型流程图 此类设备各家设计不同的最大区别基本就是在换热器的结构型式上有比较大的区别。换热器主要有:管壳式、铝板换、…

【openlayers系统学习】00官网的Workshop介绍

00Workshop介绍 官方文档:https://openlayers.org/workshop/en/ openlayers官网Workshop学习。 通过官网Workshop,系统学习openlayers的使用。 基本设置 这些说明假定您从最新Workshop版本的 openlayers-workshop-en.zip​ 文件开始。此外&#xff…

KingbaseES数据库merge语法

数据库版本:KingbaseES V008R006C008B0014 简介 MERGE 语句是一种用于数据操作的 SQL 语句,它能够根据指定的条件将 INSERT、UPDATE 和 DELETE 操作结合到单个语句中。其主要作用是在目标表和源表之间进行数据比较和同步,根据条件的匹配情况来…

IBERT眼图扫描(高速收发器八)

前文讲解了GTX的时钟及收发数据通道的组成,之后讲解了眼图、加重、均衡等原理及原因,本文通过xilinx提供的IBERT IP完成实际工程的眼图扫描,确定加重和幅值调节的参数。 1、回环模式 在此之前,需要了解一下GTX的回环模式。如果板…

批处理作业调度问题 (回溯法)

目录 一、问题解析 二、实例剖析 三、算法思路 四、代码实现 结果: 总结 前言 【问题】n 个作业{1, 2, …, n}要在两台机器上处理,每个作业必须先由机器 1 处理,再由机器 2 处理,机器 1 处理作业i所需时间为 ai,…

【Unity实战篇 】| Unity实现 文本框可以自适应大小,到达最大宽度之后再缩小字体

前言 在文本框可以自适应大小拉伸的前提下,增加一个最大限制宽度,使其到达最大宽度后 再启用 Best Fit 实现自适应改变文字大小以适应文本框的大小。 【Unity实战篇 】 | Unity实现 Text文本框可以自适应大小,到达最大宽度之后再缩小字体 在Unity中经常会用到文本组件的自…

Jmeter插件下载(下载和使用教程)

插件管理器:plugins-manager下载安装和使用 下载: 官网地址:https://jmeter-plugins.org/install/Install/ 步骤1:将下载jmeter-plugins-manager-1.10.jar放到目录apache-jmeter-5.1.1\lib\ext,如下图 步骤2&#x…

《最新出炉》系列入门篇-Python+Playwright自动化测试-42-强大的可视化追踪利器Trace Viewer

宏哥微信粉丝群:https://bbs.csdn.net/topics/618423372 有兴趣的可以扫码加入 1.简介 在我们日常执行自动化测试工作的过程中,经常会遇到一些偶发性的bug,但是因为bug是偶发性的,我们不一定每次执行都能复现,所以我…

力扣刷题--747. 至少是其他数字两倍的最大数【简单】

题目描述 给你一个整数数组 nums ,其中总是存在 唯一的 一个最大整数 。 请你找出数组中的最大元素并检查它是否 至少是数组中每个其他数字的两倍 。如果是,则返回 最大元素的下标 ,否则返回 -1 。 示例 1: 输入:n…