根据迪哥视频的pytorch Mnist数据集分类(DNN)网络

根据迪哥视频的pytorch Mnist数据集分类(DNN)网络

Mnist数据集分类任务

  • 另外关于测试集的问题,迪哥写的过于繁琐,提供的网址用requirest下载不了,直接暴力搜索用网盘下载到文件夹

  • 直接手打一个data_path,然后用gzip打开

  • gzip.open()不能接受字符串路径,需要先通过path转化后在解压

  • with gzip.open((data_path).as_posix(), “rb”) as f:

    • ((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding=“latin-1”) #这里变量最后一个_必须要加
#加载必要的库

from pathlib import Path
import requests
import pickle
import gzip
%matplotlib inline

# 创建一个存储mnist数据集的路径
data_path = Path.cwd() / 'data'/ 'MNIST'/ 'mnist.pkl.gz'
print(data_path)

# gzip.open()不能接受字符串路径,需要先通过path转化后在解压
# 由于用requests抓取网络文件太慢,直接网盘下载mnist,省略了抓取步骤
with gzip.open((data_path).as_posix(), "rb") as f:
    ((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding="latin-1") #这里变量最后一个_必须要加
print("ok")
# 用imshow可以直接显示28×28组成的数字

from matplotlib import pyplot
import numpy as np

pyplot.imshow(x_train[0].reshape((28, 28)), cmap="gray") 
print(x_train.shape)
# 构建模型

import torch
# 用一个map(),将所有数据迭代为矩阵格式
x_train, y_train, x_valid, y_valid = map(
    torch.tensor, (x_train, y_train, x_valid, y_valid)
)
print(x_train, y_train)
print(x_train.shape)
print(x_train.min(), y_train.max())
import torch.nn.functional as F

bs = 64
xb = x_train[0:bs]
yb = y_train[0:bs]
weights = torch.randn([784, 10], dtype=torch.float, requires_grad=True)
bias = torch.zeros(10, requires_grad=True)

# 损失值计算采用交叉墒,注意此处声明该函数不用预先设参数,可以后面调用是再设
loss_func = F.cross_entropy 

# 定义向前传播计算函数
def model(xb):
    return xb.mm(weights) + bias

print(loss_func(model(xb), yb)) 在这里插入代码片

创建一个model来简化代码

  • 必须继承nn.Module且在其构造函数中需调用nn.Module的构造函数
  • 无需写反向传播函数,nn.Module能够利用autograd自动实现方向传播
  • Module中的可学习参数可以通过named_parameters()或者parameters()返回迭代器
from torch import nn

class Mnist_NN(nn.Module): # 创建一个模型类,父类为nn.Module
    def __init__(self):
        # 在构造函数中就要明确每一层
        super().__init__() # 声明继承父类的构造函数
        self.hidden1 = nn.Linear(784, 128) # nn.Linear用来设置全连接层
        self.hidden2 = nn.Linear(128, 64)
        self.out = nn.Linear(64, 10)
        
    def forward(self, x):
        x = F.relu(self.hidden1(x))
        x = F.relu(self.hidden2(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来简化

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

train_ds = TensorDataset(x_train, y_train) #Dataset对tensor进行打包
train_dl = DataLoader(train_ds, batch_size=bs, shuffle=True) #用DataLoad读取数据shuffle表示每次batch都要打乱数据

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)
    )
from torch import optim # 导入优化器模块
'''
创建一个返回模型和优化器的方法,虽然不理解有什么用?
不能直接调用模型和优化器?
'''
def get_model():
    model = Mnist_NN()
    return model, optim.SGD(model.parameters(), lr=0.001) # 采用SGD优化器,优化对象为model的权重参数
def loss_batch(model, loss_func, xb, yb, opt=None): # 计算损失
    loss = loss_func(model(xb), yb) # 调用之前定义的交叉墒获得损失值
    if opt is not None:
        loss.backward() # 根据损失值求导反向传播
        opt.step() # 表示用opt优化器来更新权重参数
        opt.zero_grad() # 每次更新梯度清零
    
    return loss.item(), len(xb) # loss数据类型是Variable,loss.item()直接获取对应的python数据类型,同时获取对应数据个数
  • 一般在训练模型时加上model.train(),这样会正常使用Batch Normalization和Dropout
  • 测试的时候一般选择model.eval(),这样就不会使用Batch Normalization和Dropout
import numpy as np

# 将所有过程都放到一个函数中进行计算
def fit(steps, model, loss_func, opt, train_dl, valid_dl):
    for step in range(steps):
        model.train() # 训练模型时加上model.train(),作用是启用Batch Normalization和Dropout
        for xb, yb in train_dl:
            loss_batch(model, loss_func, xb, yb, opt)
            
        model.eval() # 测试的时候选择model.eval()
        with torch.no_grad(): # 在该模块下,所有计算得出的tensor的requires_grad都自动设置为False,因为只在验证集上求损失值,不用求导
            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)

运行结果如下

当前step:0 验证集损失:2.2804175106048583
当前step:1 验证集损失:2.247503145980835
当前step:2 验证集损失:2.201047773361206
当前step:3 验证集损失:2.132051001358032
当前step:4 验证集损失:2.0252137477874754
当前step:5 验证集损失:1.8659272445678712
当前step:6 验证集损失:1.6515238025665284
当前step:7 验证集损失:1.4080945442199706
当前step:8 验证集损失:1.1849663320541381
当前step:9 验证集损失:1.0117872383117676
当前step:10 验证集损失:0.8840345878601075
当前step:11 验证集损失:0.7874993204116821
当前step:12 验证集损失:0.7118284031867981
当前step:13 验证集损失:0.6517571626663208
当前step:14 验证集损失:0.6032021932601929
当前step:15 验证集损失:0.5631895722389221
当前step:16 验证集损失:0.530268014717102
当前step:17 验证集损失:0.5030230499267578
当前step:18 验证集损失:0.4805735528945923
当前step:19 验证集损失:0.4615746584415436
当前step:20 验证集损失:0.4459013089179993
当前step:21 验证集损失:0.4309808259963989
当前step:22 验证集损失:0.4189828608989716
当前step:23 验证集损失:0.40864138970375063
当前step:24 验证集损失:0.3988726670503616

总结一下

  • 不断调试完成模型
  • 之前报错TypeError: unsupported operand type(s) for /: ‘builtin_function_or_method’ and ‘int’
  • 因为loss.item没加()
  • 补充下fit参数含义
    • steps:要循环多少次,每个批次都是随机抽取
    • model:选用的哪个模型进行训练,这里是采用get_model然后调用Mnist_NN这个类
    • loss_func:计算损失函数的方法,这里采用定义好的F.cross_entropy
    • opt:反向传播优化器,这里用的SGD
    • train_dl:训练集
    • valid_dl:验证集
  • 总体嵌套函数较多,不容易理解,注意这里的loss_func和opt都是作为loss_batch中的参数起作用
  • loss_batch还包含了所有求导反向传播,更新参数及梯度清零操作
  • 不确定的地方,猜测 loss_batch中利用的model()函数和fit中获取的model不是同一个
  • 前一个model是定义的向前传播计算,只包括wx + b,后面的model是一个类实例,包含所有w层和relu层,不明白前一个model函数在loss_batch中的作用
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值