1.2 专家速览

自定义手写数字识别模型!

创建日期: 2022-07-18

重新实现手写数字识别模型,使用卷积层之后,准确率更高。执行程序在 quickstart_expert.py 文件中,可以直接在本地电脑运行!新手可以不用关注具体实现!

程序中导入 TensorFlow 库:

import keras
import tensorflow as tf

1.2.1 加载数据集

加载并准备 MNIST 数据集:

(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

# Add a channels dimension.
x_train = x_train[..., tf.newaxis].astype('float32')
x_test = x_test[..., tf.newaxis].astype('float32')

使用 tf.data 对数据集进行 随机排列 (Shuffle)批处理 (Batch)

BATCH_SIZE = 32

train_ds = tf.data.Dataset.from_tensor_slices(
    (x_train, y_train)).shuffle(10000).batch(BATCH_SIZE)
test_ds = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(BATCH_SIZE)

1.2.2 构建模型

使用 keras.Model 子类构建自定义模型:

class MyModel(keras.Model):
    def __init__(self):
        super().__init__()
        self.conv1 = keras.layers.Conv2D(32, 3, activation='relu')
        self.flatten = keras.layers.Flatten()
        self.d1 = keras.layers.Dense(128, activation='relu')
        self.d2 = keras.layers.Dense(10)

    def call(self, x):
        x = self.conv1(x)
        x = self.flatten(x)
        x = self.d1(x)
        return self.d2(x)

选择训练中的优化器和损失函数:

loss_object = keras.losses.SparseCategoricalCrossentropy(from_logits=True)
optimizer = keras.optimizers.Adam()

选择指标来衡量模型的损失和准确率,这些指标会累积各个时期的值,然后打印总体结果:

train_loss = keras.metrics.Mean(name='train_loss')
train_accuracy = keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')
test_loss = keras.metrics.Mean(name='test_loss')
test_accuracy = keras.metrics.SparseCategoricalAccuracy(name='test_accuracy')

1.2.3 训练与测试

使用 tf.GradientTape 训练模型:

@tf.function
def train_step(images, labels):
    with tf.GradientTape() as tape:
        predictions = model(images, training=True)
        loss = loss_object(labels, predictions)

    gradients = tape.gradient(loss, model.trainable_variables)
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))

    train_loss(loss)
    train_accuracy(labels, predictions)

测试模型:

@tf.function
def test_step(images, labels):
    predictions = model(images, training=False)
    t_loss = loss_object(labels, predictions)

    test_loss(t_loss)
    test_accuracy(labels, predictions)

每轮训练后并进行测试:

EPOCHS = 5
for epoch in range(EPOCHS):
    # Reset the metrics at the start of the next epoch
    train_loss.reset_state()
    train_accuracy.reset_state()
    test_loss.reset_state()
    test_accuracy.reset_state()

    for images, labels in train_ds:
        train_step(images, labels)

    for test_images, test_labels in test_ds:
        test_step(test_images, test_labels)

    print(
        f'Epoch {epoch + 1}, '
        f'loss: {train_loss.result():0.2f}, '
        f'accuracy: {train_accuracy.result() * 100:0.2f}, '
        f'test loss: {test_loss.result():0.2f}, '
        f'test accuracy: {test_accuracy.result() * 100:0.2f}')

输出训练和测试结果:

Epoch 1, loss: 0.13, accuracy: 96.05, test loss: 0.06, test accuracy: 98.14
Epoch 2, loss: 0.04, accuracy: 98.71, test loss: 0.06, test accuracy: 98.10
Epoch 3, loss: 0.02, accuracy: 99.32, test loss: 0.06, test accuracy: 98.21
Epoch 4, loss: 0.01, accuracy: 99.49, test loss: 0.07, test accuracy: 98.18
Epoch 5, loss: 0.01, accuracy: 99.71, test loss: 0.07, test accuracy: 98.12
            

图像分类器现在的准确率在 98% 以上!