Если вы нетерпеливы, прокрутите до конца сообщения репозиторий Github

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

В этом руководстве мы рассмотрим создание классификатора глубокой нейронной сети, способного определять породу собаки по фотографии с использованием набора данных Dog Breed. Мы рассмотрим, как обучить модель, спроектировать входные и выходные данные для классификации категорий и, наконец, отобразить результаты точности для каждой модели.

Классификация изображений

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

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

Учитывая этот факт, весь конвейер классификации изображений можно формализовать следующим образом:

  • Наш вход - это обучающий набор данных, состоящий из N изображений, каждое из которых помечено одним из K разных классов.
  • Затем мы используем этот обучающий набор для обучения классификатора, чтобы узнать, как выглядит каждый из классов.
  • В конце концов, мы оцениваем качество классификатора, прося его предсказать метки для нового набора изображений, которые он никогда раньше не видел. Затем мы сравним истинные метки этих изображений с предсказанными классификатором.

Классификация изображений с помощью машинного обучения

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

Сверточные нейронные сети

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

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

Рассмотрим изображение 256 × 256. Вместо того, чтобы обрабатывать все изображение сразу, CNN может эффективно сканировать его фрагмент за фрагментом - скажем, окно 5 × 5. Окно 5 × 5 скользит по изображению (обычно слева направо и сверху вниз), как показано на рисунке ниже. То, насколько «быстро» он скользит, называется длиной его шага. Например, длина шага 2 означает, что скользящее окно 5 × 5 перемещается на 2 пикселя за раз, пока не охватит все изображение. Это окно 5 x 5 имеет связанную матрицу весов 5 x 5.

Манипуляции со скользящим окном происходят в сверточном слое нейронной сети. Типичная CNN имеет несколько слоев свертки. Каждый сверточный слой обычно генерирует множество альтернативных сверток, поэтому весовая матрица представляет собой тензор 5 × 5 × n, где n - количество сверток.

В качестве примера предположим, что изображение проходит через слой свертки на весовой матрице 5 × 5 × 64. Оно генерирует 64 свертки, сдвигая окно 5 × 5. Следовательно, эта модель имеет 5 × 5 × 64 (= 1600) параметров, что значительно меньше параметров, чем полностью подключенная сеть, 256 × 256 (= 65 536).

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

Набор данных о породе собак

Набор данных, над которым мы будем работать, доступен здесь. Предоставляется обучающий набор и тестовый набор изображений собак. У каждого изображения есть имя файла, которое является его уникальным идентификатором. Набор данных включает 120 пород собак. Чтобы упростить задачу, мы сократим набор данных до 8 основных пород. В приведенном ниже руководстве показано, как использовать TensorFlow для создания простой CNN с 3 сверточными слоями для классификации пород собак.

Обработка данных

1 - Пакеты

Давайте импортируем все необходимые пакеты.

2 - Распаковать файлы

Теперь нам нужно извлечь обучающие и тестовые файлы из zip-архива. Это код:

# We unzip the train and test zip file
archive_train = ZipFile("Data/train.zip", 'r')
archive_test = ZipFile("Data/test.zip", 'r')
# This line shows the 5 first image name of the train database
archive_train.namelist()[0:5]
# This line shows the number of images in the train database, noted that we must remove the 1st value (column header)
len(archive_train.namelist()[:]) - 1

Последняя строка кода должна вернуть значение 10 222.

3 - Изменить размер и нормализовать данные

Функция ниже создает файл рассола для сохранения всех изображений в распакованном виде.

Затем мы определяем новый размер изображения, применяемый для всех изображений, и вызываем указанную выше функцию.

image_resize = 60
DataBase_creator(archivezip = archive_train, nwidth = image_resize, nheight = image_resize , save_name = “train")
DataBase_creator(archivezip = archive_test, nwidth = image_resize, nheight = image_resize , save_name = "test")

Если вы используете ноутбук с процессором, мы должны увидеть, что использование времени составит около 40 секунд для почтового файла поезда и 41 секунды для тестового zip-файла.

Теперь у нас есть поезд и тестовые файлы рассола. В следующий раз, когда мы откроем этот код в Jupyter Notebook, мы сможем загрузить их напрямую, и шаг выше можно пропустить, если мы перезапустим код позже.

# load TRAIN
train = pickle.load( open( "train.p", "rb" ) )
train.shape

Форма обучающих данных должна быть (10222, 60, 60, 3).

# load TEST
test = pickle.load( open( "test.p", "rb" ) )
test.shape

Форма тестовых данных должна быть (10357, 60, 60, 3).

Все изображения имеют разную форму. Для нашей модели нам нужно изменить их размер до той же формы. Мы используем обычную практику, чтобы преобразовать их в квадрат. Нам также необходимо нормализовать наш набор данных, разделив на 255 все значения пикселей. Новые значения пикселей будут в диапазоне [0,1].

Давайте проверим одно изображение из набора данных для обучения:

lum_img = train[100,:,:,:]
plt.imshow(lum_img)
plt.show()

4 - Проверьте файл ярлыков

Теперь давайте увеличим масштаб файла метки CSV из данных поезда.

labels_raw = pd.read_csv("Data/labels.csv.zip", compression='zip', header=0, sep=',', quotechar='"')
labels_raw.sample(5)

5 - Извлеките наиболее представленные породы

Мы уменьшим базу данных, чтобы уменьшить сложность нашей модели. Кроме того, это поможет в расчетах, так как нужно будет классифицировать только N пород. Мы сможем легко запустить модель менее чем за 10 минут.

Мы должны увидеть этот вывод:

Давайте посмотрим на одно изображение:

lum_img = train_filtered[1,:,:,:]
plt.imshow(lum_img)
plt.show()

6 - Горячие ярлыки

Давайте сделаем быстрое кодирование для данных наших ярлыков.

# We select the labels from the N main breeds
labels = labels_filtered["breed"].as_matrix()
labels = labels.reshape(labels.shape[0],1) #labels.shape[0] looks faster than using len(labels)
labels.shape

Форма меток - (922, 1).

labels_name, labels_bin = matrix_Bin(labels = labels)
labels_bin[0:9]

7 - Быстрая проверка ярлыков

Посмотрим, какие N ярлыков мы сохраняем. Как вы увидите ниже по горячим этикеткам, вы можете найти, какой породе он соответствует.

for breed in range(len(labels_name)):
   print('Breed {0} : {1}'.format(breed,labels_name[breed]))

labels_cls = np.argmax(labels_bin, axis=1)
labels[0:9]

Сверточные нейронные сети

1 - Создание обучающих и проверочных данных

Мы разделяем наши данные поезда на две части: обучающий набор и проверочный набор. Таким образом, мы можем проверить точность модельного поезда, созданного из «обучающего набора», на проверочном наборе.

num_validation = 0.30
X_train, X_validation, y_train, y_validation = train_test_split(train_filtered, labels_bin, test_size=num_validation, random_state=6)

2 - Создание обучающих и тестовых данных

Вот код для разделения исходных данных на наборы для обучения и тестирования:

3 - CNN с TensorFlow - определение слоев

Архитектура будет такой:

  • 1-й сверточный слой с 32 фильтрами
  • Максимальное объединение
  • Relu
  • 2-й сверточный слой с 64 фильтрами
  • Максимальное объединение
  • Relu
  • 3-й сверточный слой со 128 фильтрами
  • Максимальное объединение
  • Relu
  • Выбывать
  • Свести слой
  • Полностью подключенный уровень с 500 узлами
  • Relu
  • Выбывать
  • Полностью связанный слой с n узлами (n = количество пород)

Вот краткое объяснение этих терминов:

  • Слой свертки: Как объяснялось в разделе CNN выше, на этом уровне мы сохраняем пространственные отношения между пикселями, изучая особенности изображения с использованием небольших квадратов входных данных. Эти квадраты входных данных также называются фильтрами или ядрами. Матрица, сформированная путем перемещения фильтра по изображению и вычисления скалярного произведения, называется Карта характеристик. Чем больше у нас фильтров, тем больше изображения функции извлекаются, и наша сеть становится лучше в распознавании закономерностей на невидимых изображениях.
  • Слой ReLU: чтобы нейронная сеть была мощной, она должна содержать нелинейность. ReLU - одна из таких нелинейных операций, что расшифровывается как Rectified Linear Unit. Это поэлементная операция, которая заменяет все отрицательные значения пикселей в карте признаков на 0. Мы передаем результат из сверточного слоя через функцию активации ReLU.
  • Максимальный уровень объединения: после этого мы выполняем операцию объединения, чтобы уменьшить размерность каждой карты функций. Это позволяет нам уменьшить количество параметров и вычислений в сети, тем самым контролируя переоснащение. CNN использует max-pooling, в котором он определяет пространственную окрестность и берет самый большой элемент из исправленной карты признаков в этом окне. После уровня объединения наша сеть становится инвариантной к небольшим преобразованиям, искажениям и трансляциям во входном изображении.
  • Полностью подключенный уровень: после этих слоев мы добавляем пару полносвязных слоев, чтобы завершить архитектуру CNN. Выходные данные слоев свертки и объединения представляют собой высокоуровневые функции входного изображения. Слои FC используют эти функции для классификации входного изображения по различным классам на основе набора обучающих данных. Помимо классификации, добавление слоев FC также помогает изучить нелинейные комбинации этих функций.
  • Слой исключения. Исключение - это метод регуляризации, помогающий сети избежать переобучения. Обычно во время обучения половина нейронов на определенном слое будет деактивирована. Это улучшает обобщение, поскольку вы заставляете свой слой учиться с разными нейронами. Обычно мы используем Dropout на полностью подключенных слоях, но также можно использовать Dropout после слоев максимального объединения, создавая некоторый вид увеличения шума изображения.

Если смотреть в целом, архитектура CNN выполняет 2 основные задачи: извлечение признаков (свертка + объединение слоев) и классификация (полносвязные слои). В общем, чем больше у нас шагов свертки, тем более сложные функции наша сеть сможет научиться распознавать.

Здесь мы определяем наши веса, смещения и другие константы.

Здесь мы определяем наш сверточный слой.

Здесь мы определяем наш плоский слой.

Здесь мы определяем наш полностью связанный слой.

4 - CNN с TensorFlow - настройка тензора заполнителя

Здесь мы настраиваем заполнитель для тензора в TensorFlow.

x = tf.placeholder(tf.float32, shape=[None, img_size, img_size, num_channels], name='x')
x_image = tf.reshape(x, [-1, img_size, img_size, num_channels]) #-1 put everything as 1 array
y_true = tf.placeholder(tf.float32, shape=[None, num_classes], name='y_true')
y_true_cls = tf.argmax(y_true, axis=1)
keep_prob_fc=tf.placeholder(tf.float32)
keep_prob_conv=tf.placeholder(tf.float32)

5 - CNN с TensorFlow - разработка слоя

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

6 - CNN с TensorFlow - потеря энтропии

Здесь мы определяем нашу функцию потерь для обучения нашей модели.

cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=layer_fc2, labels=y_true)
cost = tf.reduce_mean(cross_entropy)
optimizer = tf.train.AdamOptimizer(learning_rate=1e-4).minimize(cost)
correct_prediction = tf.equal(y_pred_cls, y_true_cls)
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

7 - CNN с TensorFlow - Обучите модель

А теперь давайте обучим нашу нейронную сеть!

session = tf.Session()
def init_variables():
   session.run(tf.global_variables_initializer())

Функция ниже создает пакет из набора данных. Мы используем пакет для обучения нашей модели.

init_variables()
total_iterations = 0
optimize(num_iterations=3500, X=250)

Как видите, модель имеет тенденцию к переобучению и не очень хороша.

8 - CNN с TensorFlow - результаты

Результаты не так хороши, так как точность всего 44%. Использование предварительно обученной модели с Keras даст вам лучший результат, но с этой моделью вы будете знать, как создать с нуля собственную CNN с помощью TensorFlow.

Имея больше фотографий собак, мы можем повысить точность. Кроме того, мы можем создавать новые изображения в нашем наборе обучающих данных, вращая изображения. это то, что мы называем увеличением изображения. Это поможет модели обнаружить узор, который может иметь различное «положение» в пространстве.

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

Посмотрим на результаты!

feed_dict_validation = {x: X_validation, y_true: y_validation, keep_prob_conv : 1, keep_prob_fc : 1}
df_validation_Predicted_cls = session.run(y_pred_cls, feed_dict=feed_dict_validation)
plot_images(images=X_validation[50:62], cls_true=df_validation_toPred_cls[50:62], cls_pred=df_validation_Predicted_cls [50:62])

i = 63
print(("True : {0} / {1}").format(df_validation_toPred_cls[i], labels_name[df_validation_toPred_cls[i]]))
print(("Pred : {0} / {1}").format(df_validation_Predicted_cls[i], labels_name[df_validation_Predicted_cls[i]]))
lum = X_validation[i,:,:,:]
plt.show()

plot_confusion_matrix(df_validation_toPred_cls,df_validation_Predicted_cls)

Как видите, модель не позволяет различить породу 1: bernese_mountain_dog и породу 2: entlebucher. Эти 2 породы очень похожи друг на друга (одинакового цвета и формы). Итак, кажется нормальным, что наша модель сделала несколько ошибок между этими двумя породами.

Наносети упрощают трансферное обучение

Испытав проблему точности при переносе обучения, я решил ее решить, создав простой в использовании облачный сервис глубокого обучения, который использует трансферное обучение. Он содержит набор предварительно обученных моделей, которые были обучены по миллионам параметров. Я могу загрузить данные Fashion MNIST, а затем служба выберет лучшую модель для использования в этой задаче. Наконец, он создает новую NanoNet поверх существующей предварительно обученной модели и подгоняет NanoNet к данным.

Поскольку модели NanoNets сильно предварительно обучены, я использовал гораздо меньший обучающий набор данных, всего ~ 100 изображений на класс. От этой модели я получил точность теста 83,3%. Это на 7% больше, чем у модели VGG19, несмотря на использование 1/60 данных! Причина, по которой модель NanoNets работает лучше, заключается в большом объеме предварительного обучения, оптимальном выборе гиперпараметров и увеличении данных.

Самое замечательное в NanoNets - это то, что любой может загружать данные и создавать свои собственные модели. Строить модели можно двумя способами:

1. Используя графический интерфейс: https://app.nanonets.com

2. Использование NanoNets API:

Https://github.com/NanoNets/image-classification-sample-python

Ниже мы дадим вам пошаговое руководство по обучению вашей собственной модели с использованием Nanonets API за 9 простых шагов.

Шаг 1. Клонируйте репо

git clone https://github.com/NanoNets/image-classification-sample-python.git
cd image-classification-sample-python
sudo pip install requests

Шаг 2. Получите бесплатный ключ API

Получите бесплатный ключ API на сайте http://app.nanonets.com/#/keys

Шаг 3. Задайте ключ API как переменную среды

export NANONETS_API_KEY=YOUR_API_KEY_GOES_HERE

Шаг 4: Создайте новую модель

python ./code/create-model.py

Примечание: это генерирует MODEL_ID, который вам нужен для следующего шага.

Шаг 5. Добавьте идентификатор модели как переменную среды

export NANONETS_MODEL_ID=YOUR_MODEL_ID

Шаг 6. Загрузите тренировочные данные

Соберите изображения объектов, которые вы хотите обнаружить. Когда у вас есть готовый набор данных в папке images (файлы изображений), начните выгрузку набора данных.

python ./code/upload-training.py

Шаг 7: модель обучения

После загрузки изображений приступайте к обучению модели.

python ./code/train-model.py

Шаг 8: Получите состояние модели

На обучение модели уходит ~ 30 минут. Вы получите электронное письмо после обучения модели. А пока вы проверяете состояние модели.

watch -n 100 python ./code/model-state.py

Шаг 9: сделайте прогноз

После того, как модель обучена. Вы можете делать прогнозы с помощью модели

python ./code/prediction.py PATH_TO_YOUR_IMAGE.jpg