这个例子将会训练一个神经网络用来对衣物的图片进行分类,比如把运动鞋和衬衫进行区分。如果你对有的细节不太了解,没有关系,这个例子只是让你快速的看一下一个TensorFlow程序是什么样子,后边会对细节进行讲解。

这个例子用的是tf.keras,在tensorflow里训练模型的高层API


# TensorFlow and tf.keras
import tensorflow as tf
from tensorflow import keras

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

print(tf.__version__)

2.1.0

导入 Fashion MNIST data


fashion_mnist = keras.datasets.fashion_mnist
(train_images,train_labels),(test_images,test_labels) = fashion_mnist.load_data()

导入的数据返回的是NumPy arrays:

  • train_image 和 train_labels 是训练数据集。
  • test_images 和 test_labels 是测试数据集。

图片是28*28的numpy array,每个像素都是0到255的数字,labels是一个整数数组,从0到9,分别对应衣物的不同分类。

Label 类别
0 T-shirt/top
1 Trouser
2 Pullover
3 Dress
4 Coat
5 Sandal
6 Shirt
7 Sneaker
8 Bag
9 Ankle boot

每个图片都被映射到一个标签,因为数据里并没有包含类别名称,所以需要存在一个数组里,方便后边用来画图。


class_name = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

浏览数据

在训练模型前,我们先看一下数据。下边显示了我们共有60000张图片作为训练集,每个图片都是用28*28个像素值表示的。


train_images.shape

(60000,28,28)

同样,我们也有60000个标签数据在训练集里:


len(train_labels)

60000

每个标签都是数字0到9中的一个。


train_labels

array([9,0,0,...,3,0,5]),dtype=uint8)

同样测试集里有10000个图片,每个都是28*28个像素。


test_images.shape

(10000,28,28)

并且测试集里包含了10000个图片的标签


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_iamges/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 = keras.Sequential([
keras.layers.Flatten(input_shape=(28,28),
keras.layers.Dense(128,activation='relu'),
keras.layers.Dense(10)
])

网络中的第一层,tf.keras.layers.Flatten,把图片从二维的数组(28*28 像素)转化为一维数组(28*28=784 像素),这一层是把所有的行拼成一行。这一层没有要学习的参数。只是对数据做一个重新的组织。

所有像素被打平后,网络又连了两个tf.keras.layers.Dense层。这是全连接层。第一个全连接层有128个节点,第二层返回一个10个元素的logits数组,每个元素的值标志着属于10个类别中一类的可能性。

编译模型

模型在被训练之前,他需要一些更多的设置,这些都是在模型被编译的步骤被添加的。

  • 损失函数 - 用来衡量模型的准确性,训练时通过让这个值变小来增加模型精度的。
  • 优化器 - 这个是决定模型如何根据数据和损失函数来更新自己的。
  • Metrics - 用来监视训练和测试的每一步,下边的例子用图片被正确分类的accuracy值。

model.compile(optimizer='adam',loss=tf.keras.losses.SparseCategoricalCrossentorpy(from_logits=True,metrics=['accuracy']))

训练模型

训练一个神经网络模型需要如下几步:

  1. 把训练数据放入网络,在这个例子里,训练数据是train_images和train_labels数组。
  2. 模型通过images和labels去学习。
  3. 通过模型去预测一个测试数据集,在这个示例里,是test_images。
  4. 检查预测结果和test_labels里的值是否一致。

训练模型

为了开始训练,调用model.fit方法,这里的fit说的是让模型去适应训练数据。


model.fit(train_images,train_labels,epochs=10)

Train on 60000 samples
Epoch 1/10
60000/60000 [==============================] - 3s 49us/sample - loss: 2.4970 - accuracy: 0.6719
Epoch 2/10
60000/60000 [==============================] - 3s 42us/sample - loss: 0.6959 - accuracy: 0.7290
Epoch 3/10
60000/60000 [==============================] - 2s 39us/sample - loss: 0.5913 - accuracy: 0.7896
Epoch 4/10
60000/60000 [==============================] - 2s 39us/sample - loss: 0.5493 - accuracy: 0.8072
Epoch 5/10
60000/60000 [==============================] - 2s 40us/sample - loss: 0.5300 - accuracy: 0.8144
Epoch 6/10
60000/60000 [==============================] - 2s 39us/sample - loss: 0.5185 - accuracy: 0.8209
Epoch 7/10
60000/60000 [==============================] - 2s 40us/sample - loss: 0.5058 - accuracy: 0.8242
Epoch 8/10
60000/60000 [==============================] - 3s 44us/sample - loss: 0.4998 - accuracy: 0.8289
Epoch 9/10
60000/60000 [==============================] - 2s 42us/sample - loss: 0.4877 - accuracy: 0.8322
Epoch 10/10
60000/60000 [==============================] - 2s 40us/sample - loss: 0.4828 - accuracy: 0.8363

当模型训练时,loss和accuracy的值会显示,这个模型通过训练数据达到了0.83(或者83%)的精度。

评估精度

现在我们用测试数据集泡一下模型。


test_loss,test_acc=model.evaluate(test_images,test_labels,verbose=2)
print('\nTest accuracy:',test_acc)

10000/10000 - 0s - loss: 0.6042 - accuracy: 0.7903

Test accuracy: 0.7903

可以看到测试数据集上的准确性比训练数据集上差,这个差距叫做过拟合。当一个机器学习的模型在新数据上表现变差叫做过拟合。这些新数据在模型训练时没有用到。过拟合的模型记住了训练数据的噪声或者一些非共性的细节。这将影响它在新数据上的表现。

预测

利用训练好的模型,你可以用它去预测一些图片。这个模型的线性输出,logits,通过后续的softmax层来把logits转化为概率值,这个比较容易解释。


probability_model = tf.keras.Sequential([model,tf.keras.layers.Softmax()])
predictions = probability_model.predict(test_images)

在这里模型对每个图片都给出了预测,让我们看一下第一个预测:


predictions[0]

array([1.1315875e-17, 6.4354767e-18, 0.0000000e+00, 2.6878016e-22,
       2.5430062e-27, 1.0040930e-01, 8.3033929e-38, 4.9132548e-02,
       3.6309725e-08, 8.5045815e-01], dtype=float32)

一个预测是一个10个数的数组,它表示了模型对这个图片归属这10个类别中具体哪个类别的信心。你可以看他对哪个类别信心最大


np.argmax(predictons[0])

9

可以看到模型对这个图片是一个ankle boot最有信心。也就是class_names[9],通过test label里的值也可以验证:


test_label[0]

9

通过画图来看一下所有10种类别的预测。

验证预测

利用训练好的模型,你可以对一些图片做出预测,
我们看一下第0张图片,预测值,以及预测的数组,正确的预测标签是蓝色的,不正确的是红色的,以及预测值的百分比。


def plot_image(i,predictions_array,true_label,img):
    predictions_array,true_label,img=predictions_array,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, 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')
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 = 4
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[i]
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.0828410e-02 3.7906150e-04 6.1789840e-02 2.0429362e-02 5.7498562e-01
  6.9450844e-21 3.3157235e-01 0.0000000e+00 1.5349853e-05 5.3574017e-27]]

plot_value_array(1, predictions_single[0], test_labels)
_ = plt.xticks(range(10), class_names, rotation=45)

keras.Model.predict返回一个列表的列表。第一层是每个图片,第二层是每个图片不同分类的概率值。通过下边的方式获取我们唯一一个图片的类别预测值


np.argmax(predictions_single[0])

4

#
# 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.

这个例子使用了Fashion MNIST数据集,它包含了70000个10个分类的灰度图片。这个图片都是低分辨率的(28*28)单个衣物图片。

Fashion MNIST 是用来替代经典的MINISt数据集的,MNIST数据集是一个用来学习计算机视觉的“Hello World”数据集。MNIST数据集市一个手写数字(0,1,2...),格式与我们例子中使用的衣物数据一样。

这里我们用Fashion MNIST,让问题有趣一点,也有一点挑战性。两个数据集都相对较小,可以用来验证算法的有效性。这也是一个很好的用来测试和调试程序的起点。

在这里我们用60000张图片训练神经网络,用10000张图片来评价网络对图片分类的精度如何。你可以直接通过TensorFlow来获取MINIST数据,通过TensorFlow你可以导入和加载Fashion MINIST数据。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

%d 博主赞过: