设为首页收藏本站

安徽论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 11310|回复: 0

Python实战之MNIST手写数字识别详解

[复制链接]

110

主题

0

回帖

342

积分

中级会员

Rank: 3Rank: 3

积分
342
发表于 2022-3-26 11:01:23 | 显示全部楼层 |阅读模式
网站内容均来自网络,本站只提供信息平台,如有侵权请联系删除,谢谢!
目录


数据集介绍

MNIST数据集是机器学习领域中非常经典的一个数据集,由60000个训练样本和10000个测试样本组成,每个样本都是一张28 * 28像素的灰度手写数字图片,且内置于keras。本文采用Tensorflow下Keras(Keras中文文档)神经网络API进行网络搭建。
开始之前,先回忆下机器学习的通用工作流程( √表示本文用到,×表示本文没有用到 )
1.定义问题,收集数据集(√)
2.选择衡量成功的指标(√)
3.确定评估的方法(√)
4.准备数据(√)
5.开发比基准更好的模型(×)
6.扩大模型规模(×)
7.模型正则化与调节参数(×)
关于最后一层激活函数与损失函数的选择

下面开始正文~

1.数据预处理

首先导入数据,要使用mnist.load()函数
我们来看看它的源码声明:
  1. def load_data(path='mnist.npz'):
  2.   """Loads the [MNIST dataset](http://yann.lecun.com/exdb/mnist/).

  3.   This is a dataset of 60,000 28x28 grayscale images of the 10 digits,
  4.   along with a test set of 10,000 images.
  5.   More info can be found at the
  6.   [MNIST homepage](http://yann.lecun.com/exdb/mnist/).


  7.   Arguments:
  8.       path: path where to cache the dataset locally
  9.           (relative to `~/.keras/datasets`).

  10.   Returns:
  11.       Tuple of Numpy arrays: `(x_train, y_train), (x_test, y_test)`.
  12.       **x_train, x_test**: uint8 arrays of grayscale image data with shapes
  13.         (num_samples, 28, 28).

  14.       **y_train, y_test**: uint8 arrays of digit labels (integers in range 0-9)
  15.         with shapes (num_samples,).
  16.   """
复制代码
可以看到,里面包含了数据集的下载链接,以及数据集规模、尺寸以及数据类型的声明,且函数返回的是四个numpy array组成的两个元组。
导入数据集并reshape至想要形状,再标准化处理。
其中内置于keras的to_categorical()就是one-hot编码——将每个标签表示为全零向量,只有标签索引对应的元素为1.
eg: col=10
  1. [0,1,9]-------->[ [1,0,0,0,0,0,0,0,0,0],
  2.                   [0,1,0,0,0,0,0,0,0,0],
  3.                   [0,0,0,0,0,0,0,0,0,1] ]        
复制代码
我们可以手动实现它:
  1. def one_hot(sequences,col):
  2.         resuts=np.zeros((len(sequences),col))
  3.         # for i,sequence in enumerate(sequences):
  4.         #         resuts[i,sequence]=1
  5.         for i in range(len(sequences)):
  6.                 for j in range(len(sequences[i])):
  7.                         resuts[i,sequences[i][j]]=1
  8.         return resuts
复制代码
下面是预处理过程
  1. def data_preprocess():
  2.     (train_images, train_labels), (test_images, test_labels) = mnist.load_data()
  3.     train_images = train_images.reshape((60000, 28, 28, 1))
  4.     train_images = train_images.astype('float32') / 255
  5.     #print(train_images[0])
  6.     test_images = test_images.reshape((10000, 28, 28, 1))
  7.     test_images = test_images.astype('float32') / 255

  8.     train_labels = to_categorical(train_labels)
  9.     test_labels = to_categorical(test_labels)
  10.     return train_images,train_labels,test_images,test_labels
复制代码
2.网络搭建

这里我们搭建的是卷积神经网络,就是包含一些卷积、池化、全连接的简单线性堆积。我们知道多个线性层堆叠实现的仍然是线性运算,添加层数并不会扩展假设空间(从输入数据到输出数据的所有可能的线性变换集合),因此需要添加非线性或激活函数。relu是最常用的激活函数,也可以用prelu、elu
  1. def build_module():
  2.     model = models.Sequential()
  3.     #第一层卷积层,首层需要指出input_shape形状
  4.     model.add(layers.Conv2D(32, (3,3), activation='relu', input_shape=(28,28,1)))
  5.     #第二层最大池化层
  6.     model.add(layers.MaxPooling2D((2,2)))
  7.     #第三层卷积层
  8.     model.add(layers.Conv2D(64, (3,3), activation='relu'))
  9.     #第四层最大池化层
  10.     model.add(layers.MaxPooling2D((2,2)))
  11.     #第五层卷积层
  12.     model.add(layers.Conv2D(64, (3,3), activation='relu'))
  13.     #第六层Flatten层,将3D张量平铺为向量
  14.     model.add(layers.Flatten())
  15.     #第七层全连接层
  16.     model.add(layers.Dense(64, activation='relu'))
  17.     #第八层softmax层,进行分类
  18.     model.add(layers.Dense(10, activation='softmax'))
  19.     return model
复制代码
使用model.summary()查看搭建的网路结构:


3.网络配置

网络搭建好之后还需要关键的一步设置配置。比如:优化器——网络梯度下降进行参数更新的具体方法、损失函数——衡量生成值与目标值之间的距离、评估指标等。配置这些可以通过 model.compile() 参数传递做到。
我们来看看model.compile()的源码分析下:
  1.   def compile(self,
  2.               optimizer='rmsprop',
  3.               loss=None,
  4.               metrics=None,
  5.               loss_weights=None,
  6.               weighted_metrics=None,
  7.               run_eagerly=None,
  8.               steps_per_execution=None,
  9.               **kwargs):
  10.     """Configures the model for training.
复制代码


关于优化器

优化器:字符串(优化器名称)或优化器实例。
字符串格式:比如使用优化器的默认参数
实例优化器进行参数传入:
  1. keras.optimizers.RMSprop(lr=0.001, rho=0.9, epsilon=None, decay=0.0)
  2. model.compile(optimizer='rmsprop',loss='mean_squared_error')
复制代码
建议使用优化器的默认参数 (除了学习率 lr,它可以被自由调节)
参数:
  1. lr: float >= 0. 学习率。
  2. rho: float >= 0. RMSProp梯度平方的移动均值的衰减率.
  3. epsilon: float >= 0. 模糊因子. 若为 None, 默认为 K.epsilon()。
  4. decay: float >= 0. 每次参数更新后学习率衰减值。
复制代码
类似还有好多优化器,比如SGD、Adagrad、Adadelta、Adam、Adamax、Nadam等

关于损失函数

取决于具体任务,一般来说损失函数要能够很好的刻画任务。比如
1.回归问题
希望神经网络输出的值与ground-truth的距离更近,选取能刻画距离的loss应该会更合适,比如L1 Loss、MSE Loss等
2.分类问题
希望神经网络输出的类别与ground-truth的类别一致,选取能刻画类别分布的loss应该会更合适,比如cross_entropy
具体常见选择可查看文章开始处关于损失函数的选择

关于指标

常规使用查看上述列表即可。下面说说自定义评价函数:它应该在编译的时候(compile)传递进去。该函数需要以 (y_true, y_pred) 作为输入参数,并返回一个张量作为输出结果。
  1. import keras.backend as K
  2. def mean_pred(y_true, y_pred):
  3.     return K.mean(y_pred)

  4. model.compile(optimizer='rmsprop',
  5.               loss='binary_crossentropy',
  6.               metrics=['accuracy', mean_pred])
复制代码
4.网络训练与测试

1.训练(拟合)
使用model.fit(),它可以接受的参数列表
  1. def fit(self,
  2.           x=None,
  3.           y=None,
  4.           batch_size=None,
  5.           epochs=1,
  6.           verbose=1,
  7.           callbacks=None,
  8.           validation_split=0.,
  9.           validation_data=None,
  10.           shuffle=True,
  11.           class_weight=None,
  12.           sample_weight=None,
  13.           initial_epoch=0,
  14.           steps_per_epoch=None,
  15.           validation_steps=None,
  16.           validation_batch_size=None,
  17.           validation_freq=1,
  18.           max_queue_size=10,
  19.           workers=1,
  20.           use_multiprocessing=False):
复制代码
这个源码有300多行长,具体的解读放在下次。
我们对训练数据进行划分,以64个样本为小批量进行网络传递,对所有数据迭代5次
  1. model.fit(train_images, train_labels, epochs = 5, batch_size=64)
复制代码
2.测试

使用model.evaluates()函数
  1. test_loss, test_acc = model.evaluate(test_images, test_labels)
复制代码
关于测试函数的返回声明:
  1. Returns:
  2.         Scalar test loss (if the model has a single output and no metrics)
  3.         or list of scalars (if the model has multiple outputs
  4.         and/or metrics). The attribute `model.metrics_names` will give you
  5.         the display labels for the scalar outputs.
复制代码
5.绘制loss和accuracy随着epochs的变化图

model.fit()返回一个History对象,它包含一个history成员,记录了训练过程的所有数据。
我们采用matplotlib.pyplot进行绘图,具体见后面完整代码。
  1. Returns:
  2.         A `History` object. Its `History.history` attribute is
  3.         a record of training loss values and metrics values
  4.         at successive epochs, as well as validation loss values
  5.         and validation metrics values (if applicable).
复制代码
  1. def draw_loss(history):
  2.     loss=history.history['loss']
  3.     epochs=range(1,len(loss)+1)
  4.     plt.subplot(1,2,1)#第一张图
  5.     plt.plot(epochs,loss,'bo',label='Training loss')
  6.     plt.title("Training loss")
  7.     plt.xlabel('Epochs')
  8.     plt.ylabel('Loss')
  9.     plt.legend()

  10.     plt.subplot(1,2,2)#第二张图
  11.     accuracy=history.history['accuracy']
  12.     plt.plot(epochs,accuracy,'bo',label='Training accuracy')
  13.     plt.title("Training accuracy")
  14.     plt.xlabel('Epochs')
  15.     plt.ylabel('Accuracy')
  16.     plt.suptitle("Train data")
  17.     plt.legend()
  18.     plt.show()
复制代码
6.完整代码
  1. from tensorflow.keras.datasets import mnistfrom tensorflow.keras import modelsfrom tensorflow.keras import layersfrom tensorflow.keras.utils import to_categoricalimport matplotlib.pyplot as pltimport numpy as npdef data_preprocess():
  2.     (train_images, train_labels), (test_images, test_labels) = mnist.load_data()
  3.     train_images = train_images.reshape((60000, 28, 28, 1))
  4.     train_images = train_images.astype('float32') / 255
  5.     #print(train_images[0])
  6.     test_images = test_images.reshape((10000, 28, 28, 1))
  7.     test_images = test_images.astype('float32') / 255

  8.     train_labels = to_categorical(train_labels)
  9.     test_labels = to_categorical(test_labels)
  10.     return train_images,train_labels,test_images,test_labels#搭建网络def build_module():    model = models.Sequential()    #第一层卷积层    model.add(layers.Conv2D(32, (3,3), activation='relu', input_shape=(28,28,1)))    #第二层最大池化层    model.add(layers.MaxPooling2D((2,2)))    #第三层卷积层    model.add(layers.Conv2D(64, (3,3), activation='relu'))    #第四层最大池化层    model.add(layers.MaxPooling2D((2,2)))    #第五层卷积层    model.add(layers.Conv2D(64, (3,3), activation='relu'))    #第六层Flatten层,将3D张量平铺为向量    model.add(layers.Flatten())    #第七层全连接层    model.add(layers.Dense(64, activation='relu'))    #第八层softmax层,进行分类    model.add(layers.Dense(10, activation='softmax'))    return modeldef draw_loss(history):
  11.     loss=history.history['loss']
  12.     epochs=range(1,len(loss)+1)
  13.     plt.subplot(1,2,1)#第一张图
  14.     plt.plot(epochs,loss,'bo',label='Training loss')
  15.     plt.title("Training loss")
  16.     plt.xlabel('Epochs')
  17.     plt.ylabel('Loss')
  18.     plt.legend()

  19.     plt.subplot(1,2,2)#第二张图
  20.     accuracy=history.history['accuracy']
  21.     plt.plot(epochs,accuracy,'bo',label='Training accuracy')
  22.     plt.title("Training accuracy")
  23.     plt.xlabel('Epochs')
  24.     plt.ylabel('Accuracy')
  25.     plt.suptitle("Train data")
  26.     plt.legend()
  27.     plt.show()if __name__=='__main__':    train_images,train_labels,test_images,test_labels=data_preprocess()    model=build_module()    print(model.summary())    model.compile(optimizer='rmsprop', loss = 'categorical_crossentropy', metrics=['accuracy'])    history=model.fit(train_images, train_labels, epochs = 5, batch_size=64)    draw_loss(history)    test_loss, test_acc = model.evaluate(test_images, test_labels)    print('test_loss=',test_loss,'  test_acc = ', test_acc)
复制代码
迭代训练过程中loss和accuracy的变化


由于数据集比较简单,随便的神经网络设计在测试集的准确率可达到99.2%
以上就是Python实战之MNIST手写数字识别详解的详细内容,更多关于Python MNIST手写数字识别的资料请关注脚本之家其它相关文章!
                                                        
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
免责声明
1. 本论坛所提供的信息均来自网络,本网站只提供平台服务,所有账号发表的言论与本网站无关。
2. 其他单位或个人在使用、转载或引用本文时,必须事先获得该帖子作者和本人的同意。
3. 本帖部分内容转载自其他媒体,但并不代表本人赞同其观点和对其真实性负责。
4. 如有侵权,请立即联系,本网站将及时删除相关内容。
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表