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

Что такое система цветного поиска?

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

Очень хороший пример цветного поисковика - Multicolr. Давай, попробуй, это круто!

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

Определение проблемы

Для заданных N входных цветов RGB и N чисел с плавающей запятой от 0 до 1, которые образуют дискретное распределение вероятностей (сумма равна 1). Извлеките из коллекции изображений верхние K изображений, содержащих заданные цвета в качестве доминирующих цветов, так что распределение этих цветов в изображениях аналогично заданному распределению.

Пример запроса

Цвета [[142, 220, 20], [10, 30, 255]]. Распределение [0,6, 0,4]

K-ближайшие соседи

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

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

Первая стратегия представления: доминирующие цвета в изображении и их распределение

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

Затем можно вычислить распределение этих доминирующих цветов, просто нормализуя количество пикселей, принадлежащих каждому кластеру, на общее количество пикселей. Вектор, представляющий изображение, затем становится конкатенацией цветовых векторов RGB K наиболее доминирующих цветов и распределения вероятностей, отсортированных по убыванию количества пикселей, таким образом, вектор имеет ряд размеров (3 * N) + N. Представить запрос в виде вектора просто.

Затем нам нужно определить функцию, которая вычисляет расстояние между вектором запроса и вектором изображения. Структуры данных запроса расстояния, такие как K-D Tree и Ball tree, требуют, чтобы функция расстояния была истинной метрикой. Это означает, что он должен быть неотрицательным и симметричным, и он должен удовлетворять тождеству неразличимых и неравенству треугольника. Чтобы узнать больше о математических показателях расстояния, я отсылаю вас к этой статье в Википедии.

Цветовое расстояние

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

Расстояние распределения

Есть много способов измерить расстояние между распределениями вероятностей. На ум приходит одно популярное расхождение Кульбака – Лейблера. Однако это не настоящая метрика, поскольку она асимметрична. Другое расстояние распределения вероятностей - это расстояние Хеллингера, и оно оказывается истинной метрикой, поэтому я буду использовать его для вычисления несходства цветового распределения изображения и запроса.

Комбинированное расстояние

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

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

Ограничения комбинированной модели цвета и расстояния распределения

1. Порядок цветов имеет значение.

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

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

изображение = [0, 0, 255, 255, 0, 0, 0,51, 0,49]

Этот вектор говорит, что два наиболее доминирующих цвета в изображении - это синий (0, 0, 255) и красный (255, 0, 0) с нормализованным количеством пикселей 0,51 и 0,49 соответственно.

Теперь предположим, что мы получили запрос, который запрашивает синий (0, 0, 255) и красный (255, 0, 0), но с немного другим распределением 0,49 и 0,51 соответственно. Запрос будет отсортирован по цветовому распределению, а его вектор будет выглядеть так:

query = [255, 0, 0, 0, 0, 255, 0,51, 0,49]

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

2. Трудно найти компромисс между цветовым расстоянием и расстоянием распределения.

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

Лучшая стратегия представления: глубокое нейронное встраивание

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

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

Метрическое обучение с использованием тройной потери

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

Что, если бы мы могли сделать то же самое, но вместо набросков использовали бы запросы цвета? Это сработает? Давайте разберемся!

Набор данных

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

Для каждого изображения в наборе данных я извлек его 5 наиболее доминирующих цветов и соответствующее количество пикселей, применив K -средние к пикселям и взяв центры кластеров в качестве доминирующих цветов. Вот функция Python, которую я написал для извлечения доминирующих цветов и их распределения из изображения:

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

Вот пример изображения из Instagram и соответствующего ему эскиза:

Триплетный майнинг

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

Потеря триплета

Сеть будет предсказывать вложение (в основном D -мерный вектор) для каждого из трех входных изображений (см. Рисунок). Наша цель - сделать так, чтобы евклидовы расстояния в пространстве встраивания соответствовали некоторой комбинации цвета и расстояния распределения цвета.

Это достигается за счет минимизации так называемых триплетных потерь. Потери триплета для одного триплета векторов представления (a, p, n) выглядят следующим образом:

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

С маржей особо не экспериментировал; Я пробовал только два разных значения: m = 0 и m = 1. Я обнаружил, что если m = 0, модель сворачивается в состояние, в котором она выводит тот же вектор представления для любого входного изображения, так как это делает потерю равной 0. Это нежелательно, поскольку встраивание в этом случае пространство больше бесполезно. Поэтому я использовал m = 1.

Для более подробного объяснения того, как работает потеря триплетов, я отсылаю вас к этому прекрасному сообщению в блоге Оливье Мундро.

Сетевая архитектура

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

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

Вот код Python, описывающий модель триплета с использованием функционального API Keras:

Детали обучения

Я обучил описанную выше модель на триплетах, сгенерированных из набора данных Instagram. Данные не были не разделены на обучающие и тестовые наборы. Переоснащение не было проблемой, поскольку я использовал экстремальное увеличение данных: перетасовывал пиксели всех трех входных изображений. Был использован размер партии 64. Все изображения были изменены до (100, 100). Модель обучалась для 123 эпох по 100 партий в каждой.

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

Чтобы качественно оценить способность модели к обобщениям, я использовал набор данных цветов, который представляет собой набор данных из 8 тыс. Изображений цветов. Я передал все изображения в наборе данных цветов по сети, чтобы получить их вложения, затем я проиндексировал векторы встраивания с помощью модуля ближайших соседей scikit-learn.

Один из способов оценить, насколько хорошо модель усвоила цветовые представления, - это применить алгоритм кластеризации к векторам внедрения изображений и посмотреть на изображения, которые принадлежат одному кластеру. В идеале мы должны видеть изображения с похожими цветами в одних и тех же кластерах. В самом деле, вот несколько изображений, взятых из одного из кластеров, созданных путем применения K -средств с K = 100 к векторам внедрения:

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

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

Запрос 1

Цвета [[255, 0, 0], [255, 255, 0]]. Распределение [0,5, 0,5]

Запрос 2

Цвета [[255, 0, 0], [255, 255, 0]]. Распределение [0,3, 0,7]

Запрос 3