当前位置: 首页 > article >正文

P1打卡-使用Pytorch实现mnist手写数字识别

  •   🍨 本文为🔗365天深度学习训练营中的学习记录博客
  • 🍖 原作者:K同学啊

1.导入数据 

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import torchvision

device=torch.device("cuda" if torch.cuda.is_available() else "cpu")
device

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

​​​

2.加载数据

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

3检查数据

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

​​

4.数据可视化

import numpy as np

plt.figure(figsize=(20,5))
for i,imgs in enumerate(imgs[:20]):
    npimg=np.squeeze(imgs.numpy())
    plt.subplot(2,10,i+1)
    plt.imshow(npimg,cmap=plt.cm.binary)
    plt.axis('off')

5.构建模型

import torch.nn.functional as F
num_classes=10

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1=nn.Conv2d(1,32,kernel_size=3)
        self.pool1=nn.MaxPool2d(2)
        self.conv2=nn.Conv2d(32,64,kernel_size=3)
        self.pool2=nn.MaxPool2d(2)

        self.fc1=nn.Linear(1600,64)
        self.fc2=nn.Linear(64,num_classes)
    def forward(self,x):
        x=self.pool1(F.relu(self.conv1(x)))
        x=self.pool2(F.relu(self.conv2(x)))
        x=torch.flatten(x,start_dim=1)
        x=F.relu(self.fc1(x))
        x=self.fc2(x)
        return x
from torchinfo import summary
model=Model().to(device)
summary(model)

6.编译及训练模型

loss_fn=nn.CrossEntropyLoss()
learn_rate=1e-2
opt=torch.optim.SGD(model.parameters(),lr=learn_rate)

def train(dataloader,model,loss_fn,optimizer):
    size=len(dataloader.dataset)
    num_batches=len(dataloader)
    
    train_loss,train_acc=0,0
    for X,y in dataloader:
        X,y=X.to(device),y.to(device)
        pred=model(X)
        loss=loss_fn(pred,y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        train_acc+=(pred.argmax(1)==y).type(torch.float).sum().item()
        train_loss+=loss.item()
    train_acc/=size
    train_loss/=num_batches
    return train_acc,train_loss

def test(dataloader,model,loss_nf):
    size=len(dataloader.dataset)
    num_batches=len(dataloader)
    test_loss,test_acc=0,0
    with torch.no_grad():
        for imgs,target in dataloader:
            imgs,target=imgs.to(device),target.to(device)

            target_pred=model(imgs)
            loss=loss_fn(target_pred,target)
            test_loss+=loss.item()
            test_acc+=(target_pred.argmax(1)==target).type(torch.float).sum().item()
    test_acc/=size
    test_loss/=num_batches
    return test_acc,test_loss

epochs=5
train_loss=[]
train_acc=[]
test_loss=[]
test_acc=[]

for epoch in range(epochs):
    model.train()
    epoch_train_acc,epoch_train_loss=train(train_dl,model,loss_fn,opt)
    model.eval()
    epoch_test_acc,epoch_test_loss=test(test_dl,model,loss_fn)

    train_acc.append(epoch_train_acc)
    train_loss.append(epoch_train_loss)
    test_acc.append(epoch_test_acc)
    test_loss.append(epoch_test_loss)
    template=('Epoch:{:2d},Train Loss:{:.4f},Train Acc:{:.2f}%,Test Loss:{:.4f},Test Acc:{:.2f}%')
    print(template.format(epoch,epoch_train_loss,epoch_train_acc,epoch_test_loss,epoch_test_acc))
print('Finished Training')

​​​

7.结果可视化

import matplotlib.pyplot as plt
#隐藏警告
import warnings
warnings.filterwarnings("ignore")              
plt.rcParams['font.sans-serif']    = ['SimHei'] 
plt.rcParams['axes.unicode_minus'] = False     
plt.rcParams['figure.dpi']         = 100        

epochs_range = range(epochs)

plt.figure(figsize=(12, 3))
plt.subplot(1, 2, 1)

plt.plot(epochs_range, train_acc, label='Training Accuracy')
plt.plot(epochs_range, test_acc, label='Test Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(epochs_range, train_loss, label='Training Loss')
plt.plot(epochs_range, test_loss, label='Test Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

​​​

​​​

总结:

1.torchvision.datasets

  torchvision.datasets是Pytorch自带的一个数据库,我们可以通过代码在线下载数据,这里使用的是torchvision.datasets中的MNIST数据集。

    torchvision.datasets.MNIST(root, train=True, transform=None, target_transform=None, download=False)

参数说明:

  • root (string) :数据地址
  • train (string) :True-训练集,False-测试集
  • download (bool,optional) : 如果为True,从互联网上下载数据集,并把数据集放在root目录下。
  • transform (callable, optional ):这里的参数选择一个你想要的数据转化函数,直接完成数据转化
  • target_transform (callable,optional) :接受目标并对其进行转换的函数/转换

2.torch.utils.data.DataLoader

  torch.utils.data.DataLoader是Pytorch自带的一个数据加载器,结合了数据集和取样器,并且可以提供多个线程处理数据集。

    torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=None, sampler=None, batch_sampler=None, num_workers=0, collate_fn=None, pin_memory=False, drop_last=False, timeout=0, worker_init_fn=None, multiprocessing_context=None, generator=None, *, prefetch_factor=2, persistent_workers=False, pin_memory_device='')

  

参数说明:

  • dataset (string) :加载的数据集
  • batch_size (int,optional) :每批加载的样本大小(默认值:1)
  • shuffle (bool,optional) : 如果为True,每个epoch重新排列数据。
  • sampler (Sampler or iterable, optional) : 定义从数据集中抽取样本的策略。 可以是任何实现了 __len__ 的 Iterable。 如果指定,则不得指定 shuffle 。
  • batch_sampler (Sampler or iterable, optional) : 类似于sampler,但一次返回一批索引。与 batch_size、shuffle、sampler 和 drop_last 互斥。
  • num_workers (int,optional) : 用于数据加载的子进程数。 0 表示数据将在主进程中加载(默认值:0)。
  • pin_memory (bool,optional) : 如果为 True,数据加载器将在返回之前将张量复制到设备/CUDA 固定内存中。 如果数据元素是自定义类型,或者collate_fn返回一个自定义类型的批次。
  • drop_last (bool,optional) : 如果数据集大小不能被批次大小整除,则设置为 True 以删除最后一个不完整的批次。 如果 False 并且数据集的大小不能被批大小整除,则最后一批将保留。 (默认值:False)
  • timeout (numeric,optional) : 设置数据读取的超时时间 , 超过这个时间还没读取到数据的话就会报错。(默认值:0)
  • worker_init_fn (callable,optional) : 如果不是 None,这将在步长之后和数据加载之前在每个工作子进程上调用,并使用工作 id([0,num_workers - 1] 中的一个 int)的顺序逐个导入。(默认:None)

3.optimizer.zero_grad()

   函数会遍历模型的所有参数,通过内置方法截断反向传播的梯度流,再将每个参数的梯度值设为0,即上一次的梯度记录被清空。

4.loss.backward()

      PyTorch的反向传播(即tensor.backward())是通过autograd包来实现的,autograd包会根据tensor进行过的数学运算来自动计算其对应的梯度。

具体来说,torch.tensor是autograd包的基础类,如果你设置tensor的requires_grads为True,就会开始跟踪这个tensor上面的所有运算,如果你做完运算后使用tensor.backward(),所有的梯度就会自动运算,tensor的梯度将会累加到它的.grad属性里面去。

更具体地说,损失函数loss是由模型的所有权重w经过一系列运算得到的,若某个w的requires_grads为True,则w的所有上层参数(后面层的权重w)的.grad_fn属性中就保存了对应的运算,然后在使用loss.backward()后,会一层层的反向传播计算每个w的梯度值,并保存到该w的.grad属性中。

如果没有进行tensor.backward()的话,梯度值将会是None,因此loss.backward()要写在optimizer.step()之前。

5.optimizer.step()

   step()函数的作用是执行一次优化步骤,通过梯度下降法来更新参数的值。因为梯度下降是基于梯度的,所以在执行optimizer.step()函数前应先执行loss.backward()函数来计算梯度。

   注意:optimizer只负责通过梯度下降进行优化,而不负责产生梯度,梯度是tensor.backward()方法产生的


http://www.kler.cn/a/390186.html

相关文章:

  • 前端神经网络入门(三):深度学习与机器学习的关系、区别及核心理论支撑 - 以Brain.js示例
  • 俏美韵从心出发,与女性一道为健康生活贡献力量
  • C/C++精品项目之图床共享云存储(3):网络缓冲区类和main
  • Scala入门基础(17.1)Set集习题
  • AI 扩展开发者思维方式:以 SQL 查询优化为例
  • Xcode 16 使用 pod 命令报错解决方案
  • 解锁高效直播新体验:第三代 AI 手机自动直播工具,开启直播高效运作新时代!
  • 网页web无插件播放器EasyPlayer.js点播播放器遇到视频地址播放不了的现象及措施
  • 设计模式(主要的五种)
  • 软件设计师 - 层次化存储
  • 大数据-216 数据挖掘 机器学习理论 - KMeans 基于轮廓系数来选择 n_clusters
  • 鸿蒙UI开发——小图标的使用
  • 使用API有效率地管理Dynadot域名,列表形式查看账户whois联系人信息
  • Dubbo负载均衡
  • Baget 私有化nuget
  • SpringBoot助力企业资产优化
  • Matlab实现鹈鹕优化算法(POA)求解路径规划问题
  • [Docker#4] 镜像仓库 | 部分常用命令
  • AI生活之我用AI处理Excel表格
  • go函数传值是值传递?还是引用传递?slice案例加图解
  • 数据分析-44-时间序列预测之深度学习方法TCN
  • Autosar CP Network Management模块规范导读
  • C#中 layout的用法
  • 易泊车牌识别相机:4S 店的智能之选
  • Spring Boot与Spring Data JPA:简化数据库操作
  • Python毕业设计选题:基于django+vue的医院挂号系统设计与实现