分类
机器学习及应用

深度学习:基于mxnet的mnist手写数字识别

(在苹果系统下,如果文章中的图片不能正常显示,请升级Safari浏览器到最新版本,或者使用Chrome、Firefox浏览器打开。)

mnist手写数字识别是入门深度学习,或者学习一个新的深度学习框架时,最容易上手的程序。本文中,我将使用mxnet深度学习框架在mnist数据集上实现一个简单的手写数字识别模型。

整个程序的代码思路来源于GitHub 上别人的一个小项目,并使用mxnet框架复现了一遍:

https://gist.github.com/alexcpn/0683bb940cae510cf84d5976c1652abd

运行环境

运行软件

Python3

依赖包

  • mxnet
  • numpy
  • pandas
  • matplotlib
  • time (默认自带)
  • random (默认自带)

代码讲解

依赖包导入

from mxnet import gluon, init, nd, autograd
from mxnet.gluon import nn, utils as gutils
from mxnet.gluon import loss as gloss
import mxnet as mx
import time
import numpy as np
import random
import matplotlib.pyplot as plt
import pandas as pd

基础配置

np.random.seed(123) #设置随机数种子
use_gpu = False #指示是否使用GPU,当使用GPU时应设为True

导入数据

数据集的下载请点击这里(mnist.npz)

def load_data(path='mnist.npz'): # 读入本地文件
    f = np.load(path)
    x_train, y_train = f['x_train'], f['y_train']
    x_test, y_test = f['x_test'], f['y_test']
    f.close()
    return (x_train, y_train), (x_test, y_test)
# 将数据读入
(X_train, y_train), (X_test, y_test) = load_data()

# 查看一下数据的格式,输入输出维度
print(X_train.shape,y_train.shape,X_test.shape,y_test.shape)

数据可视化

有时候,为了方便,或者更直观,我们往往需要将数据可视化。对于图像数据来说,可视化就是家常便饭了,而且也是最容易可视化的一类数据之一。这里我们使用到一个强大的绘图库matplotlib,同样,做过数学建模以及仿真的应该都用过这类库,尤其是用过matlab的话。

plt.subplot(221)
print(y_train[4545],y_train[1],y_train[2],y_train[3])
plt.imshow(X_train[4545], cmap=plt.get_cmap('gray'))
plt.subplot(222)
plt.imshow(X_train[1], cmap=plt.get_cmap('gray'))
plt.subplot(223)
plt.imshow(X_train[2], cmap=plt.get_cmap('gray'))
plt.subplot(224)
plt.imshow(X_train[3], cmap=plt.get_cmap('gray'))
# show the plot
plt.show()

数据预处理

往往我们拿到的数据,都需要进行一些处理,在不同的场景下,有不同的处理方法。这里的mnist数据集是已经处理过的,我们只需要将其转为我们所需的输入格式即可。这里,我们需要将其转换为mxnet框架运算所需要的nd.array格式。对于数据的10个数字标签,由于mxnet框架提供的损失函数的特性,我们不需要像其他框架那样进行正交化处理。

# 调整shape
X_train = X_train.reshape(X_train.shape[0], 1, 28, 28)
X_test = X_test.reshape(X_test.shape[0], 1, 28, 28)

# 调整数据类型
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
# 归一化
X_train /= 255
X_test /= 255

print(len(y_train),len(y_test))
# 从numpy.array转换为mxnet.nd.array
Y _train = nd.array(y_train)
Y _test = nd.array(y_test)

搭建神经网络模型

net = nn.Sequential()

net.add(nn.Conv2D(channels=32,kernel_size=3,padding=1,strides=1))
net.add(nn.Conv2D(channels=32,kernel_size=3,padding=1,strides=1))
net.add(nn.MaxPool2D(pool_size=(2,2), strides=(2,2)))

net.add(nn.Dense(units=128,activation='relu', flatten=True))
net.add(nn.Dense(units=10, activation='softrelu', flatten=True))

模型训练前的初始化设置

lr=0.001  # 学习率
num_epochs = 1  # 训练轮数
batch_size = 32  # batch大小

if(use_gpu == True):
    ctx = mx.gpu(0)
else:
    ctx = mx.cpu(0)

# 取一个与输入shape一样的随机值
X = nd.random.uniform(shape=(1, 1, 28, 28), ctx=ctx)
# 网络结构初始化
net.initialize(init=init.MSRAPrelu(),ctx=ctx) 
# 进行一次正向传播测试
y = net(X)

# 设置数据加载器
dataset_train = mx.gluon.data.ArrayDataset(X_train, Y_train) # ArrayDataset不需要从硬盘上加载数据
dataset_test = mx.gluon.data.ArrayDataset(X_test, Y_test)

Train_data_loader = gluon.data.DataLoader(dataset_train, batch_size = batch_size)
Test_data_loader = gluon.data.DataLoader(dataset_test, batch_size = batch_size)

# 设置训练器,使用adam优化器
trainer = gluon.Trainer(net.collect_params(), 'adam', {'learning_rate': lr}) 

# 设置损失函数
loss = gloss.SoftmaxCrossEntropyLoss()

Train_Loss = []
Train_Acc = []
Test_Acc = []

# 定义一些模型评估函数
def accuracy(y_hat, y):
    """Get accuracy."""
    return (y_hat.argmax(axis=1) == y.astype('float32')).mean().asscalar()

def evaluate_accuracy(data_loader, net, ctx):
    acc = nd.array([0], ctx=ctx)
    for X, y in data_loader:
        X, y = X.as_in_context(ctx), y.as_in_context(ctx)
        acc += accuracy(net(X), y)
    return acc.asscalar() / len(data_loader)

训练模型

for epoch in range(num_epochs):
  train_l_sum, train_acc_sum, start = 0, 0, time.time()
  count_datatrain = 0
  for X, y in Train_data_loader:
    X, y = X.as_in_context(ctx), y.as_in_context(ctx)
    with autograd.record():
      y_hat = net(X)
      l = loss(y_hat, y)
    l.backward()
    trainer.step(batch_size)
    train_l_sum += l.mean().asscalar()
    train_acc_sum += accuracy(y_hat, y)
    
    count_datatrain += batch_size
    if(count_datatrain % batch_size == 0):
      print('have train',count_datatrain,end='\r')
    
  print('have train',count_datatrain,end='\n')
  test_acc = evaluate_accuracy(Test_data_loader, net, ctx)
  print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f, '
      'time %.1f sec' % (epoch + 1, train_l_sum / len(Train_data_loader),
               train_acc_sum / len(Train_data_loader),
               test_acc, time.time() - start))

  Train_Acc.append(train_acc_sum / len(Train_data_loader))
  Train_Loss.append(train_l_sum / len(Train_data_loader))
  Test_Acc.append(test_acc)

保存模型参数

filename='mnist.model.mxnet'
net.save_parameters(filename)

保存相关实验数据

Temp = []
Data = []
for i in range(len(Train_Acc)):
  Temp.append(Train_Loss[i])
  Temp.append(Train_Acc[i])
  Temp.append(Test_Acc[i])
  Data.append(Temp)
  Temp = []

name=['loss','train_Acc','test_Acc']
test=pd.DataFrame(columns=name,data=Data)#数据有三列
print(test)
test.to_csv('./mnist.csv',encoding='gbk')

实验结果

我们可以在文件目录中看到生成了两个新文件,一个是保存的模型参数文件“mnist.model.mxnet”,另一个是模型评估数据文件“mnist.csv”。

我们用Excel打开生成的mnist.csv文件,可以看到这几项数据:

loss train_Acc test_Acc
0 0.15305 0.9542 0.971046

模型在训练结束后,loss降为0.15305,训练集准确率为95.42%,测试集准确率为97.10%。

版权声明
本博客的文章除特别说明外均为原创,本人版权所有。欢迎转载,转载请注明作者及来源链接,谢谢。
本文地址: https://blog.ailemon.net/2019/06/06/deep-learning-mnist-handwritten-digit-recognition-by-mxnet/
All articles are under Attribution-NonCommercial-ShareAlike 4.0

关注“AI柠檬博客”微信公众号,及时获取你最需要的干货。


发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

5 × 3 =

如果您是第一次在本站发布评论,内容将在博主审核后显示,请耐心等待