初学pytorch之MNIST数据集


1.加载必要的库

代码如下:

import torch
import torch.nn as nn   # nn 作为一个代号
import torch.nn.functional as F    # F 也作为一个代号
import torch.optim as optim     #导入优化器optim,比如梯度下降法
from torchvision import datasets,transforms     #datasets,transforms导入进来

2.定义超参数

参数:模型 f ( x , θ ) f(x,\theta) f(x,θ)中的 θ \theta θ称为模型的参数,可以通过训练得到的参数。
超参数:在开始学习过程之前设置值的参数,而不是通过训练得到的参数数据。

#2.定义超参数
BATCH_SIZE = 16   #每批处理的数据,要分开进行处理
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")    #是否用GPU还是CPU训练,
#有GPU用GPU训练,没有的话用CPU来训练
EPOCHS = 10     #设置训练数据集的轮次,比如60000次训练10轮可以得到600000张图片

3.构建transforms,主要对图像进行变换

#3.构建pipeline,其实和transforms是一个意思
pipeline = transforms.Compose([
    transforms.ToTensor(),     #将图片转化为tensor(张量(也就是多维数组))
    transforms.Normalize((0.1307,),(0.3081,))     #将图片正则化,降低模型复杂度
])

4.下载、加载数据集

#4.下载加载数据
from torch.utils.data import DataLoader     #导入数据

#下载数据集
train_set = datasets.MNIST("data",train=True,download=True,transform=pipeline)        #用datasets下载数据集

test_set = datasets.MNIST("data",train=False,download=True,transform=pipeline)

#加载数据
train_loader = DataLoader(train_set,batch_size=BATCH_SIZE,shuffle=True)#shuffle打乱,提高精度
test_loader = DataLoader(test_set,batch_size=BATCH_SIZE,shuffle=True)

5.构建网络模型

此处构建的卷积结构为:
输入 → \rightarrow 卷积层1 → \rightarrow 激活层1 → \rightarrow 池化层 → \rightarrow 卷积层2 → \rightarrow 激活层2 → \rightarrow 全连接层1 → \rightarrow 激活层3 → \rightarrow 全连接层2 → \rightarrow 输出

#5.构建网络模型
class Digit(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1,10,5)   #卷积层1,1:代表灰度图片的通道,10:输出通道, 5:kernel卷积核
        self.conv2 = nn.Conv2d(10,20,3)  #卷积层2,10:输入通道,20:输出通道, 3:kernel卷积核
        self.fc1 = nn.Linear(20*10*10,500)   #全连接层,20*10*10:输入通道,500:输出通道
        self.fc2 = nn.Linear(500,10)    #全连接层,500:输入通道,10:输出通道
        
    def forward(self,x):   #前向传播算法
        input_size = x.size(0)   #batch_size *1 *28 *28  1:通道数 28*28 像素数
        x = self.conv1(x)    #卷积层:输入:batch*1*28*28,输出:batch*10*24*24 输出通道为10,(28-5+1=24)
        x = F.relu(x)         #激活层,relu函数 输出:batch*10*24*24
        x = F.max_pool2d(x,2,2) #池化层,输入:batch*10*24*24 输出:batch*10*12*12 进行减半
        
        x = self.conv2(x)    #输入:batch*10*12*12 输出:batch*20*10*10   输出通道为20,(12-3+1=10)和前面一样
        x = F.relu(x)     #激活层,relu函数 输出:batch*20*10*10
        
        x = x.view(input_size,-1)    #拉平flatten,-1:自动计算维度,其实就是2000,20*10*10=2000
        
        x = self.fc1(x)   #全连接层,输入:batch*2000 输出:batch*500
        x = F.relu(x)    #激活层是保持shape不变
        
        x = self.fc2(x)   #全连接层,输入:batch*500 输出:batch*10
        
        output = F.log_softmax(x, dim=1)     #计算分类后,每个数字的概率值
        
        return output
        

6.定义优化器

Adam优化器:
Adam的英文全称为:Adaptive Moment Estimation,它是利用梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率。
下为Adam算法的更新公式:

梯度下降法的参数更新公式为:
θ t + 1 = θ t − η ∗ ∇ J ( θ t ) \theta_{t+1}=\theta_t-\eta * \nabla J(\theta_t) θt+1=θtηJ(θt)
其中 η \eta η是学习率, θ t \theta_t θt为第t轮的参数, J ( θ t ) J(\theta_t) J(θt)为损失函数, ∇ J ( θ t ) \nabla J(\theta_t) J(θt)为梯度。为了简便,令 g t = ∇ J ( θ t ) g_t=\nabla J(\theta_t) gt=J(θt),因此梯度下降法可以写为:
θ t + 1 = θ t − η ∗ g t \theta_{t+1}=\theta_t-\eta * g_t θt+1=θtηgt
Adam是梯度下降法的变种,用来更新神经网络的权重,更新公式如下:
m t = β 1 m t − 1 + ( 1 − β 1 ) g t m_t=\beta_1m_{t-1}+(1-\beta_1)g_t mt=β1mt1+(1β1)gt(更新第一矩向量)
v t = β 2 v t − 1 + ( 1 − β 2 ) g t 2 v_t=\beta_2v_{t-1}+(1-\beta_2)g_t^2 vt=β2vt1+(1β2)gt2 (更新第二矩向量)
m ^ t = m t 1 − β 1 t \hat{m}_t=\dfrac{m_t}{1-\beta_1^t} m^t=1β1tmt (计算偏差矫正的第一矩向量)
v ^ t = v t 1 − β 2 t \hat{v}_t=\dfrac{v_t}{1-\beta_2^t} v^t=1β2tvt (计算偏差矫正的第一矩向量)
θ t + 1 = θ t − η v ^ t + ϵ m ^ t \theta_{t+1}=\theta_t-\dfrac{\eta}{\sqrt{\hat{v}_t}+\epsilon}\hat{m}_t θt+1=θtv^t +ϵηm^t (更新参数)
其中, m 0 = 0 m_0=0 m0=0 v 0 = 0 v_0=0 v0=0 β 1 \beta_1 β1为指数衰减率,控制权重分配, β 2 \beta_2 β2为指数衰减率,控制之前的梯度平方进行加权均值
代码如下:

#6.定义优化器
model = Digit().to(DEVICE)

optimizer = optim.Adam(model.parameters())   #Adam损失函数

7.定义训练的函数

一般定义的训练函数有如下几步:
1.准备好tensor形式的输入数据和标签(可选)
2.前向传播计算网络输出output和计算损失函数loss
3.反向传播更新参数
以下三句话一句也不能少:
(1)将上次迭代计算的梯度值清0
optimizer.zero_grad()
(2)反向传播,计算梯度值
loss.backward()
(3)更新权值参数
optimizer.step()
4.保存训练集上的loss和验证集上的loss以及准确率以及打印训练信息。(可选)
5.图示训练过程中loss和accuracy的变化情况(可选)

#7.定义训练的函数
def train_model(model, device, train_loader,optimizer, epoch):   # 相关参数输入进来
    # 模型训练
    model.train()
    for batch_index, (data, target) in enumerate(train_loader):
        # 部署到DEVICE上去
        data, target = data.to(device), target.to(device)   # 部署到GPU或者CPU上
        # 梯度初始化为0
        optimizer.zero_grad()
        # 训练后的结果
        output = model(data)
        # 计算损失
        loss = F.cross_entropy(output, target)   # 交叉熵损失函数适用于多分类的任务,二分类的问题损失函数是sigmoid函数
        # 找到概率值最大的下标
        pred = output.max(1, keepdim=True)    # 或者可以这样写:pred = output.argmax(dim=1)
        #反向传播
        loss.backward()
        #参数优化
        optimizer.step()
        if batch_index % 3000 == 0:
            print("Train Epoch : {} \t Loss : {:.6f}".format(epoch,loss.item()))    #输出训练的轮数和损失

8.定义测试方法

#8.定义测试方法
def test_model(model, device ,test_loader):
    #模型验证
    model.eval()
    #正确率
    correct = 0.0    # 初始值
    # 测试的损失
    test_loss = 0.0
    with torch.no_grad():    # 不会计算梯度,不需要梯度的计算,也不会进行反向传播
        for data, target in test_loader:
            # 部署到device上
            data,target = data.to(device),target.to(device)
            # 测试数据
            output = model(data)
            # 计算测试损失
            test_loss += F.cross_entropy(output,target).item()
            #找到概率值最大的下标
            pred = output.max(1,keepdim=True)[1]   # [0]值,[1]索引
            # pred = torch.max(output,dim=1)
            # pred = output.argmax(dim=1)
            #累计正确的值
            correct += pred.eq(target.view_as(pred)).sum().item()
        test_loss /= len(test_loader.dataset)   #测试的损失
        print("Test -- Average loss : {:.4f},Accuracy : {:.3f}\n".format(
        test_loss,100.0 * correct / len(test_loader.dataset)))    #输出平均损失和准确率

9.调用方法

for epoch in range(1,EPOCHS + 1):
    train_model(model, DEVICE, train_loader,optimizer,epoch)
    test_model(model, DEVICE, test_loader)

总结

以上是根据B站优秀的up主讲解并加入自己的一些细节的整理
B站链接为:https://www.bilibili.com/video/BV1WT4y177SA

以下为整理中引用的网址:

[1] https://blog.csdn.net/ddana_a/article/details/114748000
[2] https://www.jianshu.com/p/aebcaf8af76e
[3] https://blog.csdn.net/m0_37944102/article/details/104340723
[4] https://blog.csdn.net/dss_dssssd/article/details/83892824

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值