深度学习(12)--Mnist分类任务

一.Mnist分类任务流程详解

1.1.引入数据集

Mnist数据集是官方的数据集,比较特殊,可以直接通过%matplotlib inline自动下载,博主此处已经完成下载,从本地文件中引入数据集。

设置数据路径

from pathlib import Path

# 设置数据路径
# PATH = Path("data/minst")
DATA_PATH = Path("data")
PATH = DATA_PATH / "mnist"

# PATH.mkdir(parents=True, exist_ok=True)  # 父目录不存在时创建父目录

'''
parents:如果父目录不存在,是否创建父目录。
exist_ok:只有在目录不存在时创建目录,目录已存在时不会抛出异常。
'''

读取数据

import pickle
import gzip

# 读取数据
'''
gzip.open的作用是解压gzip文件
with gzip.open(PATH.as_posix(), "rb") as f:
    ((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding="latin-1")
'''
# rb表示以二进制格式打开一个文件用于只读
# 打开PATH路径的文件用以接下来的操作
# 保存数据的文件类型为pickle,所以用pickle.load打开文件,文件此处设置的别名为f
with open(PATH.as_posix(), "rb") as f:
    ((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding="latin-1")

'''
as.posix()的作用:
#返回使用斜杠(/)分割路径的字符串
#将所有连续的正斜杠、反斜杠,统一修改为单个正斜杠
#相对路径 './' 替换为空,'../' 则保持不变。
'''

测试引入数据集是否成功

from matplotlib import pyplot
import numpy as np

# 测试数据集是否导入成功
pyplot.imshow(x_train[0].reshape((28, 28)), cmap="gray")
print(x_train.shape)

1.2.数据类型转换

数据需要转换成tensor类型才能参与后续建模训练

import torch

# 通过map映射,将x_train等数据全都转为torch.tensor类型。tensor类型才能参与后续建模训练
x_train, y_train, x_valid, y_valid = map(
    torch.tensor, (x_train, y_train, x_valid, y_valid)
)

测试数据类型是否转换成功

n, c = x_train.shape
x_train, x_train.shape, y_train.min(), y_train.max()
print(x_train, y_train)
print(x_train.shape)
print(y_train.min(), y_train.max())

数据均为tensor类型,转换成功

1.3.设置损失函数

import torch.nn.functional as F

# 设置损失函数,此处使用的损失函数为交叉熵
loss_func = F.cross_entropy 

测试损失函数

手动设置初始权重和偏置值进行测试,真实情况下系统会自动帮我们初始化

bs = 64
xb = x_train[0:bs]  # a mini-batch from x ,xb是x_train中0~64项的数
yb = y_train[0:bs]

# 实际操作中模型会自动定义权重参数,不用我们手动设置
# 因为输入数据是784x1个像素点,而最后得到的是十个类别,所以权重矩阵的大小为784x10。
weights = torch.randn([784, 10], dtype = torch.float,  requires_grad = True) 
bs = 64
# bias矩阵的大小取决于最后的类别数量,此处的bias矩阵为10x1
bias = torch.zeros(10, requires_grad=True)

def model(xb):
    return xb.mm(weights) + bias  # .mm()是矩阵相乘 .mul()则是对应位相乘

# 损失函数是用来度量模型的预测值f(x)与真实值Y的差异程度的运算函数,此处model(xb)得到的是经过权重计算的预测值,yb是真实值。给损失函数传入的参数即为预测值和真实值。
print(loss_func(model(xb), yb))

1.4.神经网络构造 

此处所选用的是传统神经网络完成Minist分类任务

from torch import nn

# 创建一个模型类,注意一定要继承于nn.Module(取决于你要创建的网络类型)
class Mnist_NN(nn.Module):
    def __init__(self):
        # 调用父类的构造函数
        super().__init__()
        # 创建两个隐层 由784->128->256->10
        self.hidden1 = nn.Linear(784, 128)
        self.hidden2 = nn.Linear(128, 256)
        # 创建输出层,由256->10,即最后输出十个类别
        self.out  = nn.Linear(256, 10)
        self.dropout = nn.Dropout(0.5)

    # torch框架需要自己定义前向传播,反向传播由框架自己实现
    # 传入的x是一个batch x 特征值
    def forward(self, x):
        # x经过第一个隐层
        x = F.relu(self.hidden1(x))
        # x经过dropout层
        x = self.dropout(x)
        # x经过第二个隐藏
        x = F.relu(self.hidden2(x))
        # x经过dropout层
        x = self.dropout(x)
        # x经过输出层
        x = self.out(x)
        return x
        

测试构造的神经网络

net = Mnist_NN()
print(net)

查看网络中构建好的权重和偏置项 

for name, parameter in net.named_parameters():
    print(name, parameter,parameter.size())
 

1.5.使用TensorDataset和DataLoader简化数据 

from torch.utils.data import TensorDataset
from torch.utils.data import DataLoader

# TensorDataset获取数据,再由DataLoader打包数据传给GPU(包的大小位batch_size)
# 训练集一般打乱顺序,验证集不打乱顺序
train_ds = TensorDataset(x_train, y_train)
train_dl = DataLoader(train_ds, batch_size=bs, shuffle=True)

valid_ds = TensorDataset(x_valid, y_valid)
valid_dl = DataLoader(valid_ds, batch_size=bs * 2)

def get_data(train_ds, valid_ds, bs):
    return (
        DataLoader(train_ds, batch_size=bs, shuffle=True),
        DataLoader(valid_ds, batch_size=bs * 2),
    )

1.6.模型训练

优化器设置

from torch import optim
def get_model():
    model = Mnist_NN() # 使用先前创建的类构造一个网络
    return model, optim.SGD(model.parameters(), lr=0.001) 
    # 返回值为模型和优化器
 # 优化器的设置,optim.SGD(),参数分别为:要优化的参数、学习率

def loss_batch(model, loss_func, xb, yb, opt=None):
    # 计算损失,参数为预测值和真实值
    loss = loss_func(model.forward(xb), yb)  # 预测值由定义的前向传播过程计算处

    # 如果存在优化器
    if opt is not None: 
        loss.backward()  # 反向传播,算出更新的权重参数
        opt.step()  # 执行backward()计算出的权重参数的更新
        opt.zero_grad()  # torch会进行迭代的累加,通过zero_grad()将之前的梯度清空(不同的迭代之间应当是没有关系的)

    return loss.item(), len(xb)

常用优化器:

  • 随机梯度下降(SGD, stochastic gradient descent)
  • SGDM(加入了一阶动量)
  • AdaGrad(加入了二阶动量)
  • RMSProp
  • Adam

模型训练

import numpy as np

#epoch和batch的关系,
#eg:有10000个数据,batch=100,则一个1epoch需要训练100个batch(1一个epoch就是训练整个数据一次)
# 定义训练函数,传入的参数分别为:迭代的次数、模型、损失函数、优化器、训练集、验证集
def fit(steps, model, loss_func, opt, train_dl, valid_dl):
    for step in range(steps):
        # 训练模式:
        model.train()  
        for xb, yb in train_dl:
            loss_batch(model, loss_func, xb, yb, opt)  # 得到由loss_batch更新的权重值
        # 验证模式:
        model.eval()   
        with torch.no_grad():  # 没有梯度,即不更新权重参数
            # zip将两个矩阵配对,例如两个一维矩阵配对成一个二维矩阵,下述情况中即为一个losses对应一个nums -> [(losses,nums)]。zip*是解包操作,即将二维矩阵又拆分成一维矩阵,并返回拆分得到的一维矩阵。
            losses, nums = zip(
                *[loss_batch(model, loss_func, xb, yb) for xb, yb in valid_dl]
            )
        val_loss = np.sum(np.multiply(losses, nums)) / np.sum(nums)  # 计算平均损失:对应的损失值和样本数相乘的总和 / 总样本数
        print('当前step:'+str(step), '验证集损失:'+str(val_loss))

二.完整代码 

from pathlib import Path
import pickle
import gzip

from matplotlib import pyplot
import numpy as np

import torch

import torch.nn.functional as F

from torch import nn

from torch.utils.data import TensorDataset
from torch.utils.data import DataLoader

from torch import optim

import numpy as np


# 设置数据路径
DATA_PATH = Path("data")
PATH = DATA_PATH / "mnist.pkl"

# PATH.mkdir(parents=True, exist_ok=True)

'''
parents:如果父目录不存在,是否创建父目录。
exist_ok:只有在目录不存在时创建目录,目录已存在时不会抛出异常。
'''

# 读取数据
'''
gzip.open的作用是解压gzip文件
with gzip.open(PATH.as_posix(), "rb") as f:
    ((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding="latin-1")
'''
# rb表示以二进制格式打开一个文件用于只读
# 打开PATH路径的文件用以接下来的操作
# 保存数据的文件类型为pickle,所以用pickle.load打开文件,文件此处设置的别名为f
with open(PATH.as_posix(), "rb") as f:
    ((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding="latin-1")

'''
as.posix()的作用:
#返回使用斜杠(/)分割路径的字符串
#将所有连续的正斜杠、反斜杠,统一修改为单个正斜杠
#相对路径 './' 替换为空,'../' 则保持不变。
'''

'''
# 测试数据集是否导入成功
pyplot.imshow(x_train[0].reshape((28, 28)), cmap="gray")
print(x_train.shape)
'''

# 数据类型转换为torch

# 通过map映射,将x_train等数据全都转为torch.tensor类型。tensor类型才能参与后续建模训练
x_train, y_train, x_valid, y_valid = map(
    torch.tensor, (x_train, y_train, x_valid, y_valid)
)



# 测试数据类型是否转换成功
'''
n, c = x_train.shape
x_train, x_train.shape, y_train.min(), y_train.max()
print(x_train, y_train)
print(x_train.shape)
print(y_train.min(), y_train.max())
'''

# 设置损失函数
loss_func = F.cross_entropy


bs = 64
xb = x_train[0:bs]  # a mini-batch from x ,xb是x_train中0~64项的数
yb = y_train[0:bs]

''' 
# 手动初始化进行测试

# 实际操作中模型会自动定义权重参数,不用我们手动设置
# 因为输入数据是784x1个像素点,而最后得到的是十个类别,所以权重矩阵的大小为784x10。
weights = torch.randn([784, 10], dtype = torch.float,  requires_grad = True)
bs = 64
# bias矩阵的大小取决于最后的类别数量,此处的bias矩阵为10x1
bias = torch.zeros(10, requires_grad=True)

def model(xb):
    return xb.mm(weights) + bias  # .mm()是矩阵相乘 .mul()则是对应位相乘

# 损失函数是用来度量模型的预测值f(x)与真实值Y的差异程度的运算函数,此处model(xb)得到的是经过权重计算的预测值,yb是真实值。给损失函数传入的参数即为预测值和真实值。
print(loss_func(model(xb), yb))
'''

# 创建一个模型类,注意一定要继承于nn.Module(取决于你要创建的网络类型)
class Mnist_NN(nn.Module):
    def __init__(self):
        # 调用父类的构造函数
        super().__init__()
        # 创建两个隐层 由784->128->256->10
        self.hidden1 = nn.Linear(784, 128)
        self.hidden2 = nn.Linear(128, 256)
        # 创建输出层,由256->10,即最后输出十个类别
        self.out = nn.Linear(256, 10)
        self.dropout = nn.Dropout(0.5)

    # torch框架需要自己定义前向传播,反向传播由框架自己实现
    # 传入的x是一个batch x 特征值
    def forward(self, x):
        # x经过第一个隐层
        x = F.relu(self.hidden1(x))
        # x经过dropout层
        x = self.dropout(x)
        # x经过第二个隐藏
        x = F.relu(self.hidden2(x))
        # x经过dropout层
        x = self.dropout(x)
        # x经过输出层
        x = self.out(x)
        return x


'''
# 测试构造的网络模型
net = Mnist_NN()
print(net)

打印权重和偏置项
for name, parameter in net.named_parameters():
    print(name, parameter,parameter.size())
'''

# TensorDataset获取数据,再由DataLoader打包数据传给GPU
# 训练集一般打乱顺序,验证集不打乱顺序
train_ds = TensorDataset(x_train, y_train)
train_dl = DataLoader(train_ds, batch_size=bs, shuffle=True)

valid_ds = TensorDataset(x_valid, y_valid)
valid_dl = DataLoader(valid_ds, batch_size=bs * 2)

def get_data(train_ds, valid_ds, bs):
    return (
        DataLoader(train_ds, batch_size=bs, shuffle=True),
        DataLoader(valid_ds, batch_size=bs * 2),
    )


# 优化器设置
def get_model():
    model = Mnist_NN()
    return model, optim.SGD(model.parameters(), lr=0.001)
    # 优化器的设置,optim.SGD(),参数分别为:要优化的参数、学习率

def loss_batch(model, loss_func, xb, yb, opt=None):
    # 计算损失,参数为预测值和真实值
    loss = loss_func(model.forward(xb), yb)  # 预测值由定义的前向传播过程计算处

    # 如果存在优化器
    if opt is not None:
        loss.backward()  # 反向传播,算出更新的权重参数
        opt.step()  # 执行backward()计算出的权重参数的更新
        opt.zero_grad()  # torch会进行迭代的累加,通过zero_grad()将之前的梯度清空(不同的迭代之间应当是没有关系的)

    return loss.item(), len(xb)

# 模型训练
# epoch和batch的关系,
# eg:有10000个数据,batch=100,则一个1epoch需要训练100个batch(1一个epoch就是训练整个数据一次)
# 定义训练函数,传入的参数分别为:迭代的次数、模型、损失函数、优化器、训练集、验证集
def fit(steps, model, loss_func, opt, train_dl, valid_dl):
    for step in range(steps):
        # 训练模式:
        model.train()
        for xb, yb in train_dl:
            loss_batch(model, loss_func, xb, yb, opt)  # 得到由loss_batch更新的权重值
        # 验证模式:
        model.eval()
        with torch.no_grad():  # 没有梯度,即不更新权重参数
            # zip将两个矩阵配对,例如两个一维矩阵配对成一个二维矩阵,下述情况中即为一个losses对应一个nums -> [(losses,nums)]。zip*是解包操作,即将二维矩阵又拆分成一维矩阵,并返回拆分得到的一维矩阵。
            losses, nums = zip(
                *[loss_batch(model, loss_func, xb, yb) for xb, yb in valid_dl]
            )
        val_loss = np.sum(np.multiply(losses, nums)) / np.sum(nums)  # 计算平均损失:对应的损失值和样本数相乘的总和 / 总样本数
        print('当前step:'+str(step), '验证集损失:'+str(val_loss))

# 输出
train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
model, opt = get_model()
fit(25, model, loss_func, opt, train_dl, valid_dl)

# 准确率的计算
correct = 0
total = 0
for xb,yb in valid_dl:
    outputs = model(xb)
    _, predicted = torch.max(outputs.data,1)  # 返回最大的值和对应的列索引(列索引在此处就是对应的类别)    (, 0)则返回行索引
    total += yb.size(0)  # yb的样本数
    correct += (predicted == yb).sum().item( ) # .sum()返回验证正确了的样本数,item()从tensor数据类型中取值,方便后续的画图等(tensor数据类型不好画图)

    print('Accuracy of the network on the 10000 test image: %d %%' %(100*correct/total))

三.输出结果

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C# Onnx GroundingDINO 开放世界目标检测

目录 介绍 效果 模型信息 项目 代码 下载 介绍 地址:https://github.com/IDEA-Research/GroundingDINO Official implementation of the paper "Grounding DINO: Marrying DINO with Grounded Pre-Training for Open-Set Object Detection" 效果 …

RT-Thread 28. Nano实现MSH及CPU利用率显示

Nano版源码官网下载 https://github.com/RT-Thread/rtthread-nano/archive/refs/heads/master.zip 1. 代码结构 2.代码 //main.c #include "gd32f3x0.h" #include <rthw.h> #include <rtthread.h> #include "cpuusage.h"#define delay_ms(x…

树型结构构建,模糊查询,过滤

一、前言 1、最近在做甘特图&#xff0c;有些需求和树型结构要求很大&#xff0c;看的是 pingCode&#xff0c;有搜索 2、还有抽取一部分树型结构的&#xff0c;如下是抽取上面的结构类型为需求的&#xff0c;重新组成树型 二、构建多颗树型结构 1、某些业务下&#xff0c;从…

【Nginx】Ubuntu如何安装使用Nginx反向代理?

文章目录 使用Nginx反向代理2个web接口服务步骤 1&#xff1a;安装 Nginx步骤 2&#xff1a;启动 Nginx 服务步骤 3&#xff1a;配置 Nginx步骤 4&#xff1a;启用配置步骤 5&#xff1a;检查配置步骤 6&#xff1a;重启 Nginx步骤 7&#xff1a;访问网站 proxy_set_header 含义…

vue-3d-model

vue-3d-model - npm GitHub - hujiulong/vue-3d-model: &#x1f4f7; vue.js 3D model viewer component 通过该插件降低Threejs的使用难度 vue项目加载三维模型&#xff0c;我把模型放在了服务器的tomcat里面&#xff0c;需要对tomcat的fbx项目文件夹设置跨域&#xff0c;如…

同城外卖跑腿app开发:重新定义城市生活

随着科技的发展和人们生活节奏的加快&#xff0c;同城外卖跑腿app应运而生&#xff0c;成为现代城市生活中的重要组成部分。本文将探讨同城外卖跑腿app开发的意义、市场需求、功能特点以及未来的发展趋势。 一、同城外卖跑腿app开发的意义 同城外卖跑腿app作为一种便捷的生活…

如何看待“Linux 中国” 开源社区,停止运营?

如何看待“Linux 中国” 开源社区&#xff0c;停止运营&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「Linux的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家…

专业120+总分400+宁波大学912信号与系统考研经验电子信息通信集成电路光电

今年考研顺利上岸&#xff0c;专业课912信号与系统120&#xff0c;总分400&#xff0c;被宁波大学录取&#xff0c;回望这一年的复习有过迷茫和犹豫&#xff0c;也有过坚持和坚强&#xff0c;总结一下自己的复习得失&#xff0c;希望对大家复习有所帮助。专业课&#xff1a; 前…

论文阅读:Learning Lens Blur Fields

这篇文章是对镜头模糊场进行表征学习的研究&#xff0c;镜头的模糊场也就是镜头的 PSF 分布&#xff0c;镜头的 PSF 与物距&#xff0c;焦距&#xff0c;光学系统本身的像差都有关系&#xff0c;实际的 PSF 分布是非常复杂而且数量也很多&#xff0c;这篇文章提出用一个神经网络…

Unity_ShaderGraph示例项目启动

Unity_ShaderGraph示例项目启动 大前提不变:URP模板,Unity2023.1.19使用 Shader Graph - Unity 手册Shader Graph 是一个工具,能够让您直观地构建着色器。您可以在图形框架中创建并连接节点,而不必手写代码。Shader Graph 提供了能反映所作更改的即时反馈,对于不熟悉着色…

自然语言处理(NLP)—— Dialogflow ES聊天机器人

1. 背景介绍 这个实验室的目标是让你了解并使用Google的Dialogflow服务。Dialogflow是一个可以让你创建聊天机器人的服务&#xff0c;这个过程不需要或者只需要很少的编程技能。 1.1 账号的创建 为了完成这个实验室&#xff0c;你需要在以下网站上创建账号&#xff1a…

在 Elastic Agent 中为 Logstash 输出配置 SSL/TLS

要将数据从 Elastic Agent 安全地发送到 Logstash&#xff0c;你需要配置传输层安全性 (TLS)。 使用 TLS 可确保你的 Elastic Agent 将加密数据发送到受信任的 Logstash 服务器&#xff0c;并且你的 Logstash 服务器从受信任的 Elastic Agent 客户端接收数据。 先决条件 确保你…

RK3588 Android 12 Framework修改记录(八)Settings Ethernet以太网 多网卡设置静态IP

https://blog.csdn.net/lishu_/article/details/114391764 如何优雅的实现Android Ethernet 以太网的开启与关闭 RK3588 Android 12 Framework修改记录&#xff08;八&#xff09;Settings Ethernet以太网 多网卡设置静态IP - 知乎 Android 7.1 以太网反射 EthernetManager 配置…

LabVIEW CVT离合器性能测试

介绍了CVT&#xff08;连续变速器&#xff09;离合器的性能测试的一个应用。完成了一个基于LabVIEW软件平台开发的CVT离合器检测与控制系统&#xff0c;通过高效、准确的测试方法&#xff0c;确保离合器性能达到最优。 系统采用先进的硬件配合LabVIEW软件&#xff0c;实现了对…

【Vue3】源码探索之旅:compiler-core之parseChildren函数(二)

简言 parseChildren函数是在baseParse函数中作为createRoot函数的子节点参数传入的&#xff0c;今天来探索下parseChildren函数。 parseChildren在 compiler-core/src/parse.ts文件内。 parseChildren 这个函数就是用来解析模板字符串内容的 &#xff0c;里面有个while循环…

使用输出事件激活Simulink块

什么是输出事件? 输出事件是发生在Stateflow图表中,但在图表外的Simulink块中可见的事件。这种类型的事件允许图表将图表中发生的事件通知模型中的其他块。 您可以使用输出事件来激活同一模型中的其他块。您可以在图表中定义多个输出事件,其中每个输出事件映射到一个输出端…

Quick BI中lod函数之lod_include

一、lod函数简介 LOD函数的全称是详细级别表达式&#xff08;Level Of Detail Expressisons&#xff09;。它主要是为了克服一些表达式之间计算颗粒度不一致的问题。比如&#xff0c;要计算第一季度各月销售收入占比&#xff0c;这里分子计算颗粒度为’月’&#xff0c;但是分…

聊聊ClickHouse MergeTree引擎的固定/自适应索引粒度

前言 我们在刚开始学习ClickHouse的MergeTree引擎时&#xff0c;就会发现建表语句的末尾总会有SETTINGS index_granularity 8192这句话&#xff08;其实不写也可以&#xff09;&#xff0c;表示索引粒度为8192。在每个data part中&#xff0c;索引粒度参数的含义有二&#xf…

pytorch 利用Tensorboar记录训练过程loss变化

文章目录 1. LossHistory日志类定义2. LossHistory类的使用2.1 实例化LossHistory2.2 记录每个epoch的loss2.3 训练结束close掉SummaryWriter 3. 利用Tensorboard 可视化3.1 显示可视化效果 参考 利用Tensorboard记录训练过程中每个epoch的训练loss以及验证loss&#xff0c;便于…

布隆过滤器的概述和使用

1 布隆过滤器概述 1.1 概述 布隆过滤器&#xff08;Bloom Filter&#xff09;是1970年由布隆提出的。它实际上是由一个很长的二进制向量&#xff08;数组&#xff09;和一系列随机映射函数&#xff08;hash函数&#xff09;组成&#xff0c;它不存放数据的明细内容&#xff0…