这一节将使用 TensorFlow 官方教程 的一个例子——Basic classification: Classify images of clothing——基础分类:衣物图片分类,训练一个神经网络模型来分类像运动鞋和衬衫这样的衣服的图像。
有了《TensorFlow 2.x MNIST-图像分类(1)》和《TensorFlow 2.x MNIST-图像分类(2)》这两节的铺垫,本节将显得比较简单。
一、加载数据
在之前的文章中,我们都是使用 MNIST,但是 MNIST 太简单了,只需要几分钟的训练,准确率就可以达到 99% 以上,并且大部分图片可能只需要几个像素点就可以区分开来。真实世界千变万化,我们需要更真实的图片。
本次使用的数据集是 Fashion MNIST。该数据集由 70,000 张黑白图片构成,每张图片大小为 28x28,图片数量和大小与经典 MNIST 完全相同,但 Fashion MNIST 是由十类服饰图片构成,MNIST 是手写数字。Fashion MNIST 更有挑战性,更适合用来验证算法。Fashion-MNIST 的目的是要代替 MNIST。
废话不多说,先下载四个数据集:
(1)训练集图片:train-images-idx3-ubyte.gz,60,000张,26 MBytes。
(2)训练集标签:train-labels-idx1-ubyte.gz,60,000张,29 KBytes。
(3)测试集图片:t10k-images-idx3-ubyte.gz,10,000张,4.3 MBytes。
(4)测试集标签:t10k-labels-idx1-ubyte.gz,10,000张,5.1 KBytes。
下载后,加载数据:
1 | import tensorflow as tf |
这里的数据加载方法与 TensorFlow 官方教程上的不同,因为官方教程加载数据时,直接下载,而下载链接需要翻墙,如果你能科学上网,可以使用如下官方教程,代替上一段代码:
1 | (train_images, train_labels), (test_images, test_labels) = keras.datasets.fashion_mnist.load_data() |
二、数据预处理
数据格式如下:
1 | train_images.shape # (60000, 28, 28) |
然后我们查看第一张图片:
1 | plt.figure() |
图片大小 28x28,每个像素值取值范围 0-255。标签是整数,取值范围 0-9,与实际的服饰类别对应关系如下。
Label | Class |
---|---|
0 | T-shirt/top (T恤) |
1 | Trouser(裤子) |
2 | Pullover(套衫) |
3 | Dress (裙子) |
4 | Coat(外套) |
5 | Sandal(凉鞋) |
6 | Shirt(汗衫) |
7 | Sneaker(运动鞋) |
8 | Bag(包) |
9 | Ankle boot(短靴) |
每个图像都映射到一个标签。上图的标签是 9,所以图片中应该是 Ankle boot (短靴),虽然没看出哪里短。
1 | class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot'] |
图片的每个像素值在 0-255 之间,需要转为 0-1。训练集和测试集都需要经过相同的处理。
1 | train_images = train_images / 255.0 |
显示前 25 张图片与标签的对应关系:
1 | # show first 25 images and labels |
三、搭建神经网络
搭建神经网络分为两步,首先配置模型的每一层,然后编译模型。
配置模型层
神经网络的基本构成是网络层 (layer),大部分深度学习网络都由多个简单的 layers 构成。
1 | model = keras.Sequential([ |
网络的输入层 tf.keras.layers.Flatten
将输入的图片从 28 × 28 的二维数组(28 × 28 像素)转为 784 的一维数组,这一层的作用仅仅是将每一行值平铺在一行,没有参数需要学习。
接下来是 2 层 tf.keras.layers.Dense
,即全连接层 (Fully Connected, FC),第一层 Dense 有 128 个神经元。第二层有 10 个神经元,经过 softmax 后,返回了和为 1 长度为 10 的概率数组,每一个数分别代表当前图片属于分类 0-9 的概率。
编译模型
在开始训练前,模型需要编译 (Compile) 并设置一些参数:
- Loss function - 损失函数,训练时评估模型的正确率,希望最小化这个函数,往正确的方向训练模型。
- Optimizer - 优化器算法,更新模型参数的算法。
- Metrics - 指标,用来监视训练和测试步数,下面的例子中使用 accuracy,即图片被正确分类的比例。
1 | model.compile(optimizer='adam', |
四、训练模型
训练神经网络,通常有以下几个步骤。
- 传入训练集数据,
train_images
和train_labels
。 - 训练模型,关联图片和标签。
- 使用测试集
test_images
预测,并用标签test_labels
进行验证。
Feed the model
调用 model.fit
方法开始训练。
1 | model.fit(train_images, train_labels, epochs=10) |
1 | Epoch 1/10 |
经过 10 轮训练后,准确率达到了 91.12%。
评估准确率
使用测试集数据看看模型训练的结果:
1 | test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2) |
测试集的准确率低于训练集,训练集和测试集准确率之间的差距代表模型过拟合 (overfitting)。即对于训练中没有见过的新数据,模型表现差。如果你对过拟合不熟悉,可以看看《过拟合(Overfitting) 与 Dropout》,没错,也是我的文章。
预测
使用 predict 函数进行预测,并显示图片,打印预测结果及标签。
1 |
|
看一下第一个预测结果。
1 | [3.1960328e-09 1.2830121e-11 1.0000000e+00 1.5766790e-18 1.2614347e-16 |
结果是一个长度为 10 的数组,数组的每个值代表模型认为是对应标签的概率。上述例子中 9 号标签的概率最大 1.0000000e+00,即模型认为该图片是 9 号标签的概率是 100%。
预测结果和标签结果相同,都是 Pullover。