Обзор проекта

Этот пост подводит итог завершающему проекту, который я сделал для программы Udacity Data Science Nano Degree Program. Цель проекта — классифицировать изображения собак в соответствии с их породой. CNN (Сверточная нейронная сеть) — это методология, используемая для достижения цели.

Ссылка на Github Repo находится здесь: https://github.com/jl4730/DogBreed.

Постановка задачи

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

Метрика

Метрикой, используемой для оценки производительности модели CNN, является точность, которая представляет собой процент правильно классифицированных изображений в тестовых данных. Причина, по которой другие показатели из матрицы путаницы здесь не используются, заключается в том, что у нас действительно нет «ложноположительных» или «ложноотрицательных» здесь со 133 породами для классификации.

Во время каждой итерации нам нужно использовать параметры, обученные на обучающем наборе, для расчета потерь и точности проверки. В конце итераций к тестовому набору будет применен лучший набор параметров, и будет рассчитана окончательная точность.

Исследование и визуализация данных

Данные, используемые для этого проекта, представляют собой изображения собак и людей. После загрузки данных мы знаем, что существует 133 категории собак и 8351 изображение собак. Из которых 6680 находятся в обучающих наборах, 835 — в проверочном наборе и 836 — в тестовом наборе.

# вывести статистику по набору данных
print('Всего категорий собак: %d.' % len(dog_names))
print('Всего изображений собак: %s.\n' % len(np .hstack([train_files, valid_files, test_files])))
print('Имеется %d изображений тренировочных собак.' % len(train_files))
print('Имеется %d изображений проверяющих собак. ' % len(valid_files))
print('Имеется %d изображений тестовых собак.'% len(test_files))

Вот два примера изображений собак и людей:

Эталонная модель

Используемая здесь эталонная модель представляет собой 7-уровневую модель CNN с самообучением.

Эта выше модель создана с помощью кода Python:

model.add(Conv2D(filters=16, kernel_size=2, активация='relu',
input_shape=(224, 224, 3)))
model.add(MaxPooling2D(pool_size=2))
model.add(Conv2D(filters=32, kernel_size=2, активация='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(Conv2D( фильтры=64, kernel_size=2, активация='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(GlobalAveragePooling2D())
model.add( Плотный (133, активация = 'softmax'))

модель.резюме()

Указав эту архитектуру CNN, я скомпилировал и подогнал модель.

model.compile(optimizer=’rmsprop’, loss=’categorical_crossentropy’, metrics=[‘accuracy’])

checkpointer = ModelCheckpoint(filepath=’saved_models/weights.best.from_scratch.hdf5’,
verbose=1, save_best_only=True)

model.fit(train_tensors, train_targets,
validation_data=(valid_tensors, valid_targets),
epochs=epochs, batch_size=20, callbacks=[checkpointer], verbose=1)

Затем я загрузил лучшие параметры и проверил точность модели на тестовом наборе.

model.load_weights(‘saved_models/weights.best.from_scratch.hdf5’)

# получить индекс предсказанной породы собаки для каждого изображения в тестовом наборе
dog_breed_predictions = [np.argmax(model.predict(np.expand_dims(tensor, axis=0))) для тензора в test_tensors]

# отчет о точности теста
test_accuracy = 100*np.sum(np.array(dog_breed_predictions)==np.argmax(test_targets, axis=1))/len(dog_breed_predictions)
print(' Точность теста: %.4f%%' % test_accuracy)

Эта модель дает точность около 5%, что лучше, чем случайное предположение (1/133 породы).

Этапы предварительной обработки данных

При использовании TensorFlow в качестве бэкэнда для Keras CNN требуется массив 4D (который мы также будем называть тензором 4D) в качестве входных данных с формой (nb_samples, rows, столбцы, каналы), (nb_samples, rows, столбцы, каналы),

где nb_samples соответствует общему количеству изображений (или выборок), а rows, columns и channels соответствуют количеству строк, столбцов и каналов для каждого изображения соответственно.

Приведенная ниже функция path_to_tensor принимает в качестве входных данных путь к файлу со строковым значением к цветному изображению и возвращает четырехмерный тензор, подходящий для передачи в Keras CNN. Сначала функция загружает изображение и изменяет его размер до квадратного изображения размером 224×224224×224 пикселя. Затем изображение преобразуется в массив, размер которого затем изменяется до четырехмерного тензора. В данном случае, поскольку мы работаем с цветными изображениями, каждое изображение имеет три канала. Точно так же, поскольку мы обрабатываем одно изображение (или образец), возвращаемый тензор всегда будет иметь форму

(1,224,224,3).(1,224,224,3).

Функция paths_to_tensor принимает в качестве входных данных пустой массив путей изображения со строковым значением и возвращает 4D-тензор с формой

(nb_samples,224,224,3).(nb_samples,224,224,3).

Здесь nb_samples — это количество выборок или количество изображений в предоставленном массиве путей к изображениям. Лучше всего думать о nb_samples как о количестве трехмерных тензоров (где каждый трехмерный тензор соответствует другому изображению) в наборе данных!

def path_to_tensor(img_path):
# загружает RGB-изображение как тип PIL.Image.Image
img = image.load_img(img_path, target_size=(224, 224))
# конвертирует PIL.Image .Тип изображения в 3D-тензор с формой (224, 224, 3)
x = image.img_to_array(img)
# конвертировать 3D-тензор в 4D-тензор с формой (1, 224, 224, 3) и возврат 4D-тензора
возврат np.expand_dims(x, axis=0)

def paths_to_tensor(img_paths):
list_of_tensors = [path_to_tensor(img_path) для img_path в tqdm(img_paths)]
return np.vstack(list_of_tensors)

Выполнение

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

В начале трансферного обучения нам необходимо получить узкие места:

Bottleneck_features = np.load('bottleneck_features/DogVGG16Data.npz')
train_VGG16 = узкие_функции['поезд']
valid_VGG16 = узкие_функции['действительный']
test_VGG16 = узкие_функции['тест']

Затем мы можем указать последний сверточный слой через:

VGG16_model = Sequential()
VGG16_model.add(GlobalAveragePooling2D(input_shape=train_VGG16.shape[1:]))
VGG16_model.add(Dense(133, активация=’softmax’))

Остальная часть процесса такая же, как и на этапе эталонного тестирования.

Уточнение

Вместо использования VGG я, наконец, выбрал модель ResNet-50 для прогнозирования породы собак, которая достигла точности более 80% за 20 итераций.

Bottleneck_features = np.load(‘bottleneck_features/DogResnet50Data.npz’)
train_Resnet50 = узкие_функции[‘train’]
valid_Resnet50 = узкие_функции[‘valid’]
test_Resnet50 = узкие_функции[‘test’]

Resnet50_model = Sequential()
Resnet50_model.add(GlobalAveragePooling2D(input_shape=train_Resnet50.shape[1:]))
Resnet50_model.add(Dense(133, активация=’softmax’))

Мы определенно можем улучшить производительность, увеличив количество итераций. Я использовал только 20, и результаты уже приличные (точность 83%). Это может быть даже лучше с большим количеством эпох. Но для популяции, насчитывающей более 100 видов, 83% уже вполне прилично.

Результаты

Цель проекта — предсказать породу с помощью загружаемых пользователем изображений. Если на изображении будет обнаружена собака, он предоставит оценку породы собаки. Если человек будет обнаружен, он предоставит оценку породы собаки, которая больше всего похожа на него. Я проверил несколько изображений собак, и результаты довольно точны:

Обоснование

ResNet-50 является окончательным выбором, так как точность (83%) почти вдвое превышает точность модели VGG (43%). Основная причина может заключаться в том, что Resnet намного глубже по сравнению с VGG, где Resnet-50 относится к Resnet с 50 уровнями. Если мы добавим больше итераций к трансферному обучению (в настоящее время используется 20), уровень точности станет еще выше, что впечатляет.

Отражение

В этом проекте я создал классификатор пород собак, который может определить породу по загруженным пользователем фотографиям. Трансферное обучение использовалось для использования предварительно обученной модели ResNet-50. Проект начался с детектора собак и детектора человека для определения типа изображения. Затем проект прошел через 3 модели CNN: самообучаемый 6-слойный CNN, модель VGG и ResNet-50, из которых ResNet выбран, так как точность составляет более 80%.

Поскольку у меня нет собаки, я могу проверить только свою собственную фотографию, лол. Вот результат.

Модель правильно идентифицировала меня как человека, и это хорошо. Но трудно понять, почему я похож на Акиту, лол.

Будущие улучшения

В дальнейшем могу попробовать увеличить количество итераций и посмотреть, как в итоге сходится точность. Я также могу попробовать другую модель с еще лучшими характеристиками. Затем я могу развернуть веб-сайт для загрузки изображений и их классификации. Это будет очень весело!