赞
踩
MNIST任务是作为初学者来说, 是一个不错的起点。掌握MNIST任务的实现,以此为后续的CV(计算机视觉)和DL(深度学习)打下良好基础的基础。
目录
MNIST(Modified National Institute of Standards and Technology)数据集是一个广泛使用的手写数字识别数据集。它包含了从0到9的数字的灰度图像,通常用于训练和测试图像识别算法。MNIST数据集是由纽约大学的Yann LeCun教授及其同事创建的,它是对原始的NIST数据集进行修改和整理后的版本。
MNIST数据集包含60,000个训练样本和10,000个测试样本。每个样本都是一个28x28像素的灰度图像,代表了0到9中的一个数字。这些图像是从不同的手写体、不同的书写风格和不同的字体中提取的,因此包含了大量的变异性。
为了让大家更能理解mnist的任务实现,这里绘制了流程图:
为了源码的可读性,给出了每行源码及其注释。
代码已在pytorch框架调试(NVIDIA RTX 3060 12G,anaconda+pycharm),大家可直接拿来使用,正确率可以达到99%以上,如果达不到,可以根据硬件条件,固定随机种子,修改模型超参数,以达到最优。
- '''1.加载必要的库'''
- import torch
- import torch.nn as nn
- import torch.nn.functional as F
- import torch.optim as optim
- from torchvision import datasets,transforms
- from torch.utils.data import DataLoader
- '''2.定义超参数'''
- BATCH_SIZE=64 # 每个批次处理的图像
- EPOCH=10 # 训练数据集的轮次:数据集的循环运行几轮
- DEVICE=torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 判断是否用GPU还是CPU训练
- '''3.构建pipeline,对图像做预处理(transform)'''
- pipeline=transforms.Compose([
- transforms.ToTensor(), # 将图片转换成tensor
- transforms.Normalize((0.1307,),(0.3081,)) # 正则化,降低模型复杂度
- ])
- '''4.下载、加载数据集'''
- torch.manual_seed(0) #固定随机种子,大家可以尝试不同的种子测试,择选最好的一次
- train_set=datasets.MNIST('data',train=True,download=True,transform=pipeline) # 下载训练集
- test_set=datasets.MNIST('data',train=False,download=True,transform=pipeline) # 下载测试集
- train_loader=DataLoader(train_set,batch_size=BATCH_SIZE,shuffle=True) # 加载训练集
- test_loader=DataLoader(test_set,batch_size=BATCH_SIZE,shuffle=True) # 加载测试集 (这里顺序可以不打乱)
- '''5.定义网络模型'''
- class mnist(nn.Module): # 构建mnist模型,并继承module类
- def __init__(self): # 初始化mnist方法
- super().__init__() # 继承父类的方法
- self.conv1=nn.Conv2d(1,10,5) # 创建一个卷积模型,1:灰度图通道,10:输出通道,5:卷积核(kernel)大小
- self.conv2=nn.Conv2d(10,20,3) # 创建一个卷积模型,10:输入通道,20:输出通道,3:kernel大小
- self.drop_out=nn.Dropout2d(0.25)
- 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) # 取到第0维:batch_size
- x=self.conv1(x) # 输入:batch_size*1*28*28,输出:batch_size*10*24*24(24=28-5+1,padding=0,stride=1)
- x=F.relu(x) # 保持shape不变,表达能力更强
- x=F.max_pool2d(x,2,2) #最大池化层,步长是2,24/2=12,结果:batch_size*10*12*12
- x=self.conv2(x) # 输入:batch_size*10*12*12,输出:batch_size*20*10*10
- x=F.relu(x)
- x=x.reshape(input_size, -1) # 计算其维度 2000=20*10*10,并将其打平
- x=self.fc1(x) # 输入:batch_size=2000, 输出:batch_size*500
- x = F.relu(x)
- x=self.fc2(x) # 输入:batch_size=500, 输出:batch_size*10
- x = F.relu(x)
-
- output=F.log_softmax(x,dim=1) #计算分类后,每个数字的概率值
- return output
- '''6.定义优化器'''
- model=mnist().to(DEVICE) # 创建模型,并部署到设备上
- optimizer=optim.Adam(model.parameters()) # 优化模型的参数
- '''7.定义训练方法'''
- def train_model(model,device,train_loader,optimizer,epoch): # 定义训练方法
- model.train() #训练模型
- loss_total=0
- for batch_index,(data,target) in enumerate(train_loader):
- data,target=data.to(device),target.to(device) # 把数据部署到设备上
- optimizer.zero_grad() # 梯度初始化为0
- output=model(data) # 前向传播,得到训练后的结果
- loss=F.cross_entropy(output,target) # 计算损失值
- loss.backward() # 将损失值进行反向传播
- optimizer.step() # 参数的优化更新
- loss_total+=loss.item() # 累加一个epoch所有损失值
- loss_epoch=loss_total/len(train_loader) # 计算机每一个epoch的平均损失值
- print(f'Train epoch:{epoch} \t loss_epoch:{loss_epoch:0.6f}') # 打印epoch及平均损失值
- '''8.定义测试方法'''
- def test_model(model,device,test_loader):
- model.eval() # 设置模型的评估模式
- correct=0.0 # 初始化正确率
- loss_test=0.0 # 初始化损失值
- with torch.no_grad(): # 测试环境,不计算梯度,也不进行反向传播
- for data,target in test_loader:
- data,target=data.to(device),target.to(device) # 将数据移动到设备上
- output=model(data) # 前向传播
- loss_test+=F.cross_entropy(output,target).item() # 累加当前批次的损失值之和
- pred = output.max(1, keepdim=True)[1] # 找到概率值最大的下标
- correct+=pred.eq(target.view_as(pred)).sum().item() # 计算正确的样本数量
- loss_test/=len(test_loader.dataset) # 计算测试集平均的损失
- Accuracy=100*correct/len(test_loader.dataset)
- print(f'Test_loss:{loss_test:.4f} \t Accuracy:{Accuracy:.3f}\n')
- '''9.调用训练和测试的方法'''
- for epoch in range(EPOCH):
- train_model(model,DEVICE,train_loader,optimizer,epoch)
- test_model(model,DEVICE,test_loader)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。