《Deep Learning with Python》第二章 2.1 神经网络的MNIST手写数字识别

第二章 神经网络的数学基础

本章涉及的知识点:

  • 神经网络的MNIST手写数字识别(概览)
  • 张量(Tensor)和张量操作
  • 如何通过后向传播和梯度下降进行神经网络学习

理解深度学习要求熟悉许多简单的数学概念:张量,张量操作,微分,梯度下降等等。本章目的是让读者对这些概念有个大体的认识。

这里以一个实际的神经网络例子为开头,增加一些张量和梯度下降背景的了解。然后一点点的介绍新概念。记住,这些概念对理解后续章节的例子有帮助。

读完本章后,你将对神经网络的工作原理有个直观的认识。神经网络的应用实践将在第三章详细讲解。

2.1 神经网络的MNIST手写数字识别

第一个具体的神经网络例子是,使用Keras(Python库)学习手写数字分类。如果对Keras或者类似的库没有什么经验,那么你可能无法立即搞懂该例子的所有步骤。可能你压根还没安装Keras,那也没关系咯。下一章会详细讲解该例子的每一步。所以,不用担心啦,准备开始了。

解决的问题:识别灰度的手写数字图片(28 x 28)的数字(0到9)。本例使用机器学习经典的MNIST手写数字数据集,包含60000张训练图片饿10000张测试图片。它是NIST(National Institute of Standards and Technology)数据库的子集,建立于1980年代。你可以把“MNIST手写数字识别”看成是深度学习的“Hello World”,其可以验证算法的正确性。如果成为机器学习工作者,你将会在科学论文、博客等上不断地看到它。图2.1 是MNIST数据集的图片。

image

图2.1 MNIST手写数字图片

类(class)和标签(label)的区别

在机器学习中,分类问题中的一个类别称之为类(class);数据点称为样本;类关联的具体样本称为标签(label)。

你不需要立即重现本例,下一章3.3小结将会使用Keras。

Keras会预加载MNIST数据集,得到的是四个Numpy数组:

1
2
3
#Listing 2.1. Loading the MNIST dataset in Keras
from keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

train_imagestrain_labels形成训练数据集。test_imagestest_labels形成测试数据集。图片由NUmpy数组组成,标签是一个数字数组,范围是0到9。图片和标签是一一对应的。

下面看下训练数据:

1
2
3
4
5
6
>>> train_images.shape
(60000, 28, 28)
>>> len(train_labels)
60000
>>> train_labels
array([5, 0, 4, ..., 5, 6, 8], dtype=uint8)

接着是测试数据:

1
2
3
4
5
6
>>> test_images.shape
(10000, 28, 28)
>>> len(test_labels)
10000
>>> test_labels
array([7, 2, 1, ..., 4, 5, 6], dtype=uint8)

接下来的流程是:首先,将训练数据(train_imagestrain_labels)赋值给神经网络模型;然后神经网络学习图片及相应的标签;最后训练好的模型输入测试图片test_images进行预测,并用test_labels验证预测值。

下面构建神经网络:

1
2
3
4
5
6
7
#Listing 2.2. The network architecture
from keras import models
from keras import layers
network = models.Sequential()
network.add(layers.Dense(512, activation='relu', input_shape=(28 * 28,)))
network.add(layers.Dense(10, activation='softmax'))

神经网络的核心基础组件是层(layer),它是数据处理模块,可以认为是数据的过滤器(filter)。训练数据进入layer输出有用的形式,具体地说,layer抽取训练数据的学习特征。希望的是学习表征可以有效地解决问题。大部分深度学习包含多个layer形成链式,不断地进行数据提取。深度学习模型由一系列连续的数据过滤器(layer)提炼数据。

本例中的神经网络由两个稠密层(Dense layer)序列组成,其中稠密层也称为全联接层(*fully connected layer)。第二层是个softmax layer,它将输出一个包含10个概率的数组(概率之和为1)。每个概率值表示当前的数字图片属于10个数字分类中某一个的概率。

准备训练的步骤,下面是模型编译步骤(compilation step)中的三步:

  • 损失函数:度量神经网络模型在训练数据集上的性能,使得其向正确的方向迭代。
  • 优化器:基于训练数据和损失函数调整模型的机制。
  • 模型训练和测试的监控指标:本例只关注准确度(正确分类的图片比例)。

后续两章会清晰的讲解损失函数和优化器的功能:

1
2
3
4
#Listing 2.3. The compilation step
network.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])

在模型训练之前进行数据预处理,将数据集按神经网络模型的要求重塑(即,改变大小形状),并归一化到[0, 1]区间。例如,前面训练图片存储为(60000, 28, 28)维德数组,数值类型为uint8,其大小为[0, 255]。这里将其转换成值为0到1的float32类型的(60000, 28 * 28) 维数据。

1
2
3
4
5
6
#Listing 2.4. Preparing the image data
train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype('float32') / 255
test_images = test_images.reshape((10000, 28 * 28))
test_images = test_images.astype('float32') / 255

下面对标签进行编码,具体解释将在第三章给出:

1
2
3
4
5
#Listing 2.5. Preparing the labels
from keras.utils import to_categorical
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)

Keras调用fit方法开始训练神经网络模型:

1
2
3
4
5
>>> network.fit(train_images, train_labels, epochs=5, batch_size=128)
Epoch 1/5
60000/60000 [==============================] - 9s - loss: 0.2524 - acc: 0.9273
Epoch 2/5
51328/60000 [========================>.....] - ETA: 1s - loss: 0.1035 - acc: 0.9692

上面显示的两个数字是训练神经网络模型时的损失值和准确度。

可以看到,很快在训练数据上达到0.989 (98.9%) 的准确度。下面在测试数据集上验证模型的性能:

1
2
3
>>> test_loss, test_acc = network.evaluate(test_images, test_labels)
>>> print('test_acc:', test_acc)
test_acc: 0.9785

测试数据集上的准确度为97.8%,比训练数据集上的小一点。训练数据集上的准确度和测试数据集上的差距意味着过拟合,机器学习模型在新数据集上的效果比训练数据集的差。过拟合将在第三章详细讲解。

从上面可以看到:只用不到20行Python代码实现构建和训练一个神经网络模型来进行手写数字图片识别。下一小结,你将学习张量(,神经网络的数据存储对象),张量操作,梯度下降。

未完待续。。。

Enjoy!

翻译本书系列的初衷是,觉得其中把深度学习讲解的通俗易懂。不光有实例,也包含作者多年实践对深度学习概念、原理的深度理解。最后说不重要的一点,François Chollet是Keras作者。
声明本资料仅供个人学习交流、研究,禁止用于其他目的。如果喜欢,请购买英文原版。


侠天,专注于大数据、机器学习和数学相关的内容,并有个人公众号:bigdata_ny分享相关技术文章。

若发现以上文章有任何不妥,请联系我。

image