📜 原文链接:https://tensorflow.google.cn/tutorials/quickstart/beginner

    本篇文章将使用 Keras 来完成 3 个任务:

    1. 建立一个对图像进行分类的神经网络
    2. 训练神经网络
    3. 评估模型的准确性

    下载并安装 TensorFlow2.x,并将其导入到程序中。

    1. import tensorflow as tf

    载入并准备好 MINIST数据集,并将样本从整数转换为浮点数:

    1. mnist = tf.keras.datasets.mnist
    2. (x_train, y_train), (x_test, y_test) = mnist.load_data()
    3. x_train, x_test = x_train / 255.0, x_test / 255.0

    📑 终端输出结果:

    1. Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
    2. 11493376/11490434 [==============================] - 5s 0us/step

    🔔 首次运行上述代码,会通过 Google API 来下载 MNIST 数据。值得注意的是,如果你不能访问访问谷歌,将不能下载该数据集,其他办法请自行百度。

    通过将模型的各层进行堆叠,搭建出一个 tf.keras.Sequential 模型,同时选定模型的优化器(optimizer) 和损失函数(loss function):

    1. model = tf.keras.Sequential([
    2. tf.keras.layers.Flatten(input_shape=(28, 28)),
    3. tf.keras.layers.Dense(128, activation='relu'),
    4. tf.keras.layers.Dropout(0.2),
    5. tf.keras.layers.Dense(10)
    6. ])

    对于每个样本,模型返回一个 logits 或者 log-odds 的分数向量列表,向量列表中每个元素对应到每个类别。

    1. predictions = model(x_train[:1]).numpy()
    2. predictions

    📑 输出结果:

    1. array([[ 0.50147635, 0.27259597, -1.1021543 , -0.20509964, 0.8072599 ,
    2. -0.68293977, -0.45379734, 1.2299292 , 0.31612065, -0.17554879]],
    3. dtype=float32)

    💡 这里是 Cifar10 数据集,有 10 个类别,所以对应输出是一个长度为 10 的向量。

    通过 tf.nn.softmax 函数可以将这些 logits 分数转换为对应类的概率。

    1. tf.nn.softmax(predictions).numpy()

    📑 输出结果:

    1. array([[0.12580125, 0.10006529, 0.02530679, 0.0620616 , 0.1707989 ,
    2. 0.03848571, 0.0483966 , 0.26064417, 0.10451677, 0.06392293]],
    3. dtype=float32)

    💡 我们也可以将 tf.nn.softmax 作为神经网络中最后一层的激活函数,可将我们的代码修改成如下所示:

    1. model = tf.keras.Sequential([
    2. tf.keras.layers.Flatten(input_shape=(28, 28)),
    3. tf.keras.layers.Dense(128, activation='relu'),
    4. tf.keras.layers.Dropout(0.2),
    5. tf.keras.layers.Dense(10, activation='softmax') # 这里添加 softmax 激活函数
    6. ])

    尽管这种方法可以模型的输出更具解释性,但不建议使用此方法,因为当使用 softmax 输出时,不可能给所有模型提供精确并数值稳定的损失值计算。
    loss.SparseCategoricalCrossentropy 损失函数接收 logits 向量和 from_logits 参数,并且返回每个样本的标量损失。

    1. loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)

    返回的损失值就是真实类别的负对数概率:如果模型预测的是正确的类别,该值将会为 0。
    这个未经训练的模型给出的概率值接近于随机值(随机每个类别的概率为 1. 面向初学者的快速入门 - 图1),所以初始损失值应该接近于 2.3(-tf.math.log(1/10).numpy())。

    1. loss_fn(y_train[:1], predictions).numpy() # 输出:3.2574682

    下面我们给模型指定优化器(optimizer)、损失函数(loss function) 以及评价指标(metrics)。

    1. model.compile(optimizer='adam',
    2. loss=loss_fn,
    3. metrics=['accuracy'])

    通过 model.fit 方法调整模型参数来使损失值最小化。

    1. model.fit(x_train, y_train, epochs=5)

    📑 输出结果:

    1. Epoch 1/5
    2. 1875/1875 [==============================] - 4s 2ms/step - loss: 0.2976 - accuracy: 0.9127
    3. Epoch 2/5
    4. 1875/1875 [==============================] - 4s 2ms/step - loss: 0.1418 - accuracy: 0.9578
    5. Epoch 3/5
    6. 1875/1875 [==============================] - 4s 2ms/step - loss: 0.1060 - accuracy: 0.9678
    7. Epoch 4/5
    8. 1875/1875 [==============================] - 4s 2ms/step - loss: 0.0854 - accuracy: 0.9734
    9. Epoch 5/5
    10. 1875/1875 [==============================] - 4s 2ms/step - loss: 0.0733 - accuracy: 0.9771
    11. <tensorflow.python.keras.callbacks.History at 0x28a2370c6d8>

    model.evaluate 方法通常用来评估模型在验证集(Validation-set) 或者测试集(Test-set)的效果。

    1. model.evaluate(x_test, y_test, verbose=2)

    📑 输出结果:

    1. 313/313 - 1s - loss: 0.0764 - accuracy: 0.9762
    2. [0.07640933990478516, 0.9761999845504761]

    💡 verbose 参数可给定 3 个数值,分别为 0、1、2。其中 0 表示不展示,1 表示展示进度条,2 表示直接展示结果。

    现在我们的图像分类器在训练集上的预测精度已经接近于 98%。
    如果你想要模型输出一个概率值,可以通过结合 softmax 层与封装训练好的模型来实现:

    1. probability_model = tf.keras.Sequential([
    2. model,
    3. tf.keras.layers.Softmax()
    4. ])
    5. probability_model(x_test[:5])

    📑 输出结果:

    1. <tf.Tensor: shape=(5, 10), dtype=float32, numpy=
    2. array([[6.26229095e-08, 2.68061551e-09, 1.73842454e-05, 2.29407378e-04,
    3. 1.80993913e-12, 1.27843300e-08, 9.75732573e-15, 9.99751508e-01,
    4. 2.87250344e-07, 1.33290189e-06],
    5. [2.41450930e-08, 1.70489453e-04, 9.99811113e-01, 1.77893126e-05,
    6. 3.21382776e-16, 3.48518768e-07, 2.29711770e-08, 6.11730032e-15,
    7. 2.43219262e-07, 3.98595375e-14],
    8. [1.51075188e-08, 9.99706924e-01, 3.11348049e-05, 4.63649121e-06,
    9. 1.74165580e-05, 2.31678382e-06, 6.91525929e-06, 1.31301495e-04,
    10. 9.92691712e-05, 1.81115965e-07],
    11. [9.99845862e-01, 2.93073867e-08, 2.12001796e-05, 6.11394512e-07,
    12. 4.11029669e-06, 7.62671652e-06, 3.90081223e-05, 1.91258687e-06,
    13. 1.01774184e-07, 7.94934313e-05],
    14. [2.60670390e-07, 3.86829069e-10, 5.87267323e-07, 4.03869542e-08,
    15. 9.98871744e-01, 5.70653469e-07, 4.86737747e-07, 9.62683134e-06,
    16. 2.05614515e-06, 1.11458707e-03]], dtype=float32)>

    其实上述图像分类器也可以这些写:

    1. model = tf.keras.Sequential([
    2. tf.keras.layers.Flatten(input_shape=(28, 28)),
    3. tf.keras.layers.Dense(128, activation='relu'),
    4. tf.keras.layers.Dropout(0.2),
    5. tf.keras.layers.Dense(10, activation='softmax')
    6. ])
    7. model.compile(optimizer='adam',
    8. loss='sparse_categorical_crossentropy',
    9. metrics=['accuracy'])
    10. model.fit(x_train, y_train, epochs=5)
    11. model.predict(x_test[:5])