深度学习实验——Pythorch实现mnist手写数字识别
Pythorch实现mnist手写数字识别实验
- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊
目录
一、实验
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()
结果在前文实验中可以看到结果
更多推荐



所有评论(0)