Эта статья была изначально написана Раулем Гомесом Брубаллой и размещена в блоге Neptune.

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

В этом посте мы:

  • объясните теоретические концепции, лежащие в основе поиска изображений на основе содержания,
  • покажите шаг за шагом как создать систему поиска изображений на основе содержимого с помощью PyTorch, адресованную конкретному приложению: поиск изображений лиц с набором заданных атрибутов лица (например, мужчина, блондин, улыбающийся).

Объяснение концепций, которые могут быть интересны:

Потери ранжирования, Контрастные потери, Сиамские сети, Триплетные сети, Триплетные потери, Извлечение изображений

Получение изображений на основе содержимого: как создать их на высоком уровне

Чтобы найти изображения, наиболее близкие к заданному запросу, системе поиска изображений необходимо:

  • вычислить оценку сходства между всеми изображениями в тестовом наборе (часто называемом поисковым набором) и запросом.
  • ранжируйте все эти изображения по схожести с запросом,
  • верните верхние.

Распространенной стратегией изучения этих сходств является изучение представлений (часто называемых вложениями) изображений и запросов в одном и том же векторном пространстве (часто называемом пространством встраивания).

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

Нейронные сети используются для изучения вышеупомянутых вложений. В нашем случае сверточная нейронная сеть (CNN) используется для изучения встраивания изображений, а многослойный персептрон (MLP), который представляет собой набор полностью связанных слоев, используется для изучения встраивания векторов атрибутов.

Эти сети настроены по-сиамски и обучаются с потерей ранжирования (в нашем случае тройная потеря). Далее мы подробно объясним эти концепции.

Архитектура и утраты

Потери в рейтинге: тройное поражение

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

Для этого они вычисляют расстояние (то есть евклидово расстояние) между представлениями образцов и оптимизируют модель, чтобы минимизировать его для аналогичных образцов и максимизировать для разнородных образцов. Следовательно, модель в конечном итоге изучает похожие представления для образцов, которые вы определили как похожие, и отдаленные представления для образцов, которые вы определили как несходные.

Тройная потеря - это наиболее часто используемая потеря ранжирования. Он работает с тройками сэмплов, которые состоят из:

  • якорный образец (эталонный образец триплета).
  • положительный образец (который похож на якорь).
  • отрицательный образец (который не похож на якорь).

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

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

Другими словами: запас устанавливается, когда производительность сети для данного триплета уже оптимальна.

Триплетные потери формально определяются как:

L (a, p, n) = max (0, m + d (a, p) - d (a, n))

Где:

  • d - используемая функция расстояния (т.е. евклидово расстояние),
  • m - запас,
  • a, p и n представляют собой якорь, положительную и отрицательную выборки соответственно.

На наш взгляд, по примеру поиска атрибутов:

  • образец привязки - это изображение,
  • положительный образец - это вектор, кодирующий его атрибуты,
  • отрицательный образец - это вектор с несовпадающими атрибутами.

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

Легкие, сложные и полутвердые тройни

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

  • Простые тройки: отрицательный образец находится на достаточном расстоянии от опорного образца по сравнению с положительным. Потери равны 0, и градиенты равны.

d(a,n) > (d(a,p) + m)

  • Жесткие тройки. Отрицательное представление образца ближе к представлению образца привязки, чем положительное. Сеть неправильно различает положительные и отрицательные образцы этого триплета.

d(a,n) < d(a,p)

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

d(a,n) < (d(a,p) + m)

Сиамская сеть

Ранжирование потерь часто используется в сиамских сетевых архитектурах. Сиамские сети - это нейронные сети с общими параметрами, то есть с общими весами. Фактически это означает, что во время обучения мы оптимизируем одну нейронную сеть, несмотря на то, что она обрабатывает разные выборки.

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

Сети, обрабатывающие векторы атрибутов, будут сиамскими, что означает, что мы будем использовать одну и ту же сеть для пересылки их обоих. Это потому, что мы хотим изучить один и тот же экстрактор признаков как для положительных, так и для отрицательных векторов атрибутов.

Триплетные потери в PyTorch

PyTorch предоставляет реализацию Triplet Loss, называемую Triplet Margin Loss, которую вы можете найти здесь.

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

Вы можете создать его экземпляр, импортировав библиотеку нейронных сетей Pytorch и установив маржу:

import torch.nn as nn
criterion = nn.TripletMarginLoss(margin=0.1)

Точное значение маржи не критично для сходимости модели.

Тем не менее, вам необходимо убедиться, что разница расстояний, вычисленных по потерям, составляет около установленного вами значения. Хорошая практика - установить такой запас, чтобы в начале обучения половина триплетов были случайным образом правильными, а половина - нет. Обычно используется значение 0,1.

Чтобы вычислить потери в цикле обучения после того, как модель вычислила представления для триплетных выборок, вы должны вызвать:

loss = criterion(anchor, positive, negative)
loss.backward()

С триплетными сэмплами представления всегда в таком порядке.

Использование потери триплетов в Pytorch для поиска изображений лиц

Цель: найти изображения лиц с определенными атрибутами

Цель этого примера задачи - найти изображения лиц с определенными атрибутами. Для этого мы будем использовать набор данных изображений лиц с аннотированными двоичными атрибутами.

Используемый набор данных представляет собой Крупномасштабный набор данных атрибутов CelebFaces (CelebA), который содержит около 200 тысяч изображений лиц знаменитостей с 40 аннотированными двоичными атрибутами. Атрибуты кодируются как 40-мерные мульти-горячие векторы, которые содержат единицы для обозначения положительных атрибутов изображения лица и нули для остальных.

Чтобы вы почувствовали, что представляют собой аннотированные атрибуты, позвольте мне перечислить несколько:

  • Сумки под глазами
  • Заостренный нос
  • Усы
  • Ношение сережек
  • Ношение ожерелья
  • Овальное лицо

Полученная система поиска изображений нацелена на поиск изображений лиц с заданной комбинацией этих атрибутов. Здесь вы можете увидеть несколько примеров изображений в наборе данных:

Источник

Как создать тренировочную тройку

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

  1. Изображение (которое является якорем),
  2. Вектор его атрибутов (положительный),
  3. И вектор отрицательных атрибутов (отрицательных).

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

Далее вам нужно выбрать отрицательные атрибуты для нашего триплета. Вы могли просто:

  • Создайте случайный вектор multi-hot 40-D,
  • Проверьте, что отличается от положительного вектора,
  • Используйте это как отрицательное.

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

Общая стратегия, сохраняющая статистику набора данных, заключается в следующем:

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

Если self.attribute_vectors содержит все атрибуты обучающего набора:

while True:
    att_negative = random.choice(self.attribute_vectors)
    if not np.array_equal(att_n, att_positive):
        break

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

num_changes = random.randint(1,3)
att_negative = np.copy(att_positive)
for c in range(0,num_changes):
   att_idx = random.randint(0,len(att_negative) - 1)
   if att_positive[att_idx] == 0:
      att_negative[att_idx] = 1
   else:
      att_negative[att_idx] = 0

Обучение с помощью этих жестких отрицательных триплетов заставляет модель различать векторы атрибутов, которые похожи по всем атрибутам, кроме 1, 2 или 3.

Как спроектировать модель и обучить ее

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

Первое, что вам нужно сделать, это выбрать размерность этого пространства для вложения. Это зависит от сложности сходств, которые вы хотите изучить, но типичные размеры варьируются от 100 до 500. Мы выберем 300.

На следующем рисунке показана архитектура, которую мы будем использовать:

Чтобы изучить вложения изображений, мы используем CNN (например, ResNet-50) с тем же количеством выходов, что и размерность пространства встраивания. CNN принимает в качестве входных данных тензор изображения (img_a, который является якорем нашего триплета) [224x224x3] и выводит вектор размером 300 D (a).

Для изучения встраивания векторов атрибутов мы используем MLP, состоящий из двух 300-мерных линейных слоев с пакетной нормализацией и активациями ReLU. И положительные, и отрицательные выборки наших триплетов являются векторами атрибутов, и мы будем использовать одни и те же слои для их обработки, что известно как сиамская архитектура (показана желтым на рисунке).

После того, как вложения изображения и векторов атрибутов вычислены, мы нормализуем их в L2, чтобы гарантировать, что они имеют одну и ту же евклидову норму, и вводим их в Triplet Loss для вычисления расстояний между ними. В PyTorch мы можем записать наш цикл обучения как:

anchor = self.CNN(img_anchor)
positive = self.MLP(att_positive)
negative = self.MLP(att_negative)
loss = criterion(anchor, anchor, negative)
optimizer.zero_grad()
loss.backward()
optimizer.step()

Обратите внимание, что att_positive и att_negative обрабатываются одним и тем же MLP: мы используем для них сиамские сети.

Как следить за тренировкой

При использовании Triplet Loss для обучения модели поиска изображений отслеживать обучение труднее, чем в других сценариях, например, при обучении сети для классификации изображений. Это связано с тем, что для тестирования поиска изображений требуется встраивание изображений всего набора данных.

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

Процент правильных троек (простых отрицаний) в партии должен увеличиваться во время обучения, поскольку потери уменьшаются. Кроме того, этот% дает вам представление о том, насколько сложны триплеты для сети.

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

Используйте обученную модель для поиска изображений

Как только модель обучена, использовать ее для поиска изображений очень просто. Вам следует:

  1. Вычислите вложения всех изображений набора для поиска и сохраните их на диск.
  2. Вычислить вложение запроса (вектор атрибутов)
  3. Вычислите расстояния между внедрением запроса и всеми изображениями набора для поиска.
  4. Найдите самых близких.

Полученные результаты?

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

Выглядит неплохо!

Как оценить модель поиска изображений

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

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

  • Точность @ K (P @ K): учитываются только самые популярные K (обычно 1, 5, 10 или 100) извлеченных изображений. Он используется, когда вы заинтересованы только в правильном извлечении ограниченного количества изображений (системы рекомендаций) или когда набор извлекаемых изображений слишком велик для оценки всего ранжирования. Полученное изображение считается правильным, если оно содержит атрибуты запроса.

P @ K = правильные результаты в топовых K / K

При сообщении среднего P @ K для набора запросов этот показатель иногда записывается как AP @ K.

  • Средняя средняя точность (mAP): учитывает ранжирование всего набора для поиска. Он вычисляет P @ K для k = 1,2,…, N - количество изображений набора для поиска с атрибутами запроса. Затем он усредняет всю точность. Этот показатель дороже в вычислении и менее интуитивно понятен, но он глубоко оценивает поисковую систему.

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

Как всегда, есть масса вещей, которые могут пойти не так, поэтому позвольте мне поделиться своими извлеченными уроками:

  • Установка запаса: если в начале обучения потери уменьшаются, но количество правильных троек не увеличивается, возможно, вы установили слишком большой запас. Хорошая практика - установить маржу так, чтобы, когда вы начинаете тренировку, некоторые из троек уже случайно оказались правильными.
  • Отслеживайте правильные триплеты и используйте жесткие отрицания. Если большинство троек в ваших пакетах уже верны, измените стратегию интеллектуального анализа троек, чтобы использовать более жесткие отрицания, поскольку ваша модель ничего не извлекает из них. Однако помните о сохранении статистики набора данных.
    Может быть, вы просто хотите использовать определенный% жестких триплетов в своих партиях: это сильно зависит от вашей проблемы, но если ваши триплеты нереалистичны, вы можете в конечном итоге обучить свою сеть различать образцы, которые вы выиграли. Не нахожу ни в одном реалистичном сценарии.
  • Расчет расстояний во время извлечения. Убедитесь, что вы используете ту же функцию расстояния, что и при утере. Т.е. если потеря использует евклидово расстояние, вы также должны использовать его во время поиска.
  • Эффективность извлечения: если вы загрузите встраиваемые изображения из набора для извлечения в свой графический процессор и вычислите расстояния с помощью запроса в CUDA, извлечение будет намного быстрее для больших наборов данных.

Последние мысли

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

Дополнительные ресурсы

Смотрите также:

  1. Как проводить исследование данных для сегментации изображений и обнаружения объектов (вещи, которые мне пришлось усвоить на собственном горьком опыте)
  2. Как обучить свой собственный детектор объектов с помощью API обнаружения объектов Tensorflow

Эта статья изначально была написана Раулем Гомесом Брубаллой и размещена в блоге Neptune. Здесь вы можете найти более подробные статьи для практиков машинного обучения.