В этой статье мы создадим очень простую модель с помощью TensorFlow, которая учится распознавать рукописные цифры. Пример предназначен для использования в качестве основы для будущих статей.
Статья написана с использованием Jupyter Lab, и вы можете скачать соответствующий код по адресу https://github.com/alan-cooney/blog/blob/main/posts/mnist-simple/mnist-simple.ipynb.
Настраивать
Сначала мы импортируем ключевые зависимости:
import typing from os import getcwd, path import tensorflow as tf import tensorflow_datasets as tfds from keras import models from matplotlib import pyplot from tensorflow.python.data.ops import dataset_ops from tensorflow_datasets.core import dataset_info
Далее мы загрузим набор данных MNIST, используя tensorflow_datasets
:
# Add types for the dataset ds_train: dataset_ops.Dataset ds_test: dataset_ops.Dataset ds_info = dataset_info.DatasetInfo # Download (ds_train, ds_test), ds_info = tfds.load( 'mnist', split=['train', 'test'], # Split into training and testing data data_dir=path.join(getcwd(), ".data"), # Store in .data/ as_supervised=True, # Get tuples (features, label) with_info=True, # Include extra info about the dataset )
После этого мы нормализуем изображения, чтобы каждый пиксель был числом с плавающей запятой (0–1), а не целым числом (0–255). Это не обязательно, но улучшает обучение.
def normalize_img(image: tf.Tensor, label: tf.Tensor) -> typing.Tuple[tf.Tensor, tf.Tensor]: """Normalize image from `uint8` to `float32` The image pixels are given as integers from 0 (black) to 255 (white). Args: image (tf.uint8): Image tensor of type unit8 label (tf.int64): Label Returns: typing.Tuple[tf.float32, tf.int64]: Tuple with the normalised image, and label """ normalized_image = tf.cast(image, tf.float32) / 255. return normalized_image, label ds_train = ds_train.map(normalize_img) ds_test = ds_test.map(normalize_img)
Затем, наконец, мы поместим изображения в пакеты.
ds_train = ds_train.batch(64) ds_test = ds_test.batch(64)
Модель
Далее мы создадим очень простую модель. Сначала нам нужно сгладить каждое изображение (чтобы оно стало вектором 1x784), а затем самый простой подход — просто использовать один слой (что дает точность около 90%). Однако, чтобы получить точность 95%+, мы будем использовать два слоя со слоем активации ReLU между ними.
model = models.Sequential([ tf.keras.layers.Flatten(input_shape=(28, 28)), tf.keras.layers.Dense(128, activation='relu'), tf.keras.layers.Dense(10) ])
Далее мы скомпилируем модель, настроим оптимизатор и функцию потерь.
Для оптимизатора мы будем использовать стохастический градиентный спуск (поскольку это действительно самый простой подход), отметив, что использование адаптивного оптимизатора (например, Адама) на самом деле обучается намного быстрее.
Для потери мы будем использовать кросс-энтропию.
model.compile( optimizer=tf.keras.optimizers.SGD(0.01), loss=tf.keras.losses.SparseCategoricalCrossentropy( from_logits=True ), # Standard cross-entropy loss metrics=[tf.keras.metrics.SparseCategoricalAccuracy()], )
И с этим мы можем обучить модель:
history = model.fit( ds_train, epochs=30, validation_data=ds_test, )
Наконец, вот график точности:
pyplot.plot(history.history['val_sparse_categorical_accuracy']) pyplot.title('Model accuracy (on test data)') pyplot.ylabel('Accuracy') pyplot.ylim([0.85, 1]) pyplot.xlabel('Epoch') pyplot.show()