在 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-07-13 04:19:34.844149: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:479] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered 2024-07-13 04:19:34.871376: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:10575] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered 2024-07-13 04:19:34.871421: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1442] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered 2.16.2
导入 Fashion MNIST 数据集
本指南使用 Fashion MNIST 数据集,该数据集包含 70,000 张 10 类别的灰度图像。这些图像显示了低分辨率(28x28 像素)的单个服装,如下所示
图 1. Fashion-MNIST 样本(由 Zalando 提供,MIT 许可)。 |
Fashion 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()
加载数据集将返回四个 NumPy 数组
- The
train_images
和train_labels
数组是训练集——模型用来学习的数据。 - 模型使用测试集进行测试,即
test_images
和test_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()
在将这些值馈送到神经网络模型之前,请将其缩放到 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()
构建模型
构建神经网络需要配置模型的层,然后编译模型。
设置层
神经网络的基本构建块是 层。层从馈送到它们的数据中提取表示。希望这些表示对当前问题有意义。
深度学习的大部分内容都包括将简单的层链接在一起。大多数层,例如 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)
此网络中的第一层,tf.keras.layers.Flatten
,将图像的格式从二维数组(28x28 像素)转换为一维数组(28 * 28 = 784 像素)。将此层视为将图像中的像素行展开并排成一行。此层没有要学习的参数;它只重新格式化数据。
像素展平后,网络由两个 tf.keras.layers.Dense
层组成。这些是密集连接的或全连接的神经层。第一个 Dense
层有 128 个节点(或神经元)。第二层(也是最后一层)返回一个长度为 10 的 logits 数组。每个节点包含一个分数,该分数指示当前图像属于 10 个类别中的一个。
编译模型
在模型准备好进行训练之前,它还需要一些其他设置。这些设置是在模型的 编译 阶段添加的
- 优化器 —这是模型根据它看到的数据及其损失函数进行更新的方式。
- 损失函数 —这衡量模型在训练期间的准确率。您需要最小化此函数以“引导”模型朝正确的方向发展。
- 指标 —用于监控训练和测试步骤。以下示例使用准确率,即正确分类的图像的比例。
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
训练模型
训练神经网络模型需要以下步骤
- 将训练数据馈送到模型。在本例中,训练数据位于
train_images
和train_labels
数组中。 - 模型学习将图像和标签关联起来。
- 您要求模型对测试集进行预测——在本例中,是
test_images
数组。 - 验证预测是否与
test_labels
数组中的标签匹配。
馈送模型
要开始训练,请调用 model.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:1720844382.080422 73401 service.cc:145] XLA service 0x7f7a68006fc0 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices: I0000 00:00:1720844382.080462 73401 service.cc:153] StreamExecutor device (0): Tesla T4, Compute Capability 7.5 I0000 00:00:1720844382.080467 73401 service.cc:153] StreamExecutor device (1): Tesla T4, Compute Capability 7.5 I0000 00:00:1720844382.080470 73401 service.cc:153] StreamExecutor device (2): Tesla T4, Compute Capability 7.5 I0000 00:00:1720844382.080473 73401 service.cc:153] StreamExecutor device (3): Tesla T4, Compute Capability 7.5 124/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.5870 - loss: 1.2303 I0000 00:00:1720844382.812309 73401 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.7832 - loss: 0.6298 Epoch 2/10 1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.8619 - loss: 0.3838 Epoch 3/10 1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.8715 - loss: 0.3471 Epoch 4/10 1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.8866 - loss: 0.3164 Epoch 5/10 1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.8936 - loss: 0.2910 Epoch 6/10 1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.8978 - loss: 0.2773 Epoch 7/10 1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.8998 - loss: 0.2653 Epoch 8/10 1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.9039 - loss: 0.2578 Epoch 9/10 1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.9079 - loss: 0.2458 Epoch 10/10 1875/1875 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step - accuracy: 0.9149 - loss: 0.2300 <keras.src.callbacks.history.History at 0x7f7c3b75e7c0>
随着模型的训练,损失和准确率指标将被显示。此模型在训练数据上的准确率约为 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.8888 - loss: 0.3224 Test accuracy: 0.8888000249862671
事实证明,测试数据集上的准确率略低于训练数据集上的准确率。训练准确率和测试准确率之间的差距代表了过拟合。过拟合是指机器学习模型在新的、以前从未见过的输入上的表现比在训练数据上的表现差。过拟合模型“记住”了训练数据集中的噪声和细节,以至于对新数据的模型性能产生了负面影响。有关更多信息,请参阅以下内容
进行预测
模型训练完成后,您可以使用它来预测一些图像。将 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([1.0297459e-08, 6.0991318e-10, 4.4771734e-10, 4.6667561e-12, 1.7007395e-08, 2.9962388e-04, 1.6731771e-07, 2.5453644e-03, 3.6041616e-08, 9.9715471e-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()
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()
让我们绘制几张图像及其预测。请注意,即使模型非常自信,它也可能是错误的。
# 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()
使用训练后的模型
最后,使用训练后的模型来预测单个图像。
# Grab an image from the test dataset.
img = test_images[1]
print(img.shape)
(28, 28)
tf.keras
模型经过优化,可以一次对批次(或集合)中的示例进行预测。因此,即使您使用的是单个图像,也需要将其添加到列表中
# 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 140ms/step [[3.1302361e-06 2.6202183e-12 9.9640650e-01 3.0387102e-13 3.1137168e-03 5.0210312e-11 4.7672543e-04 8.7875020e-13 4.1576378e-11 2.9291714e-15]]
plot_value_array(1, predictions_single[0], test_labels)
_ = plt.xticks(range(10), class_names, rotation=45)
plt.show()
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.