1.1 新手速览

使用 Keras API 构建手写数字识别模型!

创建日期: 2022-07-16

本教程简单使用 Keras 来进行以下几点:

  1. 加载预先构建的数据集;

  2. 构建对图像进行分类的神经网络机器学习模型;

  3. 训练构建的神经网络;

  4. 评估模型的准确性。

学习本教程必须具备 Python 基础知识,可以阅读教程 Python 语言入门,针对机器学习而编写。代码实现在文件 quickstart_beginner.py 中,可在本地电脑上安装 Python 环境,下载相关依赖,点击运行!

以下示例图片由程序 show_mnist_tfds.py 生成:

MNIST 示例图片

1.1.1 设置

程序中引入 KerasTensorFlow (可选) 库:

import keras
import tensorflow as tf

print('Keras version:', keras.__version__)
print('TensorFlow version:', tf.__version__)

输出两者的版本号,因为程序简单,版本差异不影响最终结果:

Keras version: 3.6.0
TensorFlow version: 2.18.0

TensorFlow 是一个端到端的机器学习开源平台。Keras 是一个可以使用 TensorFlow 作为后端的深度学习 API ,让开发人员能够简单、灵活地构建模型!

1.1.2 加载数据集

加载并准备 MNIST 数据集,图像像素值范围为 [0, 255] 。通过将这些值除以 255.0 ,缩小到 [0, 1] 的范围,这还会将样本数据从整形转换为浮点型:

(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

1.1.3 构建模型

建立 keras.models.Sequential 模型:

model = keras.models.Sequential([
    keras.layers.Flatten(input_shape=(28, 28)),
    keras.layers.Dense(128, activation='relu'),
    keras.layers.Dropout(0.1),
    keras.layers.Dense(10)
])

Sequential 用于将 层 (Layer) 进行堆叠,其中每一层都有一个输入张量和一个输出张量。层是具有已知数学结构的函数,可以重复使用,并具有可训练的变量。大多数 TensorFlow 模型是由层组成,本模型使用了 FlattenDenseDropout 层。

对于每个示例,模型都会返回一个 Logits 分数 向量,向量的长度为类别 (0-9) 的个数(本示例为 10)。

NUM = 5
predictions = model.call(x_train[:NUM]).numpy()
print(numpy.round(predictions, 3))

获取 5 个样本,输入到模型中,输出 Logits 分数,保留 3 位小数:

[[-0.797  0.542 -0.022 -0.481  0.255 -0.392 -0.245 -0.312  0.504  0.064]
 [-0.379  0.724 -0.208 -0.074  0.267 -0.277 -0.065 -0.521  0.559 -0.346]
 [-0.696  0.233  0.224 -0.351 -0.181 -0.293  0.202 -0.245  0.535 -0.139]
 [-0.348 -0.472 -0.281 -0.101  0.154 -0.258 -0.396 -0.699  0.596 -0.044]
 [-0.544  0.774 -0.79  -0.719  0.233 -0.238 -0.13  -0.153  0.599 -0.2  ]]

使用 tf.nn.softmax 函数将这些 Logits 分数转换为每个类别的 概率 (Probability)

probabilities = tf.nn.softmax(predictions).numpy()
print(numpy.round(probabilities, 3))
[[0.045 0.173 0.098 0.062 0.129 0.068 0.079 0.073 0.166 0.107]
 [0.065 0.196 0.077 0.088 0.124 0.072 0.089 0.056 0.166 0.067]
 [0.05  0.128 0.127 0.071 0.084 0.076 0.124 0.079 0.173 0.088]
 [0.08  0.07  0.085 0.102 0.132 0.087 0.076 0.056 0.205 0.108]
 [0.057 0.214 0.045 0.048 0.125 0.078 0.087 0.085 0.18  0.081]]

注:可以将 tf.nn.softmax 函数嵌入到网络最后一层的激活函数中。虽然这样做可以让模型输入更容易理解,但是不建议采用这种方法,因为在使用 softmax 输出后,不可能为所有模型提供精确且数值稳定的损失计算。

使用 keras.losses.SparseCategoricalCrossentropy 为训练过程定义损失函数:

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

损失函数接收一个真实值向量和一个 Logits 值向量,为每个样本返回一个标量损失。此损失为对应真实类别的 Logits 值的负对数函数值:如果模型确定正确的类别,则损失为零。

未经训练的模型给出的概率是随机的(每个类别为 1/10 ),所以初始损失应该接近 \(-ln(1/10) ~= 2.3\) :

print(loss_fn(y_train[:NUM], predictions).numpy())
2.442869

在开始训练之前,需要使用 Model.compile 函数配置并编译模型。将 optimizer 参数设置为 adam ,使用 loss_fn 作为损失函数,并通过 metrics 指定需要评估的指标:

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

1.1.4 训练与评估

使用 Model.fit 方法调整模型的参数并最小化损失:

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

训练过程中模型识别的准确率逐渐提高,最终达到 98.30%

Epoch 1/5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 3s 1ms/step - accuracy: 0.8643 - loss: 0.4636.2900
Epoch 2/5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 3s 1ms/step - accuracy: 0.9584 - loss: 0.1399  
Epoch 3/5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 3s 1ms/step - accuracy: 0.9719 - loss: 0.0934  
Epoch 4/5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 3s 2ms/step - accuracy: 0.9795 - loss: 0.0696  
Epoch 5/5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 3s 1ms/step - accuracy: 0.9830 - loss: 0.0572 

使用 Model.evaluate 方法在测试集上评估模型的性能:

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

模型在从未看过的样本上依然有 97.65% 的正确率(稍微低于训练):

313/313 - 0s - 1ms/step - accuracy: 0.9765 - loss: 0.0735

如果我们希望模型返回一个概率,可以包装训练好的模型,将 softmax 层附加在最后:

probability_model = keras.Sequential([
    model,
    keras.layers.Softmax()
])

用测试集前 5 张图片进行测试,它们的标签分别是:[7 2 1 0 4] ,可以看到和预测结果是一致的:

probabilities = probability_model(x_test[:NUM]).numpy()
print(numpy.round(probabilities, 3))
print('Predict label:', probabilities.argmax(axis=-1))
print('True label:', y_test[:NUM])
[[0.    0.    0.    0.    0.    0.    0.    1.    0.    0.   ]
 [0.    0.001 0.999 0.    0.    0.    0.    0.    0.    0.   ]
 [0.    0.999 0.    0.    0.    0.    0.    0.001 0.    0.   ]
 [1.    0.    0.    0.    0.    0.    0.    0.    0.    0.   ]
 [0.    0.    0.    0.    0.994 0.    0.    0.001 0.    0.005]]
Predict label: [7 2 1 0 4]
True label: [7 2 1 0 4]

恭喜!我们已经使用 Keras 的 API ,利用预先构建的数据集,训练了机器学习模型。