目录

一、实验

1、实验目的

2、相关知识点

3、错误及解决方案

4、总结

二、代码实现

1、前期准备

2、构建网络

3、训练模型

4、结果可视化


一、实验

1、实验目的

        ①了解Pytorch基本语法

        ②使用Pytorch构建一个深度学习程序(手写数字识别)

2、相关知识点

        ①卷积层:卷积层可以保持形状不变

        卷积运算的批处理需要将各层间传递的数据保存为4维数据,按照(batch_num,channel,height,width)的顺序保存数据

        ②激活函数:向网络添加了基于激活函数的“非线性”的表现力,通过非线性函数的叠加,可以表现更加复杂的东西

        ReLu函数的公式及图像

        

        ③池化层:能够缩小高、长方向上的空间运算,通道数不发生变化,没有要学习的参数并且对微小位置的变化具有鲁棒性

        ④flatten层:该层能将卷积层提取的空间特征转换为一维向量,为后续的全连接分类层提供合适的输入格式

        ⑤全连接层:位于网络的末端,负责将前面层次提取的特征进行整合,并最终输出网络的预测结果

        ⑥超参数:超参数也经常出现,包括各层的神经元数量、batch大小、参数更新时的学习率或权值衰减等,如果这些超参数没有设置合适的值,那模型的性能就会很差

本实验的网络结构

输入层->卷积层1->ReLu激活->最大池化1->卷积层2->ReLu激活->最大池化2->flatten->全连接1->ReLu激活->全连接2

数据集(MNIST

MNIST是一个非常成熟的数据集,作为机器学习在视觉领域的“hello world”,可以通过链接点进去了解

神经网络训练-三步走

完整的神经网络训练:前向传播-反向传播-在n个epoch上训练

三步走相关语法:

        optimizer.zero_grad():清空梯度,避免梯度累加

        loss.backward():反向传播,计算梯度

        optimizer.step():根据当前的梯度,更新模型参数

实验结果

能够清楚的看到随着训练进行,精度和损失函数的变化过程

3、错误及解决方案

缺少模块:conda install -c conda-forge 模块名下载

已经下载模块但无法找到:可能是解释器出错,需要用conda环境下的python解释器,文件 -> 设置 -> 项目 -> python解释器中为新建的python解释器添加/修改路径

数据集无法下载or访问:无法联网下载,把参数download改为false,root设置为数据集的存储路径,最好是完整路径

4、总结

第一次接触深度学习,在pycharm编译器上配环境还花了挺多时间的,能够勉强看懂代码的逻辑,但pytorch的基本语法还得多熟悉,该实验重点在于特征网络、分类网络的构建和模型训练三步走,后续的学习要理解网络构建的更加体系化的流程思路

二、代码实现

1、前期准备

        ①导入库并设置GPU

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import torchvision
from torch.onnx.symbolic_opset11 import relu6
from torchvision import transforms

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

        ②导入并测试数据集

        导入数据集,注意无法联网下载的时候就从本地加载,但需要先下载数据集放在文件目录下

dataPath = "G:\project_P1\data"
#获取训练数据
train_ds = torchvision.datasets.MNIST(
    root=dataPath,
    #只需要数据集中的训练集
    train=True,
    transform=transforms.ToTensor(),
    #因为本地数据集有MNIST,故不需要下载
    download=False
)
#获取测试数据
test_ds = torchvision.datasets.MNIST(
    root=dataPath,
    #不需要训练数据
    train=False,
    transform=transforms.ToTensor(),
    download=False
)

       测试数据集

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
)

imgs,labels=next(iter(train_dl))

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')
    plt.show()

注意如果想看img的形状大小可以用imgs.shape来查看

部分结果图(这里设置的是2行10列,但不知道结果为啥只有1列了,我还没搞懂)

2、构建网络

        ①了解网络架构

        一般的网络都会包括特征提取网络和分类网络构成,卷积层和池化层主要用于图像特征的提取,分类网络则用于图片的分类

        该实验当中的网络经过两次卷积-池化后,再经过flatten层和两次全连接

        ②实现模型

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)

可以看到该实验的模型框架详细信息

3、训练模型

(训练三步走:梯度清零、反向传播、更新权重)

设置超参数并编写训练函数,这里的优化器选择的是SGD

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()

        #记录acc与loss
        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

测试函数同理,但是不需要对网络权重进行更新,因此不传入优化器,其余原理一致

模型训练

#设置训练的轮次为5
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_acc:{:.1f}%,Train_loss:{:.3f},Test_acc:{:.1f}%,Test_loss:{:.3f}')
    print(template.format(epoch+1,epoch_train_acc*100,epoch_train_loss,epoch_test_acc*100,epoch_test_loss))
print('Done')

得到的训练过程如下

4、结果可视化

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

from datetime import datetime
current_time=datetime.now()

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.xlabel(current_time)

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()

结果在前文实验中可以看到结果

更多推荐