На этом шаге мы рассмотрим пример простой сверточной сети.
Здесь мы погрузимся в теорию сверточных нейронных сетей и выясним причины их успеха в задачах распознавания образов. Но сначала рассмотрим практический пример простой сверточной нейронной сети, классифицирующей изображения рукописных цифр из набора MNIST. Эту задачу мы решили на 26 шаге, использовав полносвязную сеть (ее точность на контрольных данных составила 97,8%). Несмотря на простоту сверточной нейронной сети, ее точность будет значительно выше полносвязной модели из этого шага.
В следующем примере показано, как выглядит простая сверточная нейронная сеть. Это стек слоев Conv2D и MaxPooling2D. Как она действует, рассказывается чуть ниже. Мы построим модель с помощью функционального API, с которым вы познакомились на предыдущих шагах.
from tensorflow import keras from tensorflow.keras import layers from tensorflow.keras.datasets import mnist inputs = keras.Input(shape=(28, 28, 1)) x = layers.Conv2D(filters=32, kernel_size=3, activation="relu")(inputs) x = layers.MaxPooling2D(pool_size=2)(x) x = layers.Conv2D(filters=64, kernel_size=3, activation="relu")(x) x = layers.MaxPooling2D(pool_size=2)(x) x = layers.Conv2D(filters=128, kernel_size=3, activation="relu")(x) x = layers.Flatten()(x) outputs = layers.Dense(10, activation="softmax")(x) model = keras.Model(inputs=inputs, outputs=outputs)
Важно отметить, что данная сеть принимает на входе тензоры с формой
(высота_ изображения, ширина_изображения, каналы) ,
Рассмотрим поближе текущую архитектуру сети.
print(model.summary())
Model: "functional"
Layer (type) Output Shape Param #
input_layer (InputLayer) (None, 28, 28, 1) 0
conv2d (Conv2D) (None, 26, 26, 32) 320
max_pooling2d (MaxPooling2D) (None, 13, 13, 32) 0
conv2d_1 (Conv2D) (None, 11, 11, 64) 18,496
max_pooling2d_1 (MaxPooling2D) (None, 5, 5, 64) 0
conv2d_2 (Conv2D) (None, 3, 3, 128) 73,856
flatten (Flatten) (None, 1152) 0
dense (Dense) (None, 10) 11,530
Total params: 104,202 (407.04 KB)
Trainable params: 104,202 (407.04 KB)
Non-trainable params: 0 (0.00 B)
Как видите, все слои Conv2D и MaxPooling2D выводят трехмерный тензор с формой
(высота, ширина, каналы) .
Последний слой Conv2D выдает результат с формой (3, 3, 128) - карту признаков 3 * 3 со 128 каналами. Следующий шаг - передача этого результата на вход полносвязной классифицирующей сети, подобной той, с которой мы уже знакомы: стека слоев Dense. Эти классификаторы обрабатывают векторы - одномерные массивы, - тогда как текущий выход является трехмерным тензором. Чтобы преодолеть это несоответствие, мы преобразуем трехмерный вывод в одномерный с помощью слоя Flatten, а затем добавляем полносвязные слои Dense.
В заключение выполняется классификация по десяти категориям, поэтому последний слой имеет десять выходов и активацию softmax.
Теперь обучим сверточную сеть распознаванию цифр MNIST. Мы будем повторно брать большое количество программного кода из шагов, начиная с 26-го. Поскольку модель выполняет классификацию по десяти категориям с активацией softmax, мы используем функцию потерь категориальной перекрестной энтропии, а так как метки являются целыми числами, нам понадобится разреженная версия sparse_categorical_crossentropy.
(train_images, train_labels), (test_images, test_labels) = mnist.load_data() train_images = train_images.reshape((60000, 28, 28, 1)) train_images = train_images.astype("float32") / 255 test_images = test_images.reshape((10000, 28, 28, 1)) test_images = test_images.astype("float32") / 255 model.compile(optimizer="rmsprop", loss="sparse_categorical_crossentropy", metrics=["accuracy"]) model.fit(train_images, train_labels, epochs=5, batch_size=64)
Оценим модель на контрольных данных.
test_loss, test_acc = model.evaluate(test_images, test_labels) print(f"Test accuracy: {test_acc:.3f}") Test accuracy: 0.990
Полносвязная сеть из 26 шага показала точность 97,8% на контрольных данных, а простенькая сверточная нейронная сеть - 99,0%.
Но почему такая простая сверточная нейронная сеть работает намного лучше полносвязной модели? Чтобы ответить на этот вопрос, погрузимся в особенности работы слоев Conv2D и MaxPooling2D.
На следующем шаге мы рассмотрим операцию свертывания.