老饼讲解:一步一步上手深度学习
好了,这一节我们具体来看看CNN如何实现手写数字识别。
虽然我们知道,光是MLP就能实现手写数字识别了,因为手写数字比较简单,输入个数比较小,完全不能体现CNN的威力。但是呢,拿它来试试刀先,至少它不能比MLP差吧?~
好了,直接上代码,
CNN识别手写数字,具体代码实现如下:
# 本代码用于展示CNN实现手写数字识别
# 本代码来自《老饼讲解-深度学习》www.bbblearn.com
import torch
from torch import nn
from torch.utils.data import DataLoader
import torchvision
import numpy as np
#--------------------模型结构----------------------
# 卷积神经网络的结构
class ConvNet(nn.Module):
def __init__(self,in_channel,num_classes):
super(ConvNet, self).__init__()
self.stack=nn.Sequential(
#--------------C1层------------
nn.Conv2d(in_channel,6, kernel_size=5,stride=1,padding=2),
nn.ReLU(inplace=True),
nn.AvgPool2d(kernel_size=2,stride=2),
# 输出14*14
#--------------C2层------------
nn.Conv2d(6,16, kernel_size=5,stride=1,padding=2),
nn.ReLU(inplace=True),
nn.AvgPool2d(kernel_size=2,stride=2),
# 输出7*7
#--------------C3层------------
nn.Conv2d(16,80,kernel_size=7,stride=1,padding=0),
# 输出1*1*80
#--------------全连接层F4------
nn.Flatten(), # 对C3的结果进行展平
nn.Linear(80, 120),
nn.ReLU(inplace=True),
#--------------全连接层F5------
nn.Linear(120, num_classes)
)
def forward(self, x):
y = self.stack(x)
return y
#-----------------------模型训练-----------------
# 训练函数
def train(dataloader,model,optimizer,epochs,goal):
print("\n--开始训练--:") # 打印准确率
for epoch in range(epochs): # 逐步训练
for batch, (x, y) in enumerate(dataloader): # 逐批训练
# -----训练模型-----
optimizer.zero_grad() # 将优化器里的参数梯度清空
py = model(x) # 计算模型的预测值
loss = lossFun(py, y) # 计算损失函数值
loss.backward() # 更新参数的梯度
optimizer.step() # 更新参数
acc_rate = calAcc(model,dataloader) # 计算数据集的准确率
print(f"第{epoch}步,准确率:",acc_rate) # 打印准确率
if(acc_rate>=goal): # 检查退出条件
break
# 计算数据集的准确率
def calAcc(model,dataLoader):
py = np.empty(0) # 初始化预测结果
y = np.empty(0) # 初始化真实结果
for batch, (imgs, labels) in enumerate(dataLoader): # 逐批预测
cur_py = model(imgs) # 计算网络的输出
cur_py = torch.argmax(cur_py,axis=1) # 将最大者作为预测结果
py = np.hstack((py,cur_py.detach().cpu().numpy())) # 记录本批预测的y
y = np.hstack((y,labels)) # 记录本批真实的y
acc_rate = sum(y==py)/len(y) # 计算测试样本的准确率
return acc_rate
#--------------主流程脚本----------------------
#-------------------加载数据------------------------
train_data = torchvision.datasets.MNIST(
root = 'D:\\pytorch\\data' # 路径有,就从路径中加载,否则联网获取
,download = True # 是否下载,选为True,就下载到root下面
,train = True # 获取训练数据
,transform = torchvision.transforms.ToTensor() # 转换为tensor数据
,target_transform= None)
test_data = torchvision.datasets.MNIST(
root = 'D:\\pytorch\\data' # 路径有,就从路径中加载,否则联网获取
,download = True # 是否下载,选为True,就下载到root下面
,train = False # 获取测试数据
,transform = torchvision.transforms.ToTensor() # 转换为tensor数据
,target_transform= None)
#-------------------模型训练--------------------------------
trainLoader = DataLoader(train_data, batch_size=100, shuffle=True) # 将训练数据装载到DataLoader
testLoader = DataLoader(test_data , batch_size=100) # 将测试数据装载到DataLoader
model = ConvNet(in_channel =1,num_classes=10) # 初始化模型
lossFun = torch.nn.CrossEntropyLoss() # 定义损失函数为交叉熵损失函数
optimizer = torch.optim.SGD(model.parameters(), lr=0.05,momentum =0.9) # 初始化优化器
train(trainLoader,model,optimizer,1000,0.99) # 训练模型
# -----------模型效果评估---------------------------
print("\n--训练结果--:") # 打印训练结果
train_acc_rate = calAcc(model,trainLoader) # 计算训练数据集的准确率
print("训练数据的准确率:",train_acc_rate) # 打印准确率
test_acc_rate = calAcc(model,testLoader) # 计算测试数据集的准确率
print("测试数据的准确率:",test_acc_rate) # 打印准确率运行结果如下:

可以看到,简单的3个epoch,模型就训练完成了,比我们用MLP时要快得多。
而且,训练结果中,测试数据0.9889,与训练数据的准确率几乎一致,它的泛化能力明显也比用MLP的效果更好。
代码主要由模型与训练代码组成,模型已经在《CNN卷积神经网络是什么》中解说过了,而训练代码跟《MLP识别手写数字》中一模一样,因为我就是直接从那里复制过来的,哈哈,多省事。所以这代码也没什么好说的,因为就只是之前MLP的代码改了一下模型而已。
好了,关于模型中的参数设置,我们在正式学CNN的时候,自然就会理解了。
好了,这节我们就看了一下CNN识别手写数字的整体代码和效果,它在图像上的处理果然是专业的,比MLP时的效果好多了。
评论