基于pytorch框架的MNIST手写数字识别详解(附源码)

前言

数字识别,因其识别对象蕴含信息简单(灰度图单通道即可)、应用场景广阔,成为了传统图像处理的一大Key Topic. 深度学习的兴起使得端到端学习取代了机器学习+手工设计的传统识别算法成为了热门。
本文基于pytorch框架、MNIST数据集,使用LeNet对MNIST数据集实现高精度手写数字识别。

MNIST数据集, 引自WIKI

数据集介绍参考维基百科:MNIST database.

LeNet-5模型介绍

LeNet-5出自Y. L. LeCun的论文Gradient-Based Learning Applied to Document Recognition,是一种专门设计于场景”手写体字符识别“的非常高效的卷积神经网络。LeNet-5这个网络虽然很小,但是它包含了深度学习的基本模块:卷积层,池化层,全链接层。
原文中的网络结构图见下:
原文网络结构图LeNet-5不含输入共7层,每个层有多个Feature Map,每个FeatureMap通过一种卷积滤波器提取输入的一种特征。

各层参数

Input

ParameterValue
Input32x32x1
Conv1 卷积层
ParameterValue
-------------
Input32x32x1
Kernel Size5x5
Kernel Number6
Stride1
Output28x28x6
Pool2 池化层
ParameterValue
-------------
Input28x28x6
Kernel Size2x2
Stride2
Output14x14x6
Conv3 卷积层
ParameterValue
-------------
Input14x14x6
Kernel Size5x5
Kernel Number16
Stride1
Output10x10x16
Pool4 池化层
ParameterValue
-------------
Input10x10x16
Kernel Size2x2
Stride2
Output5x5x16
Conv5 卷积层
ParameterValue
-------------
Input5x5x16
Kernel Size5x5
Kernel Number120
Stride1
Output1x1x120
F6 全连接层
ParameterValue
-------------
Input120
Output84
Output 全连接层
ParameterValue
-------------
Input84
Output10

百度学术链接:Gradient-Based Learning Applied to Document Recognition.
注:本文发表于1998年,原文中的部分内容经过今年的发展有了更好的选择,如ReLU激活函数的优越性、最大池化层代替平均池化层的使用会获得更好的结果等,故实现过程中有些许改动及优化。

Pytorch代码详解

开发环境

工具包版本
python3.6.2
torch1.0.0
torchvision0.2.1
visdom0.1.7
matplotlib2.0.2

代码详解

库依赖

# standard library
import os 
# third-party library
import torch
import torch.nn as nn
from torch.autograd import Variable
import torch.utils.data as Data 		# dataset
import torchvision						# torch vision library
import matplotlib.pyplot as plt 		# plot 2D data, Visualization
import visdom 							# python -m visdom.server

超参定义

torch.manual_seed(1)    # reproducible 设定生成随机数的种子,并返回一个 torch._C.Generator 对象

# Hyper Parameters 超参数
EPOCH = 250             # train the training data n times, to save time, we just train 1 epoch
BATCH_SIZE = 8192		# Data number per batch
LR = 0.001              # learning rate
VISDOM = True           # 绘图

torch.manual_seed(1) 使得每次得到的随机数(参数初始化)是固定的,无需固定随机参数可删。

数据集下载打包

torchvision.datasets中包含了MNIST数据集,我们无需另外下载。该部分自动检测数据集是否置于工作路径下,若未检测到则自动下载。
我们采用mini-batch梯度下降法进行训练,故需要生成相应的mini-batch训练集和数据集。

##############################################################################################
########################### Mnist digits dataset preparation #################################
DOWNLOAD_MNIST = False  # 是否下载
if not(os.path.exists('./mnist/')) or not os.listdir('./mnist/'):
    # not mnist dir or mnist is empyt dir
    DOWNLOAD_MNIST = True

MNISTtrainData = torchvision.datasets.MNIST(            # data size (60000, 28, 28) + label(60000)
    root = './mnist/',
    train = True,                                     # this is training data
    transform = torchvision.transforms.ToTensor(),    # Converts a PIL.Image or numpy.ndarray to
                        # torch.FloatTensor of shape (C x H x W) and normalize in the range [0.0, 1.0]
    download = DOWNLOAD_MNIST
)
# Data Loader for easy mini-batch return in training,
# the image batch shape will be (BATCH_SIZE, 1, 28, 28)
train_loader = Data.DataLoader(dataset=MNISTtrainData, batch_size=BATCH_SIZE, shuffle=True)

MNISTtestData = torchvision.datasets.MNIST(            # data size (10000, 28, 28) + label(10000)
    root = './mnist/', train = False,
    transform = torchvision.transforms.ToTensor(),    # Converts a PIL.Image or numpy.ndarray to
                        # torch.FloatTensor of shape (C x H x W) and normalize in the range [0.0, 1.0]
    download = DOWNLOAD_MNIST
)
test_loader = Data.DataLoader(dataset=MNISTtestData, batch_size=BATCH_SIZE, shuffle=True)

网络构建

采用LeNet-5模型,详见上述。

######################## define LeNet construction & Parameters ##############################
# widith_output = (widith_input + 2 * padding - kernel_size) / stride + 1
# padding = (kernel_size - 1) / 2 if stride = 1
class LeNet(nn.Module):
    def __init__(self):     
        super(LeNet, self).__init__()
        self.conv1 = nn.Sequential(         # input shape (1, 28, 28)
            nn.Conv2d(
                in_channels = 1,            # input height 输入通道
                out_channels = 6,           # n_filters 输出通道
                kernel_size = 5,            # filter size 卷积核
                stride = 1,                 # filter movement/step 步长
                padding = 2,                # if want same width and length of this image after con2d
            ),                              # output shape (6, 28, 28)
            nn.ReLU(),                      # activation
            nn.MaxPool2d(                   # choose max value in 2x2 area
                kernel_size = 2,
                stride = 2
            ),                              # output shape (6, 14, 14)
        )
        self.conv2 = nn.Sequential(         # input shape (6, 14, 14)
            nn.Conv2d(6, 16, 5),            # output shape (16, 10, 10)
            nn.ReLU(),                      # activation
            nn.MaxPool2d(2, 2),             # output shape (16, 5, 5)
        )
        self.fc1 = nn.Sequential( 
            nn.Linear(16 * 5 * 5, 120),     # fully connected layer, output 120 classes
            nn.ReLU() 
        ) 
        self.fc2 = nn.Sequential( 
            nn.Linear(120, 84),             # fully connected layer, output 84 classes
            nn.ReLU() 
        ) 
        self.fc3 = nn.Linear(84, 10)        # fully connected layer, output 10 classes

    # define forward propagation progress 
    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = x.view(x.size(0), -1)           # flatten the output of conv2 to (batch_size, 16 * 5 * 5)
        x = self.fc1(x)
        x = self.fc2(x)
        output = self.fc3(x)

        return output, x            # return x for visualization

myLeNet = LeNet()	# 网络实例化

if torch.cuda.is_available():	# cuda可用时可置于GPU中训练网络,以加快计算速度
    myLeNet.cuda()
    print("cuda is available, and the calculation will be moved to GPU\n")
else:
    print("cuda is unavailable!")

训练&测试

采用Adam优化算法+交叉熵损失函数,并用visdom进行可视化操作。

###########################       training & testing         #################################
optimizer = torch.optim.Adam(myLeNet.parameters(), lr = LR)   # optimize all cnn parameters
loss_func = nn.CrossEntropyLoss()           # 交叉熵 loss the target label is not one-hotted

if VISDOM:
    vis = visdom.Visdom(env=u'MNIST for leNet')
    vis.line(X=torch.Tensor([1]),Y=torch.Tensor([0]),win='trainAcc', \
        opts=dict(title = 'acc rate(%) for train data', ytickmin = 0, ytickmax = 100)) 
    vis.line(X=torch.Tensor([1]),Y=torch.Tensor([0]),win='trainLoss', \
        opts=dict(title = 'train loss', ytickmin = 0, ytickmax = 2.5))
    vis.line(X=torch.Tensor([1]),Y=torch.Tensor([0]),win='testAcc', \
        opts=dict(title = 'acc rate(%) for test data', ytickmin = 0, ytickmax = 100)) 
    vis.line(X=torch.Tensor([1]),Y=torch.Tensor([0]),win='testLoss', \
        opts=dict(title = 'test loss', ytickmin = 0, ytickmax = 2.5))

mini-batch梯度下降法,并对每个epoch记录并更新loss值和准确度。

for epoch in range(EPOCH):
    for step, (x, y) in enumerate(train_loader):   
        # gives batch data, normalize x when iterate train_loader
        if torch.cuda.is_available():
            batch_x = Variable(x).cuda()
            batch_y = Variable(y).cuda()
        else:
            batch_x = Variable(x)
            batch_y = Variable(y)

        output, last_layer = myLeNet(batch_x)      # LeNet output
        loss = loss_func(output, batch_y)   # cross entropy loss
        optimizer.zero_grad()           # clear gradients for this training step
        loss.backward()                 # backpropagation, compute gradients
        optimizer.step()                # apply gradients
 
        _, correct_label = torch.max(output, 1)  # 输出预测概率的label
        # print('label', correct_label)
        correct_num = (correct_label == batch_y).sum()

        trainAcc = correct_num.item() / float(batch_y.size(0))

        print('train: Epoch [%d/%d], Iter [%2d/%d] Loss: %.4f, Acc: %.4f' % \
              	(epoch + 1, EPOCH, step + 1, len(MNISTtrainData) // BATCH_SIZE + 1, \
              		loss.item(), trainAcc))
        
    if VISDOM:
        vis.line(X=torch.Tensor([epoch + 1]), \
                     Y=torch.Tensor([trainAcc * 100]),  win='trainAcc',  update='append')
        vis.line(X=torch.Tensor([epoch + 1]),\
                     Y=torch.Tensor([loss]), win='trainLoss', update='append')

    testAcc = 0
    for _, (x, y) in enumerate(test_loader):   
        # gives batch data, normalize x when iterate train_loader
        if torch.cuda.is_available():
            batch_x = Variable(x).cuda()
            batch_y = Variable(y).cuda()
        else:
            batch_x = Variable(x)
            batch_y = Variable(y)

        output, last_layer = myLeNet(batch_x)      # LeNet output
        loss = loss_func(output, batch_y)   		# cross entropy loss
        _, correct_label = torch.max(output, 1)  # 输出预测概率最大的值和标签
        # print('label', correct_label)
        correct_num = (correct_label == batch_y).sum()
        testAcc += correct_num.item()  

    testAcc = testAcc / float(MNISTtestData.test_labels.size(0))

    print('----------------test: Epoch [%d/%d] Acc: %.4f' % (epoch + 1, EPOCH,  testAcc))
    
    if VISDOM:
        vis.line(X=torch.Tensor([epoch + 1]), \
                 Y=torch.Tensor([testAcc * 100]),  win='testAcc',  update='append')
        vis.line(X=torch.Tensor([epoch + 1]),\
                     Y=torch.Tensor([loss]), win='testLoss', update='append')
    torch.save(myLeNet, './ModelBackup/MNIST_lenet_model_%d_%f.pkl'%(epoch, testAcc))

最后保存模型(建议每隔几个epoch保存备用):

torch.save(myLeNet, './ModelBackup/MNIST_lenet_model_%d_%f.pkl'%(epoch, testAcc))

这样,你就有一个专门处理手写数字的简单模型了。

运行说明

  1. 终端启动visdom server:
python -m visdom.server
  1. 打开链接 http://localhost:8097/# ;
  2. 运行源码,visdom选定environment选定所处环境,查看曲线实时更新。

运行结果

epoch训练集损失值训练集准确度(%)测试集损失值测试集准确度(%)
12.23223.382.20029.94
55.142e-183.325.328e-179.95
201.488e-194.921.222e-195.97
506.347e-297.705.043e-298.13
903.147e-298.913.701e-298.69
1402.868e-299.513.873e-298.86
2001.300e-299.964.108e-298.85
2506.061e-399.893.226e-298.91
在约90轮训练后,模型对训练集开始出现过拟合现象,测试集准确度随着epoch的增大变化较小,故90轮的模型较好。

训练集损失值曲线:
在这里插入图片描述
训练集准确度曲线:
在这里插入图片描述测试集损失值曲线:
在这里插入图片描述
测试集准确度曲线:

在这里插入图片描述

模型实测

改变打开的图片文件,可以判别数字并计算概率。
整体思路

  1. 载入图片
  2. 转灰度并压缩至指定大小
  3. 图片归一化,使得对比度增强
  4. 图片输入模型
  5. 全连接层输出做softmax
  6. 得出结果

源码

import cv2
import torch
import torch.nn as nn
import numpy as np
import math
from torch.autograd import Variable
from LeNet import LeNet

# 模型读取
myLeNet = torch.load('Best_LeNet_Model.pkl')
if torch.cuda.is_available():
    myLeNet.cuda()
    print("cuda is available, and the calculation will be moved to GPU\n")
else:
    print("cuda is unavailable!")

# 文件读取->灰度->压缩
frame = cv2.imread('2.png')
originImg = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame', originImg)
inputImage = cv2.resize(originImg, (28, 28))
inputImage = np.ones([28,28]) * 255 - inputImage

# 灰度域拉伸
inputImage = np.floor(255 / (np.max(np.max(inputImage)) - np.min(np.min(inputImage))) 
				* (inputImage - np.min(np.min(inputImage))))

# 与Net输入做匹配
inputImage = np.expand_dims(inputImage, axis=0)	# 维度增加!!!
inputImage = np.expand_dims(inputImage, axis=0)

# 输入必须归一化!和数据集保持一致
tensorImage = torch.FloatTensor(inputImage/255)
varImage = Variable(tensorImage).cuda()
output,_ = myLeNet(varImage)      # LeNet output
_, correct_label = torch.max(output, 1)  # 输出预测概率的label

# GPUtensor转numpy
npOutput = output.cpu().detach().numpy()[0]
npCorrect_label = correct_label.cpu().detach().numpy()[0]

similarity = np.exp(npOutput)/np.sum(np.exp(npOutput))
print('label:', npCorrect_label, 'similarity :', similarity[npCorrect_label]*100,'%')

测试结果

图片取自网络(随机截图)。
图片| 识别结果| 置信度(%)
-------- | -------- | ----------- | -----------
在这里插入图片描述|2|94.90
在这里插入图片描述|5|99.85
在这里插入图片描述|7|97.25
在这里插入图片描述|8|98.19

完整训练源码

github链接

https://github.com/HYPENG1/MNIST_train_LeNet/tree/YoooHu

# standard library
import os 
# third-party library
import torch
import torch.nn as nn
from torch.autograd import Variable
import torch.utils.data as Data 		# dataset
import torchvision						# torch vision library
import matplotlib.pyplot as plt 		# plot 2D data, Visualization
import visdom 							# python -m visdom.server


torch.manual_seed(1)    # reproducible 设定生成随机数的种子,并返回一个 torch._C.Generator 对象

# Hyper Parameters 超参数
EPOCH = 250             # train the training data n times, to save time, we just train 1 epoch
BATCH_SIZE = 8192		# Data number per batch
LR = 0.001              # learning rate
VISDOM = True           # 绘图

##############################################################################################
########################### Mnist digits dataset preparation #################################
DOWNLOAD_MNIST = False  # 是否下载
if not(os.path.exists('./mnist/')) or not os.listdir('./mnist/'):
    # not mnist dir or mnist is empyt dir
    DOWNLOAD_MNIST = True

MNISTtrainData = torchvision.datasets.MNIST(            # data size (60000, 28, 28) + label(60000)
    root = './mnist/',
    train = True,                                     # this is training data
    transform = torchvision.transforms.ToTensor(),    # Converts a PIL.Image or numpy.ndarray to
                        # torch.FloatTensor of shape (C x H x W) and normalize in the range [0.0, 1.0]
    download = DOWNLOAD_MNIST
)
# Data Loader for easy mini-batch return in training,
# the image batch shape will be (BATCH_SIZE, 1, 28, 28)
train_loader = Data.DataLoader(dataset=MNISTtrainData, batch_size=BATCH_SIZE, shuffle=True)

MNISTtestData = torchvision.datasets.MNIST(            # data size (10000, 28, 28) + label(10000)
    root = './mnist/', train = False,
    transform = torchvision.transforms.ToTensor(),    # Converts a PIL.Image or numpy.ndarray to
                        # torch.FloatTensor of shape (C x H x W) and normalize in the range [0.0, 1.0]
    download = DOWNLOAD_MNIST
)
test_loader = Data.DataLoader(dataset=MNISTtestData, batch_size=BATCH_SIZE, shuffle=True)

##############################################################################################
######################## define LeNet construction & Parameters ##############################
# widith_output = (widith_input + 2 * padding - kernel_size) / stride + 1
# padding = (kernel_size - 1) / 2 if stride = 1
class LeNet(nn.Module):
    def __init__(self):     
        super(LeNet, self).__init__()
        self.conv1 = nn.Sequential(         # input shape (1, 28, 28)
            nn.Conv2d(
                in_channels = 1,            # input height 输入通道
                out_channels = 6,           # n_filters 输出通道
                kernel_size = 5,            # filter size 卷积核
                stride = 1,                 # filter movement/step 步长
                padding = 2,                # if want same width and length of this image after con2d
            ),                              # output shape (6, 28, 28)
            nn.ReLU(),                      # activation
            nn.MaxPool2d(                   # choose max value in 2x2 area
                kernel_size = 2,
                stride = 2
            ),                              # output shape (6, 14, 14)
        )
        self.conv2 = nn.Sequential(         # input shape (6, 14, 14)
            nn.Conv2d(6, 16, 5),            # output shape (16, 10, 10)
            nn.ReLU(),                      # activation
            nn.MaxPool2d(2, 2),             # output shape (16, 5, 5)
        )
        self.fc1 = nn.Sequential( 
            nn.Linear(16 * 5 * 5, 120),     # fully connected layer, output 120 classes
            nn.ReLU() 
        ) 
        self.fc2 = nn.Sequential( 
            nn.Linear(120, 84),             # fully connected layer, output 84 classes
            nn.ReLU() 
        ) 
        self.fc3 = nn.Linear(84, 10)        # fully connected layer, output 10 classes

    # define forward propagation progress 
    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = x.view(x.size(0), -1)           # flatten the output of conv2 to (batch_size, 16 * 5 * 5)
        x = self.fc1(x)
        x = self.fc2(x)
        output = self.fc3(x)

        return output, x            # return x for visualization

myLeNet = LeNet()	# 网络实例化

if torch.cuda.is_available():
    myLeNet.cuda()
    print("cuda is available, and the calculation will be moved to GPU\n")
else:
    print("cuda is unavailable!")

##############################################################################################
###########################       training & testing         #################################
optimizer = torch.optim.Adam(myLeNet.parameters(), lr = LR)   # optimize all cnn parameters
loss_func = nn.CrossEntropyLoss()           # 交叉熵 loss the target label is not one-hotted

if VISDOM:
    vis = visdom.Visdom(env=u'MNIST for leNet')
    vis.line(X=torch.Tensor([1]),Y=torch.Tensor([0]),win='trainAcc', \
        opts=dict(title = 'acc rate(%) for train data', ytickmin = 0, ytickmax = 100)) 
    vis.line(X=torch.Tensor([1]),Y=torch.Tensor([0]),win='trainLoss', \
        opts=dict(title = 'train loss', ytickmin = 0, ytickmax = 2.5))
    vis.line(X=torch.Tensor([1]),Y=torch.Tensor([0]),win='testAcc', \
        opts=dict(title = 'acc rate(%) for test data', ytickmin = 0, ytickmax = 100)) 
    vis.line(X=torch.Tensor([1]),Y=torch.Tensor([0]),win='testLoss', \
        opts=dict(title = 'test loss', ytickmin = 0, ytickmax = 2.5))

for epoch in range(EPOCH):
    for step, (x, y) in enumerate(train_loader):   
        # gives batch data, normalize x when iterate train_loader
        if torch.cuda.is_available():
            batch_x = Variable(x).cuda()
            batch_y = Variable(y).cuda()
        else:
            batch_x = Variable(x)
            batch_y = Variable(y)

        output, last_layer = myLeNet(batch_x)      # LeNet output
        loss = loss_func(output, batch_y)   # cross entropy loss
        optimizer.zero_grad()           # clear gradients for this training step
        loss.backward()                 # backpropagation, compute gradients
        optimizer.step()                # apply gradients
 
        _, correct_label = torch.max(output, 1)  # 输出预测概率的label
        # print('label', correct_label)
        correct_num = (correct_label == batch_y).sum()

        trainAcc = correct_num.item() / float(batch_y.size(0))

        print('train: Epoch [%d/%d], Iter [%2d/%d] Loss: %.4f, Acc: %.4f' % \
              	(epoch + 1, EPOCH, step + 1, len(MNISTtrainData) // BATCH_SIZE + 1, \
              		loss.item(), trainAcc))
        
    if VISDOM:
        vis.line(X=torch.Tensor([epoch + 1]), \
                     Y=torch.Tensor([trainAcc * 100]),  win='trainAcc',  update='append')
        vis.line(X=torch.Tensor([epoch + 1]),\
                     Y=torch.Tensor([loss]), win='trainLoss', update='append')

    testAcc = 0
    for _, (x, y) in enumerate(test_loader):   
        # gives batch data, normalize x when iterate train_loader
        if torch.cuda.is_available():
            batch_x = Variable(x).cuda()
            batch_y = Variable(y).cuda()
        else:
            batch_x = Variable(x)
            batch_y = Variable(y)

        output, last_layer = myLeNet(batch_x)      # LeNet output
        loss = loss_func(output, batch_y)   		# cross entropy loss
        _, correct_label = torch.max(output, 1)  # 输出预测概率最大的值和标签
        # print('label', correct_label)
        correct_num = (correct_label == batch_y).sum()
        testAcc += correct_num.item()  

    testAcc = testAcc / float(MNISTtestData.test_labels.size(0))

    print('----------------test: Epoch [%d/%d] Acc: %.4f' % (epoch + 1, EPOCH,  testAcc))
    
    if VISDOM:
        vis.line(X=torch.Tensor([epoch + 1]), \
                 Y=torch.Tensor([testAcc * 100]),  win='testAcc',  update='append')
        vis.line(X=torch.Tensor([epoch + 1]),\
                     Y=torch.Tensor([loss]), win='testLoss', update='append')
        
    if epoch % 25 == 0:
        torch.save(myLeNet, './ModelBackup/MNIST_lenet_model_%d_%f.pkl'%(epoch, testAcc))

修改记录

TimeNoteAuthor
19.4.11原始版本Yooo_Hu
19.4.12添加模型实测部分Yooo_Hu
  • 11
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
以下是基于PyTorchMNIST手写数字识别的步骤: 1.导入必要的库 ```python import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader from torchvision import datasets, transforms ``` 2.定义数据预处理操作 ```python transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ]) ``` 3.加载数据集 ```python train_data = datasets.MNIST(root='data', train=True, download=True, transform=transform) test_data = datasets.MNIST(root='data', train=False, download=True, transform=transform) ``` 4.定义数据加载器 ```python batch_size = 64 train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True) test_loader = DataLoader(test_data, batch_size=batch_size, shuffle=True) ``` 5.定义模型 ```python class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(1, 32, kernel_size=3, padding=1) self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1) self.dropout1 = nn.Dropout2d(0.25) self.dropout2 = nn.Dropout2d(0.5) self.fc1 = nn.Linear(64*7*7, 128) self.fc2 = nn.Linear(128, 10) def forward(self, x): x = nn.functional.relu(self.conv1(x)) x = nn.functional.relu(self.conv2(x)) x = nn.functional.max_pool2d(x, 2) x = self.dropout1(x) x = torch.flatten(x, 1) x = nn.functional.relu(self.fc1(x)) x = self.dropout2(x) x = self.fc2(x) return nn.functional.log_softmax(x, dim=1) model = Net() ``` 6.定义优化器和损失函数 ```python learning_rate = 0.01 optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=0.5) criterion = nn.CrossEntropyLoss() ``` 7.训练模型 ```python epochs = 10 for epoch in range(epochs): for batch_idx, (data, target) in enumerate(train_loader): optimizer.zero_grad() output = model(data) loss = criterion(output, target) loss.backward() optimizer.step() if batch_idx % 100 == 0: print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( epoch, batch_idx*len(data), len(train_loader.dataset), 100.*batch_idx/len(train_loader), loss.item())) ``` 8.测试模型 ```python test_loss = 0 correct = 0 with torch.no_grad(): for data, target in test_loader: output = model(data) test_loss += criterion(output, target).item() pred = output.data.max(1, keepdim=True)[1] correct += pred.eq(target.data.view_as(pred)).sum() test_loss /= len(test_loader.dataset) accuracy = 100. * correct / len(test_loader.dataset) print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format( test_loss, correct, len(test_loader.dataset), accuracy)) ``` 这就是基于PyTorchMNIST手写数字识别的步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值