更新至 2018-8-30 版本
本指南训练一个神经网络模型,对运动鞋和衬衫等服装图像进行分类。如果你不了解所有细节也没关系,这是一个完整的 TensorFlow 程序的快速概览。
本指南使用 tf.keras,一个高级API,用于在 TensorFlow 中构建和训练模型。
# TensorFlow 和 tf.keras
import tensorflow as tf
from tensorflow import keras
# 相关库
import numpy as np
import matplotlib.pyplot as plt
print(tf.__version__)
1.10.0
导入 Fashion MNIST 数据集
本指南使用 Fashion MNIST 数据集,该数据集包含 10 个类别中的 70,000 张灰度图像。下图显示了低分辨率(28 x 28 像素)的单件服装:
Fashion MNIST 旨在作为经典 MNIST 数据集的直接替代品,MNIST 通常用作计算机视觉机器学习程序的“Hello,World”。MNIST 数据集包含手写数字(0、1、2 等)的图像,其格式与我们在此处使用的服装格式相同。
Fashion MNIST 具有多样性,且比普通的 MNIST 更具挑战性。两个数据集都相对较小,用于验证算法是否按预期工作。它们是测试和调试代码的良好起点。
我们将使用 60,000 张图像来训练网络,10,000 张图像来评估学习对图像进行分类的网络的准确性。你可以直接从 TensorFlow 访问 Fashion MNIST,只需导入并加载数据:
fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-labels-idx1-ubyte.gz
32768/29515 [=================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz
26427392/26421880 [==============================] - 1s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz
8192/5148 [===============================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz
4423680/4422102 [==============================] - 0s 0us/step
加载数据集将返回四个 NumPy 数组:
train_images
和train_labels
数组为训练集 —— 模型用来学习的数据。- 模型使用测试集 ——
test_images
和test_labels
数组 —— 测试模型。
图像是 28 x 28 NumPy 数组,像素值在 0 到 255 之间。标签是一个整数数组,范围从 0 到 9。标签对应于图像所代表的服装类别:
标签 | 类别 |
---|---|
0 | T-恤 |
1 | 裤子 |
2 | 套衫 |
3 | 连衣裙 |
4 | 大衣 |
5 | 凉鞋 |
6 | 衬衫 |
7 | 运动鞋 |
8 | 手提包 |
9 | 踝靴 |
每个图像都映射到一个标签。由于类名不包含在数据集中,因此将它们存储在列表以便在绘制图像时使用:
class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
探索数据
让我们在训练模型之前探索数据集的格式。下例显示训练集中有 60,000 张图像,每张图像为 28 x 28 像素:
train_images.shape
(60000, 28, 28)
同样,训练集中有 60,000 个标签:
len(train_labels)
60000
每个标签都是 0 到 9 之间的整数:
train_labels
array([9, 0, 0, ..., 3, 0, 5], dtype=uint8)
测试集中有 10,000 张图像。同样,每张图像为 28 x 28 像素:
test_images.shape
(10000, 28, 28)
测试集包含 10,000 个图像标签:
len(test_labels)
10000
预处理数据
在训练网络之前,必须对数据进行预处理。如果你检查训练集中的第一个图像,你将看到像素值位于 0 到 255 之间:
plt.figure()
plt.imshow(train_images[0])
plt.colorbar()
plt.grid(False)
在将数据送入神经网络模型之前,我们将这些值缩放至 0 到 1 的范围。先将图像的数据类型从整数转换为浮点数,并除以255。
这是预处理图像的功能,以同样的方式对训练集和测试集进行预处理非常重要:
train_images = train_images / 255.0
test_images = test_images / 255.0
显示训练集中的前 25 张图像,并在每个图像下方显示类名。验证数据格式是否正确,以及是否已准备好构建和训练网络。
plt.figure(figsize=(10,10))
for i in range(25):
plt.subplot(5,5,i+1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(train_images[i], cmap=plt.cm.binary)
plt.xlabel(class_names[train_labels[i]])
建立模型
构建神经网络需要配置模型的网络层,然后编译模型。
设置网络层
神经网络的基本构造块是网络层。网络层从提供给它们的数据中提取表征,这些表征对于手头的问题更有意义。
大多数深度学习包括将简单网络层链接在一起。大多数网络层,像 tf.keras.layers.Dense
都具有在训练期间需要学习的参数。
model = keras.Sequential([
keras.layers.Flatten(input_shape=(28, 28)),
keras.layers.Dense(128, activation=tf.nn.relu),
keras.layers.Dense(10, activation=tf.nn.softmax)
])
该网络中的第一层,tf.keras.layers.Flatten
,将图像的格式从 2 维数组(28 x 28 像素)转换为 28 * 28 = 784 像素的一维数组。该网络层将图像像素去堆叠,并进行排列。该层没有要学习的参数,它只重新格式化数据。
在像素展开为一维之后,网络由两层 tf.keras.layers.Dense
序列组成。这些是密集连接或全连接的神经网络层。第一 Dense
层有 128 个节点(或神经元)。第二(最后)层是一个 10 节点的 softmax 层 —— 返回 10 个概率分数的数组,其总和为1。每个节点包含指示当前图像属于 10 个类之一的概率的分数。
编译模型
在对模型进行训练之前,需要一些设置。这些是在模型的编译步骤中添加的:
- 损失函数(Loss function)—— 衡量模型在训练过程中的准确性。我们希望最小化此函数,以便在正确的方向上“引导”模型。
- 优化器(Optimizer)—— 基于数据以及损失函数更新模型的方式。
- 指标(Metrics)—— 监控训练和测试步骤。以下示例使用 accuracy,即正确分类的图像比例。
model.compile(optimizer=tf.train.AdamOptimizer(),
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
训练模型
训练神经网络模型需要以下步骤:
- 将训练数据送入模型 —— 在此示例中为
train_images
和train_labels
数组。 - 模型学习关联图像和标签。
- 使用模型对测试集进行预测 —— 在此示例中为
test_images
数组。验证预测结果是否与test_labels
数组中的标签匹配。
要开始训练,需要调用 model.fit
方法:
model.fit(train_images, train_labels, epochs=5)
Epoch 1/5
60000/60000 [==============================] - 2s 37us/step - loss: 0.4942 - acc: 0.8255
Epoch 2/5
60000/60000 [==============================] - 2s 34us/step - loss: 0.3723 - acc: 0.8656
Epoch 3/5
60000/60000 [==============================] - 2s 37us/step - loss: 0.3333 - acc: 0.8794
Epoch 4/5
60000/60000 [==============================] - 2s 35us/step - loss: 0.3099 - acc: 0.8861
Epoch 5/5
60000/60000 [==============================] - 2s 35us/step - loss: 0.2938 - acc: 0.8918
模型训练时,显示损失和准确率指标。该模型在训练数据上达到约 0.88(或 88%)的准确率。
评估准确率
接下来,比较模型在测试数据集上的性能:
test_loss, test_acc = model.evaluate(test_images, test_labels)
print('Test accuracy:', test_acc)
10000/10000 [==============================] - 0s 20us/step
Test accuracy: 0.8741
事实证明,模型在测试集上的准确率略低于训练集的准确率。训练准确率和测试准确率之间的差距是过拟合的一个例子。过拟合是指机器学习模型在新数据上的表现比在训练数据上表现得更差。
作出预测
我们可以使用训练之后的模型来预测某些图像。
predictions = model.predict(test_images)
模型已经预测了测试集中每个图像的标签。我们来看看第一个预测结果:
predictions[0]
array([1.2189614e-05, 9.8493892e-08, 2.6474936e-06, 4.6750273e-08,
2.2893637e-07, 4.9046555e-04, 4.9265759e-06, 9.2500690e-03,
2.6400221e-05, 9.9021286e-01], dtype=float32)
预测结果是 10 个数字的数组。这描述了模型的“自信程度”,图像对应于 10 种不同服装中的一种。我们可以看到哪个标签具有最高的置信度:
np.argmax(predictions[0])
9
因此,该模型最有信心这个图像是踝靴,或是 class_names[9]
。我们可以检查测试标签,看看这是否正确:
test_labels[0]
9
我们可以绘制出图像来看看全部 10 个通道。
def plot_image(i, predictions_array, true_label, img):
predictions_array, true_label, img = predictions_array[i], true_label[i], img[i]
plt.grid(False)
plt.xticks([])
plt.yticks([])
plt.imshow(img, cmap=plt.cm.binary)
predicted_label = np.argmax(predictions_array)
if predicted_label == true_label:
color = 'blue'
else:
color = 'red'
plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
100*np.max(predictions_array),
class_names[true_label]),
color=color)
def plot_value_array(i, predictions_array, true_label):
predictions_array, true_label = predictions_array[i], true_label[i]
plt.grid(False)
plt.xticks([])
plt.yticks([])
thisplot = plt.bar(range(10), predictions_array, color="#777777")
plt.ylim([0, 1])
predicted_label = np.argmax(predictions_array)
thisplot[predicted_label].set_color('red')
thisplot[true_label].set_color('blue')
查看第一张图像(索引为 0)、预测结果和预测数组。
i = 0
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions, test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions, test_labels)
i = 12
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions, test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions, test_labels)
让我们绘制更多的图像。正确的预测标签标记为蓝色,错误的预测标签标记为红色。数字表示对预测标签的自信百分比。注意,即使预测很自信,结果也可能是错的。
# 绘制前 X 张测试图像、预测标签和真实标签
# 蓝色为正确预测,红色为错误预测
num_rows = 5
num_cols = 3
num_images = num_rows*num_cols
plt.figure(figsize=(2*2*num_cols, 2*num_rows))
for i in range(num_images):
plt.subplot(num_rows, 2*num_cols, 2*i+1)
plot_image(i, predictions, test_labels, test_images)
plt.subplot(num_rows, 2*num_cols, 2*i+2)
plot_value_array(i, predictions, test_labels)
最后,使用训练的模型对单个图像进行预测。
# 从测试数据集中选出一张图像
img = test_images[0]
print(img.shape)
(28, 28)
tf.keras
模型被优化为一次性对样本的批量或集合进行预测。因此,即使我们使用单个图像,我们也需要将其添加到列表中:
# 添加图像至批量
img = (np.expand_dims(img,0))
print(img.shape)
(1, 28, 28)
现在预测图像:
predictions_single = model.predict(img)
print(predictions_single)
[[1.2189591e-05 9.8493892e-08 2.6474886e-06 4.6750095e-08 2.2893614e-07
4.9046462e-04 4.9265759e-06 9.2500662e-03 2.6400170e-05 9.9021286e-01]]
plot_value_array(0, predictions_single, test_labels)
_ = plt.xticks(range(10), class_names, rotation=45)
model.predict
返回一个列表集,一个列表对应一批量数据中的一个图像。获取批量中图像的预测:
np.argmax(predictions_single[0])
9
和以前一样,模型预测标签为 9。