基础分类:对服装图像进行分类

在 TensorFlow.org 上查看 在 Google Colab 中运行 在 GitHub 上查看源码 下载笔记本

本指南训练了一个神经网络模型来对运动鞋和衬衫等服装图像进行分类。如果您不理解其中的所有细节也没关系;这是一个关于完整 TensorFlow 程序的快速概述,细节会在后续过程中为您讲解。

本指南使用 tf.keras,这是一个用于在 TensorFlow 中构建和训练模型的高级 API。

# TensorFlow and tf.keras
import tensorflow as tf

# Helper libraries
import numpy as np
import matplotlib.pyplot as plt

print(tf.__version__)
2024-08-16 01:20:39.960631: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered
2024-08-16 01:20:39.982110: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered
2024-08-16 01:20:39.988691: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered
2.17.0

导入 Fashion MNIST 数据集

本指南使用 Fashion MNIST 数据集,其中包含 70,000 张灰度图像,涵盖 10 个类别。这些图像展示了低分辨率(28 x 28 像素)的各类服装,如下图所示:

Fashion MNIST sprite
图 1. Fashion-MNIST 样本(由 Zalando 提供,MIT 许可证)。
 

Fashion MNIST 旨在作为经典 MNIST 数据集的直接替代品——MNIST 数据集通常被用作计算机视觉机器学习程序的“Hello, World”。MNIST 数据集包含手写数字(0、1、2 等)图像,其格式与您此处将使用的服装图像格式相同。

本指南使用 Fashion MNIST 是为了多样性,同时也因为它比普通 MNIST 问题稍具挑战性。这两个数据集都相对较小,用于验证算法是否按预期工作。它们是测试和调试代码的良好起点。

在这里,60,000 张图像用于训练网络,10,000 张图像用于评估网络学习对图像进行分类的准确度。您可以直接从 TensorFlow 访问 Fashion MNIST。直接从 TensorFlow 导入并加载 Fashion MNIST 数据

fashion_mnist = tf.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
29515/29515 ━━━━━━━━━━━━━━━━━━━━ 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz
26421880/26421880 ━━━━━━━━━━━━━━━━━━━━ 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz
5148/5148 ━━━━━━━━━━━━━━━━━━━━ 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz
4422102/4422102 ━━━━━━━━━━━━━━━━━━━━ 0s 0us/step

加载数据集会返回四个 NumPy 数组:

  • train_imagestrain_labels 数组是训练集——即模型用来学习的数据。
  • 模型通过测试集(即 test_imagestest_labels 数组)进行测试。

图像是 28x28 的 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)
plt.show()

png

在将这些值馈送到神经网络模型之前,将其缩放到 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]])
plt.show()

png

构建模型

构建神经网络需要配置模型的层,然后编译模型。

设置层

神经网络的基本构建块是层 (layer)。层从馈送给它们的数据中提取表示。希望这些表示对于手头的问题是有意义的。

深度学习的大部分内容是由简单的层串联在一起组成的。大多数层,例如 tf.keras.layers.Dense,都具有在训练期间学习的参数。

model = tf.keras.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(10)
])
/tmpfs/src/tf_docs_env/lib/python3.9/site-packages/keras/src/layers/reshaping/flatten.py:37: UserWarning: Do not pass an `input_shape`/`input_dim` argument to a layer. When using Sequential models, prefer using an `Input(shape)` object as the first layer in the model instead.
  super().__init__(**kwargs)
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
I0000 00:00:1723771245.399945    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771245.403709    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771245.407479    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771245.411239    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771245.422243    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771245.425820    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771245.429273    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771245.432759    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771245.436119    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771245.439570    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771245.443002    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771245.446467    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.712159    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.714268    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.716341    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.718359    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.720355    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.722302    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.724257    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.726181    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.728090    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.730035    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.731978    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.733907    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.773205    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.775242    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.777277    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.779277    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.781323    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.783269    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.785254    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.787201    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.789148    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.792670    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.795758    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723771246.798118    8232 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355

该网络中的第一层 tf.keras.layers.Flatten,将图像格式从二维数组(28 x 28 像素)转换为一维数组(28 * 28 = 784 像素)。可以将此层视为将图像中的像素行“拆开”并排成一行。该层没有要学习的参数;它仅对数据进行格式化。

像素展平后,网络由两个 tf.keras.layers.Dense 层序列组成。这些是密集连接或全连接的神经层。第一个 Dense 层有 128 个节点(或神经元)。第二个(也是最后一个)层返回一个长度为 10 的 logits 数组。每个节点包含一个得分,指示当前图像属于 10 个类别中的哪一个。

编译模型

在模型准备好训练之前,它还需要一些额外的设置。这些设置是在模型的编译 (compile)步骤中添加的:

  • 优化器 (Optimizer) — 这是模型根据所看到的数据及其损失函数进行更新的方式。
  • 损失函数 (Loss function) — 这用于衡量模型在训练期间的准确度。您希望最小化此函数,以“引导”模型朝正确的方向发展。
  • 指标 (Metrics) — 用于监控训练和测试步骤。以下示例使用准确率 (accuracy),即分类正确的图像所占的比例。
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

训练模型

训练神经网络模型需要以下步骤:

  1. 将训练数据馈送到模型中。在此示例中,训练数据位于 train_imagestrain_labels 数组中。
  2. 模型学习建立图像和标签之间的关联。
  3. 要求模型对测试集进行预测——在此示例中为 test_images 数组。
  4. 验证预测是否与 test_labels 数组中的标签匹配。

馈送模型

要开始训练,请调用 model.fit 方法——之所以这样命名,是因为它将模型“拟合 (fit)”到训练数据上。

model.fit(train_images, train_labels, epochs=10)
Epoch 1/10
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
I0000 00:00:1723771249.187940    8438 service.cc:146] XLA service 0x7f4a6c007630 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices:
I0000 00:00:1723771249.187968    8438 service.cc:154]   StreamExecutor device (0): Tesla T4, Compute Capability 7.5
I0000 00:00:1723771249.187973    8438 service.cc:154]   StreamExecutor device (1): Tesla T4, Compute Capability 7.5
I0000 00:00:1723771249.187976    8438 service.cc:154]   StreamExecutor device (2): Tesla T4, Compute Capability 7.5
I0000 00:00:1723771249.187979    8438 service.cc:154]   StreamExecutor device (3): Tesla T4, Compute Capability 7.5
125/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.5742 - loss: 1.2336
I0000 00:00:1723771250.049424    8438 device_compiler.h:188] Compiled cluster using XLA!  This line is logged at most once for the lifetime of the process.
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 4s 1ms/step - accuracy: 0.7842 - loss: 0.6205
Epoch 2/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.8607 - loss: 0.3859
Epoch 3/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.8768 - loss: 0.3384
Epoch 4/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.8842 - loss: 0.3138
Epoch 5/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.8915 - loss: 0.2939
Epoch 6/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.8944 - loss: 0.2868
Epoch 7/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.8990 - loss: 0.2700
Epoch 8/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.9012 - loss: 0.2623
Epoch 9/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.9091 - loss: 0.2476
Epoch 10/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.9107 - loss: 0.2364
<keras.src.callbacks.history.History at 0x7f4d31649eb0>

随着模型训练的进行,损失和准确率指标会显示出来。该模型在训练数据上的准确率约为 0.91(或 91%)。

评估准确率

接下来,比较模型在测试数据集上的表现:

test_loss, test_acc = model.evaluate(test_images,  test_labels, verbose=2)

print('\nTest accuracy:', test_acc)
313/313 - 1s - 3ms/step - accuracy: 0.8863 - loss: 0.3257

Test accuracy: 0.8863000273704529

事实证明,模型在测试数据集上的准确率略低于训练数据集。训练准确率与测试准确率之间的差距代表了过拟合 (overfitting)。当机器学习模型在新的、从未见过的数据上的表现比在训练数据上更差时,就会发生过拟合。过拟合的模型会“记住”训练数据集中的噪声和细节,以至于对模型在处理新数据时的性能产生负面影响。有关详细信息,请参阅以下内容:

进行预测

模型训练完成后,您可以使用它对某些图像进行预测。附加一个 softmax 层以将模型的线性输出(logits)转换为概率,这样更容易解释。

probability_model = tf.keras.Sequential([model, 
                                         tf.keras.layers.Softmax()])
predictions = probability_model.predict(test_images)
313/313 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step

在这里,模型预测了测试集中每张图像的标签。让我们看看第一个预测:

predictions[0]
array([6.8082486e-06, 8.7130829e-08, 2.3059203e-08, 1.7164245e-08,
       9.2101942e-07, 1.5966746e-03, 3.3436372e-06, 1.1623867e-02,
       4.7985890e-07, 9.8676783e-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):
  true_label, img = 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):
  true_label = true_label[i]
  plt.grid(False)
  plt.xticks(range(10))
  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 张图像、预测结果和预测数组。正确的预测标签为蓝色,错误的预测标签为红色。数字表示预测标签的百分比(满分 100)。

i = 0
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions[i], test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions[i],  test_labels)
plt.show()

png

i = 12
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions[i], test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions[i],  test_labels)
plt.show()

png

让我们绘制几张带有预测结果的图像。请注意,即使模型非常有把握,也可能会出错。

# Plot the first X test images, their predicted labels, and the true labels.
# Color correct predictions in blue and incorrect predictions in red.
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[i], test_labels, test_images)
  plt.subplot(num_rows, 2*num_cols, 2*i+2)
  plot_value_array(i, predictions[i], test_labels)
plt.tight_layout()
plt.show()

png

使用训练好的模型

最后,使用训练好的模型对单张图像进行预测。

# Grab an image from the test dataset.
img = test_images[1]

print(img.shape)
(28, 28)

tf.keras 模型经过优化,可以一次性对一批 (batch) 或一组示例进行预测。因此,即使您只使用一张图像,也需要将其添加到列表中:

# Add the image to a batch where it's the only member.
img = (np.expand_dims(img,0))

print(img.shape)
(1, 28, 28)

现在预测该图像的正确标签:

predictions_single = probability_model.predict(img)

print(predictions_single)
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 146ms/step
[[4.0262650e-05 1.7603366e-12 9.9607229e-01 4.6822952e-11 3.8338848e-03
  1.7586101e-10 5.3584125e-05 7.4621548e-13 5.4244734e-12 5.0442324e-15]]
plot_value_array(1, predictions_single[0], test_labels)
_ = plt.xticks(range(10), class_names, rotation=45)
plt.show()

png

tf.keras.Model.predict 返回一个列表的列表——数据批次中的每张图像对应一个列表。获取我们批次中(唯一)图像的预测结果:

np.argmax(predictions_single[0])
2

模型按预期预测出了标签。

要了解有关使用 Keras 构建模型的更多信息,请参阅 Keras 指南

# MIT License
#
# Copyright (c) 2017 François Chollet
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.