10 минут до создания классификатора двоичных изображений CNN в TensorFlow
Как построить бинарный классификатор изображений с использованием слоев сверточной нейронной сети в TensorFlow / Keras
Это краткое введение в компьютерное зрение, а именно, как создать классификатор двоичных изображений с использованием слоев сверточной нейронной сети в TensorFlow / Keras, ориентированный в основном на новых пользователей. Это простое в использовании руководство разбито на 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. Если вас интересуют подобные простые и серьезные уроки, подобные этому, пожалуйста, ознакомьтесь с другими моими рассказами!