文章目录
- 一. 训练Keras中的MNIST数据集
- 二. 工作流程
- 1. 构建神经网络
- 2. 准备图像数据
- 3. 训练模型
- 4. 利用模型进行预测
- 5. (新数据上)评估模型精度
本节将首先给出一个神经网络示例,引出如下概念。了解完本节后,可以对神经网络在代码上的实现有一个整体的了解。
本节相关概念:
- 类
- 样本
- 标签
- 层(layer)
- 数据蒸馏
- 密集连接
- 10路softmax分类层
- 编译(compilation)步骤的3个参数
- 损失值、精度
- 过拟合
我们来看一个神经网络的具体实例:使用Python的Keras库来学习手写数字分类。
在这个例子中,我们要解决的问题是,将手写数字的灰度图像(28像素×28像素)划分到10个类别中(从0到9)。我们将使用MNIST数据集。你可以将“解决”MNIST问题看作深度学习的“Hello World”,用来验证你的算法正在按预期运行。下图给出了MNIST数据集的一些样本。
说明
在机器学习中,分类问题中的
某个类别叫作类(class
),数据点叫作样本(sample)
,与某个样本对应的类叫作标签(label)
(即描述:样本属于哪个类别)。
你不需要现在就尝试在计算机上运行这个例子。之后的文章会具体分析。
一. 训练Keras中的MNIST数据集
from tensorflow.keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
train_images和train_labels组成了训练集,模型将从这些数据中进行学习。然后,我们在测试集(包括test_images和test_labels)上对模型进行测试。
图像被编码为NumPy数组,而标签是一个数字数组,取值范围是0~9。图像和标签一一对应。
看一下训练数据:
>>> train_images.shape
(60000, 28, 28)
>>> len(train_labels)
60000
>>> train_labels
array([5, 0, 4, ..., 5, 6, 8], dtype=uint8)
再来看一下测试数据:
>>> test_images.shape
(10000, 28, 28)
>>> len(test_labels)
10000
>>> test_labels
array([7, 2, 1, ..., 4, 5, 6], dtype=uint8)
二. 工作流程
我们的工作流程如下:
首先,将训练数据(train_images和train_labels)输入神经网络;
然后,神经网络学习将图像和标签关联在一起;
最后,神经网络对test_images进行预测
,我们来验证这些预测与test_labels中的标签是否匹配。
具体的代码我们可以在 deep-learning-with-python-notebooks 中直接运行。
1. 构建神经网络
下面我们来构建神经网络,如下:
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential(
[ layers.Dense(512, activation="relu"),
layers.Dense(10, activation="softmax") ])
神经网络的核心组件是层(layer)
。
具体来说,层从输入数据中提取表示。大多数深度学习工作涉及将简单的层链接起来,从而实现渐进式的数据蒸馏(data distillation)
。深度学习模型就像是处理数据的筛子,包含一系列越来越精细
的数据过滤器(也就是层)。
本例中的模型包含2个Dense层,它们都是密集连接(也叫全连接)
的神经层。
第2层是一个10路softmax分类层,它将返回一个由10个概率值(总和为1)组成的数组。每个概率值表示当前数字图像属于10个数字类别中某一个的概率。
在训练模型之前,我们还需要指定编译(compilation)步骤的3个参数
。
- 优化器(optimizer):模型基于训练数据
来自我更新的机制
,其目的是提高模型性能。- 损失函数(loss function):模型如何衡量在训练数据上的性能,从而引导自己朝着正确的方向前进。
- 在训练和测试过程中需要监控的指标(metric):本例只关心精度(accuracy),即正确分类的图像所占比例。后面两章会详细介绍损失函数和优化器的确切用途。
如下代码展示了编译步骤。
model.compile(
optimizer="rmsprop",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"]
)
2. 准备图像数据
在开始训练之前,我们先对数据进行预处理,将其变换为模型要求的形状,并缩放到所有值都在[0, 1]区间。前面提到过,训练图像保存在一个uint8类型的数组中,其形状为(60000, 28, 28),取值区间为[0,255]。我们将把它变换为一个float32数组,其形状为(60000, 28 *28),取值范围是[0, 1]。
下面准备图像数据,如代码所示。
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
3. 训练模型
在Keras中,通过调用模型的fit方法调用数据,训练模型。
>>> model.fit(train_images, train_labels, epochs=5, batch_size=128)
Epoch 1/5
60000/60000 [===========================] - 5s - loss: 0.2524 - acc: 0.9273 Epoch 2/5
51328/60000 [=====================>.....] - ETA: 1s - loss: 0.1035 - acc: 0.9692
训练过程中显示了两个数字:一个是模型在训练数据上的损失值(loss),另一个是模型在训练数据上的精度(acc)。我们很快就在训练数据上达到了0.989(98.9%)的精度。
现在我们得到了一个训练好的模型,可以利用它来预测新数字图像的类别概率(如下代码)。这些新数字图像不属于训练数据,比如可以是测试集中的数据。
4. 利用模型进行预测
>>> test_digits = test_images[0:10]
>>> predictions = model.predict(test_digits)
>>> predictions[0]
array([1.0726176e-10, 1.6918376e-10, 6.1314843e-08, 8.4106023e-06, 2.9967067e-11, 3.0331331e-09, 8.3651971e-14, 9.9999106e-01, 2.6657624e-08, 3.8127661e-07], dtype=float32)
如上代码我们对11个test_images图片进行预测,是什么数字,我们拿到第一个图片预测的概率数组,其中索引为7时,概率最大(0.99999106,几乎等于1),所以根据我们的模型,这个数字一定是7。
>>> predictions[0].argmax()
7
>>> predictions[0][7]
0.99999106
这里我们检查测试标签是否与之一致:
>>> test_labels[0]
7
平均而言,我们的模型对这种前所未见的数字图像进行分类的效果如何?我们来计算在整个测试集上的平均精度,如下代码所示。
5. (新数据上)评估模型精度
>>> test_loss, test_acc = model.evaluate(test_images, test_labels)
>>> print(f"test_acc: {test_acc}")
test_acc: 0.9785
测试精度约为97.8%,比训练精度(98.9%)低不少。训练精度和测试精度之间的这种差距是过拟合
(overfit)造成的。
过拟合是指机器学习模型在新数据上的性能往往比在训练数据上要差。
第一个例子到这里就结束了。你刚刚看到了如何用不到15行Python代码构建和训练一个神经网络,对手写数字进行分类。
之后的文章我们将详细描述每一个步骤的原理,并且将学到张量(输入模型的数据存储对象)、张量运算(层的组成要素)与梯度下降(可以让模型从训练示例中进行学习)。
参考:
《Python深度学习(第二版)》–弗朗索瓦·肖莱
https://www.redhat.com/zh/topics/digital-transformation/what-is-deep-learning