«Собака — джентльмен; Я надеюсь попасть на его небеса, а не на мужчин». - Марк Твен

Существует много разных пород собак, и некоторым людям трудно отличить, например, аляскинского маламута от сибирского хаски. Более 340 различных пород, признанных Международной кинологической федерацией.

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

Помимо создания классификатора собак в этом проекте, мы также будем использовать созданную классификацию для классификации человеческих лиц и похожих на них пород собак. Мы разобьем этот подход на X простых шагов.

Шаг 1: Загрузка и импорт набора данных.

Первый набор данных состоит из 13233 изображений человека.

Второй набор данных состоит из 8351 изображения собак.

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

def load_dataset(path):
    data = load_files(path)
    dog_files = np.array(data['filenames'])
    dog_targets = np_utils.to_categorical(np.array(data['target']), 133)
    return dog_files, dog_targets
# load train, test, and validation datasets
train_files, train_targets = load_dataset('path/to/yourdata/dog_images/train')
valid_files, valid_targets = load_dataset('path/to/yourdata/dog_images/valid')
test_files, test_targets = load_dataset('path/to/yourdata/dog_images/test')

После создания нашей функции у нас есть 6680 тренировочных изображений, 835 проверочных изображений и 836 тестовых изображений из 133 категорий собак. Что приводит к расколу 80/10/10.

Шаг 2. Создание детектора лиц и детектора собак с помощью OpenCV.

OpenCV — это библиотека, которая предоставляет сотни различных алгоритмов компьютерного зрения. Мы будем использовать OpenCV каскадные классификаторы на основе признаков Хаара для обнаружения человеческих лиц. На следующем шаге нам нужно загрузить предварительно обученные детекторы лиц, хранящиеся на Github. Мы будем использовать фронтальный каскад хаара.

import cv2                               
# extract pre-trained face detector
face_cascade = cv2.CascadeClassifier('path_to_haarcascade_xml/haarcascade_frontalface_alt.xml')

После загрузки и создания нашего face_cascade мы хотим создать детектор лиц:

# returns "True" if face is detected in image stored at img_path
def face_detector(img_path):
    img = cv2.imread(img_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray)
    return len(faces) > 0

После создания нашего детектора лиц нам нужно создать детектор собак. Для этого мы будем использовать ResNet-50, предварительно обученную модель компьютерного зрения для классификации изображений.

from keras.applications.resnet50 import ResNet50
# define ResNet50 model
ResNet50_model = ResNet50(weights='imagenet')
def dog_detector(img_path):
    prediction = ResNet50_predict_labels(img_path)
    return ((prediction <= 268) & (prediction >= 151))

Следующий dog_detector выведет метку из словаря ResNet50. Между номерами 151 и 268 находится другая категория собак от бордер-колли до уокер-фоксхаунд.

Шаг 3: Создайте CNN

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

def path_to_tensor(img_path):
    # loads RGB image as PIL.Image.Image type
    img = image.load_img(img_path, target_size=(224, 224))
    # convert PIL.Image.Image type to 3D tensor with shape (224, 224, 3)
    x = image.img_to_array(img)
    # convert 3D tensor to 4D tensor with shape (1, 224, 224, 3) and return 4D tensor
    return np.expand_dims(x, axis=0)
def paths_to_tensor(img_paths):
    list_of_tensors = [path_to_tensor(img_path) for img_path in tqdm(img_paths)]
    return np.vstack(list_of_tensors)
#we need to divide every pixel in every image by 255.
# pre-process the data for Keras
train_tensors = paths_to_tensor(train_files).astype('float32')/255
valid_tensors = paths_to_tensor(valid_files).astype('float32')/255
test_tensors = paths_to_tensor(test_files).astype('float32')/255

Разделив, мы масштабируем картинку до нужного размера. После предварительной обработки мы переходим к созданию нашей CNN.

model = Sequential()
model.add(Conv2D(filters=16, kernel_size=2, input_shape=(224, 224, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=2, data_format='channels_last'))

model.add(Conv2D(filters=32, kernel_size=2, activation='relu'))
model.add(MaxPooling2D(pool_size=2, data_format='channels_last'))

model.add(Conv2D(filters=64, kernel_size=2, activation='relu'))
model.add(MaxPooling2D(pool_size=2, data_format='channels_last'))
model.add(GlobalAveragePooling2D())
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])

Мы создали очень простую модель, в которой используется функция активации relu в конце каждого слоя и MaxPooling. Мы используем кросс-энтропийную функцию и rmsprop в качестве оптимизатора. Мы обучаем эту модель в течение 25 эпох, которых должно быть достаточно для первого создания. Наша модель имеет точность 1,19%, что лучше, чем случайное угадывание 133 различных пород.

Шаг 4. Перенесите обучение с помощью Resnet для повышения точности

Как вы могли догадаться, точность 1,19% не очень хороша для использования в продакшене, поэтому мы будем использовать ResNet и оптимизировать его для нашего набора данных изображений.

#Create the model
Resnet50_model = Sequential()
Resnet50_model.add(GlobalAveragePooling2D(input_shape=(train_ResNet_50.shape[1:])))
Resnet50_model.add(Dense(133, activation='softmax'))
Resnet50_model.summary()

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

Resnet50_model.compile(loss='categorical_crossentropy', optimizer='rmsprop')

Обучите модель:

checkpointer = ModelCheckpoint(filepath='saved_models/weights.best.Resnet50.hdf5', 
                               verbose=1, save_best_only=True)
Resnet50_model.fit(train_ResNet_50, train_targets, 
          validation_data=(valid_ResNet_50, valid_targets),
          epochs=20, batch_size=20, callbacks=[checkpointer], verbose=1)

После обучения и загрузки нашей лучшей модели мы достигли точности теста 81,56%.

Шаг 5: Создайте наше приложение для идентификации собак

def dog_identification_app(img_path):
    
    display(Image(img_path,width=200,height=200))
    breed = resnet50_prediction_breed(img_path)
    if dog_detector(img_path):
        print("Hello, dog! You look like a {}\n".format(breed))
    elif face_detector(img_path):
        print("Hello, human! You look like a {}\n".format(breed))
    else:
        print("Uhmmm You are not a dog or a human! Can you please try another picture? THANKS")

Ввод представляет собой изображение, которое сначала отображается, а затем проверяется с помощью созданного нами dog_detector, собака это или человек. Если наше входное изображение не является ни собакой, ни человеком, оно вернет:

Uhmmm Вы не собака или человек! Не могли бы вы попробовать другую картинку? БЛАГОДАРНОСТЬ

На рисунках выше показано, как работает наше приложение.

Заключение и перспективы:

Обучение CNN с нуля может занять от нескольких минут до нескольких часов, но, возможно, это не удовлетворит наши потребности. Трансферное обучение подходит для большинства случаев использования, таких как создание классификатора собак.

Это был довольно забавный проект по созданию CNN с нуля и использованию простой архитектуры Keras NN для создания классификатора изображений. Проект работает очень хорошо, если все параметры хорошие, а порода собак находится в классификаторе CNN.

Есть достаточно моментов, которые можно улучшить, например:

  • входное изображение должно показывать переднюю часть лица, но мы также можем использовать другие XML-файлы для обнаружения лиц из OpenCV для дальнейшего улучшения нашей модели.
  • Мы также могли бы улучшить предварительную обработку с помощью преобразователей и повысить производительность модели.
  • Добавьте параметры входного изображения, если хотите, чтобы собака, кошка, другие животные выглядели как.
  • Создайте простое веб-приложение с помощью Flask на Heroku

На моем, GitHub — это также подход с PyTorch с другой и более сложной архитектурой модели.

Если вы хотите увидеть все шаги по созданию проекта, вы можете увидеть их в следующем Git-репозитории:

Оба набора данных взяты из Udacity.

Большое спасибо, что нашли время, чтобы прочитать этот пост в блоге.