大家好,又见面了,我是你们的朋友全栈君。
MNIST虽然很简单,但是值得我们学习的东西还是有很多的。
项目虽然简单,但是个人建议还是将各个模块分开创建,特别是对于新人而言,模块化的创建会让读者更加清晰、易懂。
注意! 有GPU的小伙伴尽量使用GPU训练,GPU的训练速度比CPU的训练速度高许多倍,可以节约大量训练时间
MNIST的识别算法有很多,在此提供的是 卷积神经网络CNN ,其他算法也同样可以取得很好的识别效果,有兴趣的小伙伴可以自己尝试下。
在此就不得不提 Pytorch的优势了,都知道 Pytorch 是动态计算模型。但是何为动态计算模型呢?
如果暂时看不懂的小伙伴,可以先不管,先往后学习,等将来需要的时候再回头思考这段话。
CNN 模块主要分为两个部分,一个是定义CNN模块,另一个是将各个模块组成前向传播通道
# !/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time : 2020.
# @Author : 绿色羽毛
# @Email : lvseyumao@foxmail.com
# @Blog : https://blog.csdn.net/ViatorSun
# @Note :
from torch import nn
class SimpleCNN(nn.Module):
def __init__(self):
super(SimpleCNN, self).__init__()
self.layer1 = nn.Sequential(
nn.Conv2d(1,16,kernel_size=3) ,
nn.BatchNorm2d(16) ,
nn.ReLU(inplace=True))
self.layer2 = nn.Sequential(
nn.Conv2d(16,32,kernel_size=3) ,
nn.BatchNorm2d(32) ,
nn.ReLU(inplace=True) ,
nn.MaxPool2d(kernel_size=2 , stride=2))
self.layer3 = nn.Sequential(
nn.Conv2d(32,64,kernel_size=3) ,
nn.BatchNorm2d(64) ,
nn.ReLU(inplace=True))
self.layer4 = nn.Sequential(
nn.Conv2d(64,128,kernel_size=3) ,
nn.BatchNorm2d(128) ,
nn.ReLU(inplace=True) ,
nn.MaxPool2d(kernel_size=2 , stride=2))
self.fc = nn.Sequential(nn.Linear(128*4*4,1024) ,
nn.ReLU(inplace=True) ,
nn.Linear(1024,128) ,
nn.ReLU(inplace=True) ,
nn.Linear(128,10) )
def forward( self , x):
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
# x = x.view(x.size(0) , -1)
x = x.reshape(x.size(0) , -1)
fc_out = self.fc(x)
return fc_out
# !/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time : 2020.
# @Author : 绿色羽毛
# @Email : lvseyumao@foxmail.com
# @Blog : https://blog.csdn.net/ViatorSun
# @Note :
import torch
import CNN
from torch import nn , optim
from torchvision import datasets
from torchvision import transforms
from torch.autograd import Variable
from torch.utils.data import DataLoader
# 定义超参数
learning_rate = 1e-2 # 学习率
batch_size = 128 # 批的大小
epoches_num = 20 # 遍历训练集的次数
# 下载训练集 MNIST 手写数字训练集
train_dataset = datasets.MNIST( root='./data', train=True, transform=transforms.ToTensor(), download=True )
train_loader = DataLoader( train_dataset, batch_size=batch_size, shuffle=True )
# 定义model 、loss 、optimizer
model = CNN.SimpleCNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD( model.parameters(), lr=learning_rate )
if torch.cuda.is_available():
print("CUDA is enable!")
model = model.cuda()
model.train()
# 开始训练
for epoch in range(epoches_num):
print('*' * 40)
train_loss = 0.0
train_acc = 0.0
# 训练
for i, data in enumerate(train_loader, 1 ):
img, label = data
# 拥有GPU的小伙伴还是推荐使用GPU训练
if torch.cuda.is_available():
img = Variable(img).cuda()
label = Variable(label).cuda()
else:
img = Variable(img)
label = Variable(label)
# 前向传播
optimizer.zero_grad()
out = model(img)
loss = criterion(out, label)
# 反向传播
loss.backward()
optimizer.step()
# 损失/准确率计算
train_loss += loss.item() * label.size(0)
_ , pred = out.max(1)
num_correct = pred.eq(label).sum()
accuracy = pred.eq(label).float().mean()
train_acc += num_correct.item()
print('Finish {} Loss: {:.6f}, Acc: {:.6f}'.format( epoch+1 , train_loss / len(train_dataset), train_acc / len(train_dataset )))
# 保存模型
torch.save(model, 'cnn.pt')
在模型的使用过程中,有些子模块(如:丢弃层、批次归一化层等)有两种状态,即训练状态和预测状态,在不同时候 Pytorch模型 需要在两种状态中相互转换。
Pytorch 的模型在不同状态下的预测准确性会有差异,在训练模型的时候需要转换为训练状态,在预测的时候需要转化为预测状态,否则最后模型预测准确性可能会降低,甚至会得到错误的结果。
# !/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time : 2020.
# @Author : 绿色羽毛
# @Email : lvseyumao@foxmail.com
# @Blog : https://blog.csdn.net/ViatorSun
# @Note :
import torch
from torch import nn
from torchvision import datasets
from torchvision import transforms
from torch.autograd import Variable
from torch.utils.data import DataLoader
# 定义超参数
batch_size = 128 # 批的大小
# 下载训练集 MNIST 手写数字测试集
test_dataset = datasets.MNIST( root='./data', train=False, transform=transforms.ToTensor())
test_loader = DataLoader(test_dataset , batch_size=batch_size, shuffle=False)
# 加载 Train 模型
model = torch.load('cnn.pt')
criterion = nn.CrossEntropyLoss()
model.eval()
eval_acc = 0
eval_loss = 0
# 测试
for data in test_loader:
img, label = data
if torch.cuda.is_available():
img = Variable(img ).cuda()
label = Variable(label).cuda()
else:
img = Variable(img )
label = Variable(label)
out = model(img)
loss = criterion(out, label)
eval_loss += loss.item() * label.size(0)
_ , pred = torch.max(out,1)
num_correct = (pred==label).sum()
eval_acc += num_correct.item()
print('Test Loss: {:.6f} , Acc: {:.6f}'.format( eval_loss/(len(test_dataset)), eval_acc/(len(test_dataset)) ))
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/126743.html原文链接:https://javaforall.cn