10 минут до создания классификатора двоичных изображений CNN в TensorFlow

Как построить бинарный классификатор изображений с использованием слоев сверточной нейронной сети в TensorFlow / Keras

Это краткое введение в компьютерное зрение, а именно, как создать классификатор двоичных изображений с использованием слоев сверточной нейронной сети в TensorFlow / Keras, ориентированный в основном на новых пользователей. Это простое в использовании руководство разбито на 3 раздела:

  1. Данные
  2. Архитектура модели
  3. Точность, кривая ROC и AUC

Требования: ничего! Все, что вам нужно, чтобы следовать этому руководству, - это записная книжка Google Colab, содержащая данные и код. Google Colab позволяет писать и запускать код Python в браузере без какой-либо настройки и включает бесплатный доступ к графическому процессору!

1. Данные

Мы собираемся создать классификатор изображений одуванчика и травы. Я создал небольшой набор данных изображений, используя изображения из Google Images, которые вы можете загрузить и проанализировать в первых 8 ячейках руководства.

К концу этих 8 строк визуализация образца набора данных изображения будет выглядеть примерно так:

Обратите внимание, что некоторые изображения в наборе данных не являются идеальным изображением травы или одуванчиков. Для простоты давайте исправим это и перейдем к тому, как легко создать наш набор данных для обучения и проверки.

Данные, которые мы получили ранее, разделены на две папки: train и valid. В этих папках папкиdandelion и grass содержат изображения каждого класса. Чтобы создать набор данных, давайте воспользуемся классом keras.preprocessing.image.ImageDataGenerator для создания набора данных для обучения и проверки и нормализации наших данных. Что делает этот класс, так это создает набор данных и автоматически маркирует за нас, позволяя нам создать набор данных всего в одной строке!

2. Модельная архитектура

В начале этого раздела мы сначала импортируем TensorFlow.

Давайте тогда добавим наши слои CNN. Сначала мы добавим сверточный 2D-слой с 16 фильтрами, ядром 3x3, входным размером как наши размеры изображения, 200x200x3, и активацией как ReLU.

tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(200, 200, 3))

После этого мы добавим слой с максимальным объединением, который уменьшит размер изображения вдвое, так что после этого слоя результат будет 100x100x3.

tf.keras.layers.MaxPooling2D(2, 2)

Мы сложим 5 из этих слоев вместе, и каждый последующий CNN будет добавлять новые фильтры.

Наконец, мы сгладим выходные данные слоев CNN, подадим их на полностью связанный слой, а затем на сигмовидный слой для двоичной классификации.

Вот модель, которую мы построили:

model = tf.keras.models.Sequential([
# Note the input shape is the desired size of the image 200x200 with 3 bytes color
# This is the first convolution
tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(200, 200, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
# The second convolution
tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# The third convolution
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# The fourth convolution
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# # The fifth convolution
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# Flatten the results to feed into a DNN
tf.keras.layers.Flatten(),
# 512 neuron hidden layer
tf.keras.layers.Dense(512, activation='relu'),
# Only 1 output neuron. It will contain a value from 0-1 where 0 for 1 class ('dandelions') and 1 for the other ('grass')
tf.keras.layers.Dense(1, activation='sigmoid')

Давайте посмотрим вкратце построенной нами модели:

Model: "sequential" _________________________________________________________________ Layer (type)                 Output Shape              Param #    ================================================================= conv2d (Conv2D)              (None, 198, 198, 16)      448        _________________________________________________________________ max_pooling2d (MaxPooling2D) (None, 99, 99, 16)        0          _________________________________________________________________ conv2d_1 (Conv2D)            (None, 97, 97, 32)        4640       _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 48, 48, 32)        0          _________________________________________________________________ conv2d_2 (Conv2D)            (None, 46, 46, 64)        18496      _________________________________________________________________ max_pooling2d_2 (MaxPooling2 (None, 23, 23, 64)        0          _________________________________________________________________ conv2d_3 (Conv2D)            (None, 21, 21, 64)        36928      _________________________________________________________________ max_pooling2d_3 (MaxPooling2 (None, 10, 10, 64)        0          _________________________________________________________________ conv2d_4 (Conv2D)            (None, 8, 8, 64)          36928      _________________________________________________________________ max_pooling2d_4 (MaxPooling2 (None, 4, 4, 64)          0          _________________________________________________________________ flatten (Flatten)            (None, 1024)              0          _________________________________________________________________ dense (Dense)                (None, 512)               524800     _________________________________________________________________ dense_1 (Dense)              (None, 1)                 513        ================================================================= Total params: 622,753 Trainable params: 622,753 Non-trainable params: 0

Затем мы настроим спецификации для обучения модели. Тренируем нашу модель с проигрышем binary_crossentropy. Мы будем использовать оптимизатор RMSProp. RMSProp - разумный алгоритм оптимизации, потому что он автоматизирует настройку скорости обучения для нас (в качестве альтернативы, мы могли бы также использовать Adam или Adagrad для аналогичных результатов). Мы добавим точность к metrics, чтобы модель отслеживала точность во время обучения.

model.compile(loss='binary_crossentropy',
optimizer=RMSprop(lr=0.001),
metrics='accuracy')

Тренируемся 15 эпох:

history = model.fit(train_generator,
steps_per_epoch=8,
epochs=15,
verbose=1,
validation_data = validation_generator,
validation_steps=8)

3. Точность, кривая ROC и AUC.

Давайте оценим точность нашей модели:

model.evaluate(validation_generator)

Теперь давайте рассчитаем нашу кривую ROC и построим ее.

Во-первых, давайте сделаем прогнозы на основе нашего набора для проверки. При использовании генераторов для прогнозирования мы должны сначала отключить перемешивание (как мы это делали при создании validation_generator) и сбросить генератор:

STEP_SIZE_TEST=validation_generator.n//validation_generator.batch_size
validation_generator.reset()
preds = model.predict(validation_generator,
verbose=1)

Чтобы построить кривую ROC и AUC, нам нужно вычислить частоту ложных и истинно положительных результатов:

fpr, tpr, _ = roc_curve(validation_generator.classes, preds)
roc_auc = auc(fpr, tpr)
plt.figure()
lw = 2
plt.plot(fpr, tpr, color='darkorange',
lw=lw, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
plt.show()

Кривая ROC - это кривая вероятности, отображающая соотношение истинно-положительных результатов (TPR) и ложноположительных результатов (FPR).

Точно так же AUC (площадь под кривой), как показано в легенде выше, измеряет, насколько наша модель способна различать наши два класса, одуванчики и траву. Он также используется для сравнения различных моделей, что я буду делать в будущих уроках, когда я расскажу, как построить классификатор изображений с использованием полносвязных слоев, а также передать обучение с помощью ResNet!

Наконец, в конце блокнота у вас будет возможность делать прогнозы на основе собственных изображений!

Я надеюсь, что это дает вам легкое введение в создание простого двоичного классификатора изображений с использованием слоев CNN. Если вас интересуют подобные простые и серьезные уроки, подобные этому, пожалуйста, ознакомьтесь с другими моими рассказами!