День сообщества ML - 9 ноября! Присоединяйтесь к нам для обновления от TensorFlow, JAX, и многое другое Подробнее

Сверточная нейронная сеть (CNN)

Посмотреть на TensorFlow.org Запустить в Google Colab Посмотреть исходный код на GitHub Скачать блокнот

В этом руководстве демонстрируется обучение простой сверточной нейронной сети (CNN) для классификации изображений CIFAR . Поскольку в этом руководстве используется Keras Sequential API , для создания и обучения вашей модели потребуется всего несколько строк кода.

Импортировать TensorFlow

import tensorflow as tf

from tensorflow.keras import datasets, layers, models
import matplotlib.pyplot as plt

Загрузите и подготовьте набор данных CIFAR10

Набор данных CIFAR10 содержит 60 000 цветных изображений в 10 классах, по 6 000 изображений в каждом классе. Набор данных разделен на 50 000 обучающих изображений и 10 000 тестовых изображений. Классы являются взаимоисключающими, и между ними нет перекрытия.

(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data()

# Normalize pixel values to be between 0 and 1
train_images, test_images = train_images / 255.0, test_images / 255.0
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170500096/170498071 [==============================] - 11s 0us/step

Проверить данные

Чтобы убедиться, что набор данных выглядит правильно, давайте построим первые 25 изображений из обучающего набора и отобразим имя класса под каждым изображением:

class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',
               'dog', 'frog', 'horse', 'ship', 'truck']

plt.figure(figsize=(10,10))
for i in range(25):
    plt.subplot(5,5,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(train_images[i])
    # The CIFAR labels happen to be arrays, 
    # which is why you need the extra index
    plt.xlabel(class_names[train_labels[i][0]])
plt.show()

PNG

Создайте сверточную базу

6 строк кода ниже определяют основу свертки, используя общий шаблон: стек слоев Conv2D и MaxPooling2D .

В качестве входных данных CNN принимает тензоры формы (image_height, image_width, color_channels), игнорируя размер пакета. Если вы новичок в этих измерениях, color_channels относится к (R, G, B). В этом примере вы настроите свою CNN для обработки входных данных формы (32, 32, 3), которая является форматом изображений CIFAR. Вы можете сделать это, передав аргумент input_shape вашему первому слою.

model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))

Давайте пока что покажем архитектуру вашей модели:

model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 30, 30, 32)        896       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 15, 15, 32)        0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 13, 13, 64)        18496     
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 6, 6, 64)          0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 4, 4, 64)          36928     
=================================================================
Total params: 56,320
Trainable params: 56,320
Non-trainable params: 0
_________________________________________________________________

Выше вы можете видеть, что выходные данные каждого слоя Conv2D и MaxPooling2D представляют собой трехмерный тензор формы (высота, ширина, каналы). Размеры ширины и высоты имеют тенденцию уменьшаться по мере того, как вы углубляетесь в сеть. Количество выходных каналов для каждого уровня Conv2D определяется первым аргументом (например, 32 или 64). Как правило, по мере уменьшения ширины и высоты вы можете позволить (вычислительно) добавить больше выходных каналов на каждом уровне Conv2D.

Добавить плотные слои сверху

Чтобы завершить модель, вы передадите последний выходной тензор из сверточной базы (формы (4, 4, 64)) в один или несколько плотных слоев для выполнения классификации. Плотные слои принимают векторы в качестве входных данных (которые являются одномерными), в то время как текущий выход представляет собой трехмерный тензор. Сначала вы сведете (или развернете) трехмерный вывод до 1D, а затем добавите один или несколько плотных слоев поверх. CIFAR имеет 10 классов вывода, поэтому вы используете последний плотный слой с 10 выходами.

model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10))

Вот полная архитектура вашей модели:

model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 30, 30, 32)        896       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 15, 15, 32)        0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 13, 13, 64)        18496     
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 6, 6, 64)          0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 4, 4, 64)          36928     
_________________________________________________________________
flatten (Flatten)            (None, 1024)              0         
_________________________________________________________________
dense (Dense)                (None, 64)                65600     
_________________________________________________________________
dense_1 (Dense)              (None, 10)                650       
=================================================================
Total params: 122,570
Trainable params: 122,570
Non-trainable params: 0
_________________________________________________________________

Сводка сети показывает, что выходы (4, 4, 64) были сглажены в векторы формы (1024) перед прохождением через два плотных слоя.

Скомпилируйте и обучите модель

model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

history = model.fit(train_images, train_labels, epochs=10, 
                    validation_data=(test_images, test_labels))
Epoch 1/10
1563/1563 [==============================] - 7s 3ms/step - loss: 1.5216 - accuracy: 0.4446 - val_loss: 1.2293 - val_accuracy: 0.5562
Epoch 2/10
1563/1563 [==============================] - 5s 3ms/step - loss: 1.1654 - accuracy: 0.5857 - val_loss: 1.0774 - val_accuracy: 0.6143
Epoch 3/10
1563/1563 [==============================] - 5s 3ms/step - loss: 1.0172 - accuracy: 0.6460 - val_loss: 1.0041 - val_accuracy: 0.6399
Epoch 4/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.9198 - accuracy: 0.6795 - val_loss: 0.9946 - val_accuracy: 0.6540
Epoch 5/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.8449 - accuracy: 0.7060 - val_loss: 0.9169 - val_accuracy: 0.6792
Epoch 6/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.7826 - accuracy: 0.7264 - val_loss: 0.8903 - val_accuracy: 0.6922
Epoch 7/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.7338 - accuracy: 0.7441 - val_loss: 0.9217 - val_accuracy: 0.6879
Epoch 8/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.6917 - accuracy: 0.7566 - val_loss: 0.8799 - val_accuracy: 0.6990
Epoch 9/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.6431 - accuracy: 0.7740 - val_loss: 0.9013 - val_accuracy: 0.6982
Epoch 10/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.6074 - accuracy: 0.7882 - val_loss: 0.8949 - val_accuracy: 0.7075

Оцените модель

plt.plot(history.history['accuracy'], label='accuracy')
plt.plot(history.history['val_accuracy'], label = 'val_accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.ylim([0.5, 1])
plt.legend(loc='lower right')

test_loss, test_acc = model.evaluate(test_images,  test_labels, verbose=2)
313/313 - 0s - loss: 0.8949 - accuracy: 0.7075

PNG

print(test_acc)
0.7074999809265137

Ваш простой CNN достиг точности теста более 70%. Неплохо для нескольких строк кода! Чтобы узнать о другом стиле CNN, ознакомьтесь с кратким руководством TensorFlow 2 для экспертов, в котором используется API подклассаtf.GradientTape иtf.GradientTape .