Практика: Распознавание собак и кошек на изображениях
В этой практической работе по курсу “Программирование глубоких нейронных сетей на Python” вы узнаете, как дообучить предварительно обученную нейронную сеть для распознавания кошек и собак на изображениях из соревнования Kaggle Dogs vs Cats.
Цель работы: научиться применять предварительно обученные нейронные сети для решения задач классификации изображений.
Предварительные сведения
Перед выполнением работы рекомендуется посмотреть два видео. Первое видео о подготовке набора данных с фотографиями собак и кошек для обучения нейронной сети:
Второе видео о технологии переноса обучения:
Необходимое программное обеспечение
Используется библиотека Keras, а также TensorFLow в качестве вычислительного бэкенда.
Инструкция по установке Keras и TensorFlow с дистрибутивом Anaconda.
Подготовка данных
Перед началом выполнения работы скачайте набор данных с фотографиями собак и кошек с сайта Kaggle. Вам нужен файл train.zip.
Разделите фотографии собак и кошек на три части: набор данных для обучения (train), проверки (validation) и тестирования (test). Для обучения можно использовать 70% фотографий, а для проверки и тестирования по 15%. В каждом наборе данных скопируйте фотографии собак в каталог dogs, а фотографии котов – в каталог cats. У вас должна получится такая структура каталогов:
cats_vs_dogs/
|----train/
| |----cats/
| |----dogs/
|
|----validation/
| |----cats/
| |----dogs/
|
|----test/
|----cats/
|----dogs/
Подробная инструкция с примером скрипта, который выполняет распределение фото по каталогам автоматически, есть в статье “Как подготовить набор изображений для обучения нейронной сети в Keras”.
Базовая версия программы
Базовая версия программы, в которой используется перенос обучения для распознавания собак и кошек.
from tensorflow.python.keras.preprocessing.image import ImageDataGenerator
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Activation, Dropout, Flatten, Dense
from tensorflow.python.keras.applications import VGG16
from tensorflow.python.keras.optimizers import Adam
# Каталог с данными для обучения
train_dir = 'train'
# Каталог с данными для проверки
val_dir = 'val'
# Каталог с данными для тестирования
test_dir = 'test'
# Размеры изображения
img_width, img_height = 150, 150
# Размерность тензора на основе изображения для входных данных в нейронную сеть
# backend Tensorflow, channels_last
input_shape = (img_width, img_height, 3)
# Размер мини-выборки
batch_size = 64
# Количество изображений для обучения
nb_train_samples = 17500
# Количество изображений для проверки
nb_validation_samples = 3750
# Количество изображений для тестирования
nb_test_samples = 3750
# Загружаем предварительно обученную нейронную сеть VGG16
vgg16_net = VGG16(weights='imagenet', include_top=False,
input_shape=(150, 150, 3))
# "Замораживаем" веса предварительно обученной нейронной сети VGG16
vgg16_net.trainable = False
# Создаем составную нейронную сеть на основе VGG16
# Создаем последовательную модель Keras
model = Sequential()
# Добавляем в модель сеть VGG16 вместо слоя
model.add(vgg16_net)
# Добавляем в модель новый классификатор
model.add(Flatten())
model.add(Dense(256))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))
# Компилируем составную нейронную сеть
model.compile(loss='binary_crossentropy',
optimizer=Adam(lr=1e-5),
metrics=['accuracy'])
# Создаем генератор изображений на основе класса ImageDataGenerator.
# Генератор делит значения всех пикселов изображения на 255.
datagen = ImageDataGenerator(rescale=1. / 255)
# Генератор данных для обучения на основе изображений из каталога
train_generator = datagen.flow_from_directory(
train_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='binary')
# Генератор данных для проверки на основе изображений из каталога
val_generator = datagen.flow_from_directory(
val_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='binary')
# Генератор данных для тестирования на основе изображений из каталога
test_generator = datagen.flow_from_directory(
test_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='binary')
# Обучаем модель с использованием генераторов
model.fit_generator(
train_generator,
steps_per_epoch=nb_train_samples // batch_size,
epochs=10,
validation_data=val_generator,
validation_steps=nb_validation_samples // batch_size)
# Оцениваем качество работы сети с помощью генератора
scores = model.evaluate_generator(test_generator, nb_test_samples // batch_size)
print("Аккуратность на тестовых данных: %.2f%%" % (scores[1]*100))
Также базовую версию программы можно найти в репозитории примеров курса.
Для начала запустите базовую версию программы:
python cats_dogs.py
Примерный вывод программы:
Using TensorFlow backend.
Found 17500 images belonging to 2 classes.
Found 3750 images belonging to 2 classes.
Found 3750 images belonging to 2 classes.
Epoch 1/10
273/273 [==============================] - 462s - loss: 0.2524 - acc: 0.8857 - val_loss: 0.1329 - val_acc: 0.9472
Epoch 2/10
273/273 [==============================] - 458s - loss: 0.0975 - acc: 0.9630 - val_loss: 0.1237 - val_acc: 0.9512
Epoch 3/10
273/273 [==============================] - 454s - loss: 0.0606 - acc: 0.9762 - val_loss: 0.0804 - val_acc: 0.9710
Epoch 4/10
273/273 [==============================] - 454s - loss: 0.0446 - acc: 0.9840 - val_loss: 0.0791 - val_acc: 0.9696
Epoch 5/10
273/273 [==============================] - 454s - loss: 0.0254 - acc: 0.9915 - val_loss: 0.0976 - val_acc: 0.9699
Epoch 6/10
273/273 [==============================] - 453s - loss: 0.0169 - acc: 0.9942 - val_loss: 0.0883 - val_acc: 0.9693
Epoch 7/10
273/273 [==============================] - 451s - loss: 0.0125 - acc: 0.9960 - val_loss: 0.0702 - val_acc: 0.9740
Epoch 8/10
273/273 [==============================] - 452s - loss: 0.0146 - acc: 0.9951 - val_loss: 0.1078 - val_acc: 0.9704
Epoch 9/10
273/273 [==============================] - 450s - loss: 0.0049 - acc: 0.9986 - val_loss: 0.1971 - val_acc: 0.9563
Epoch 10/10
273/273 [==============================] - 451s - loss: 0.0054 - acc: 0.9983 - val_loss: 0.1101 - val_acc: 0.9756
Аккуратность на тестовых данных: 97.31%
Запишите точность работы сети после обучения на тестовых данных. Она приводится в последней строке вывода:
Аккуратность на тестовых данных: 97.31%
Проанализируйте точность на проверочной выборке в процессе обучения. Она указывается после заголовка val_acc. Началось ли переобучение нейронной сети?
Экспериментируем с гиперпараметрами обучения
Мы попытаемся улучшить качество обучения сети путем изменения гиперпараметров. Для этого проведем серию экспериментов, в каждом из которых будем менять один из гиперпараметров, и анализировать, как изменилось качество работы сети.
-
Изменение параметров классификатора. Попробуйте изменить параметры нового классификатора, который мы добавили к модели VGG16:
# Добавляем в модель новый классификатор model.add(Flatten()) model.add(Dense(256)) model.add(Activation('relu')) model.add(Dropout(0.5)) model.add(Dense(1)) model.add(Activation('sigmoid'))Измените количество нейронов в первом полносвязном (
Dense) слое, попробуйте добавить еще один полносвязный слой в классификатор (или несколько полносвязных слоев) с разным количеством нейронов. Оцените, как это влияет на качество распознавания.Оцените роль слоя регуляризации
Dropout. Попробуйте убрать его и сети и посмотреть, что произойдет. Попробуйте изменить значение параметра слояDropoutс 0.5 на другое и посмотреть, как это влияет на качество распознавания. -
Другие предварительно обученные сети. Попробуйте вместо
VGG16использовать другую предварительно обученную нейронную сеть. Список доступных сетей есть на странице Keras Applications. Например, для использования сети GoogleInceptionv3:# Подключаем модуль с сетью Inceptionv3 from tensorflow.python.keras.applications import InceptionV3 ... # Загружаем предварительно обученную нейронную сеть Inceptionv3 inception_net = InceptionV3(weights='imagenet', include_top=False, input_shape=(150, 150, 3)) # "Замораживаем" веса предварительно обученной нейронной сети Inceptionv3 inception_net.trainable = False ... # Создаем составную нейронную сеть на основе Inceptionv3 # Создаем последовательную модель Keras model = Sequential() # Добавляем в модель сеть Inceptionv3 вместо слоя model.add(inception_net) ...Оцените качество работы сети на основе
Inceptionv3и сравните с качеством сетиVGG16. Попробуйте также использовать сетиResNet50иInceptionResNetV2. Если есть желание, то исследуйте качество работы других предварительно обученных нейронных сетей, входящих в Keras.С сетями
Inceptionv3,ResNet50и другими, более новыми, вы можете в классификаторе вместо слояFlattenиспользовать слойGlobalAveragePooling2D. Оцените, как это влияет на качество обучения. -
Время обучения сети. Сети
Inceptionv3иResNet50обеспечивают лучшее качество распознавания, но содержат гораздо больше слоев, чем сетьVGG16. УResNet50, как понятно из названия, 50 слоев, уInceptionv3- 159 слоев. СетьInceptionResNetV2содержит 578 слоев. Чем большое слоев в сети, тем больше времени требуется для ее дообучения. Постарайтесь подобрать компромиссный вариант предварительно обученной нейронной сети с учетом точности распознавания и времени обучения.
Выбираем лучшие гиперпараметры
Создайте сеть с лучшими значениями всех гиперпараметров обучения, которые вы определили на предыдущем шаге. Учитывайте не только точность работы, но и время обучения сети. Что можно сделать, чтобы еще больше увеличить точность?
Расскажите о своих результатах
Пишите в комментариях, какой точности вам удалось достичь, и какие предварительно обученные сети и гиперпараметры вы при этом использовали.
