Необоснованная эффективность представлений глубокого обучения

Хотите узнать о прикладном искусственном интеллекте у ведущих специалистов Кремниевой долины или Нью-Йорка? Узнайте больше о программе Искусственный интеллект на сайте Insight.

Вы - компания, работающая в области искусственного интеллекта, и хотели бы принять участие в программе Insight AI Fellows Program? Не стесняйтесь связаться.

Чтобы получить больше подобных материалов, подписывайтесь на Insight и Emmanuel в Twitter.

Почему поиск сходства?

Изображение стоит тысячи слов и даже больше строк кода.

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

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

Вот почему многие команды - например, в Pinterest, StitchFix и Flickr - начали использовать Deep Learning, чтобы изучать представления своих изображений, и предоставляют рекомендации на основе контента, который пользователи находят визуально приятным. . Точно так же сотрудники Insight использовали глубокое обучение для создания моделей для таких приложений, как помощь людям в поиске кошек для усыновления, рекомендации для покупки солнцезащитных очков и поиск художественных стилей.

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

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

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

Этот пост сопровождается записной книжкой с комментариями с использованием streamlit и самостоятельной кодовой базой, демонстрирующей и применяющей все эти методы. Не стесняйтесь запускать код и следовать!

Какой у нас план?

Перерыв в разговоре об оптимизации

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

Представим себе несколько подходов:

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

2 / Другой подход заключается в построении модели, которая берет два изображения и выводит оценку попарного сходства от 0 до 1 (например, Сиамские сети [PDF]). Эти модели точны для больших наборов данных, но приводят к другой проблеме масштабируемости. Обычно мы хотим найти похожее изображение, просматривая обширную коллекцию изображений, поэтому мы должны запустить нашу модель подобия один раз для каждой пары изображений в нашем наборе данных. Если наша модель - CNN, и у нас более дюжины изображений, это становится слишком медленным, чтобы его даже можно было рассматривать. Кроме того, это работает только для схожести изображений, но не для текстового поиска. Этот метод масштабируется до больших наборов данных, но работает медленно.

3 / Есть более простой метод, похожий на вложения слов. Если мы найдем выразительное векторное представление или вложение для изображений, мы сможем вычислить их сходство, посмотрев, насколько близки их векторы друг к другу. Этот тип поиска - распространенная проблема, которая хорошо изучена, и многие библиотеки реализуют быстрые решения (здесь мы будем использовать Annoy). Кроме того, если мы заранее вычислим эти векторы для всех изображений в нашей базе данных, этот подход будет быстрым (один прямой проход и эффективный поиск сходства) и масштабируемым. Наконец, если нам удастся найти общие вложения для наших изображений и слов, мы сможем использовать их для поиска текста в изображение!

Из-за своей простоты и эффективности третий метод будет в центре внимания этой статьи.

Как нам туда добраться?

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

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

  • Поиск изображений, похожих на входное (Изображение → Изображение)
  • Поиск слов, похожих на введенное слово (Текст → Текст)
  • Создание тегов для изображений и поиск изображений с помощью tex t (Изображение ↔ Текст)

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

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

Начнем с набора данных, с которым можно поэкспериментировать.

Набор данных

Изображений

Наш набор данных изображений состоит из 1000 изображений, разделенных на 20 классов по 50 изображений в каждом. Этот набор данных можно найти здесь. Не стесняйтесь использовать сценарий в связанном коде для автоматической загрузки всех файлов изображений. Благодарим Сайруса Раштчиана, Питера Янга, Мики Ходоша и Джулии Хокенмайер за набор данных.

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

aeroplane bicycle bird boat bottle bus car cat chair cow dining_table dog horse motorbike person potted_plant sheep sofa train tv_monitor

Мы видим, что наши ярлыки довольно шумные: многие фотографии содержат несколько категорий, и ярлык не всегда выбирается из самой заметной. Например, в правом нижнем углу изображение помечено chair, а не person, хотя в центре изображения стоят 3 человека, а стул едва виден.

Текст

Кроме того, мы загружаем вложения слов, которые были предварительно обучены в Википедии (в этом уроке будут использоваться те, что из модели GloVe). Мы будем использовать эти векторы для включения текста в наш семантический поиск. Для получения дополнительной информации о том, как работают эти векторы слов, см. Шаг 7 нашего руководства по НЛП.

Изображение - ›Изображение

Начиная с простого

Теперь мы собираемся загрузить модель, которая была предварительно обучена на большом наборе данных (Imagenet) и находится в свободном доступе в Интернете. Здесь мы используем VGG16, но этот подход будет работать с любой недавней архитектурой CNN. Мы используем эту модель для создания вложений для наших изображений.

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

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

Ниже представлены наши вложения. Каждое изображение теперь представлено разреженным вектором размером 4096. Примечание. Причина разреженности вектора в том, что мы взяли значения после функции активации, которая обнуляет отрицательные значения.

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

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

Это особенно полезно, так как метки изображений часто шумные, а изображение - это нечто большее, чем его метка.

Например, в нашем наборе данных есть и класс cat, и класс bottle.

Как вы думаете, к какому классу относится это изображение?

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

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

Поиск изображений, похожих наdataset/bottle/2008_000112.jpg

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

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

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

Полу-контролируемый поиск

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

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

Существует более простой хакерский подход, который заключается в повторном взвешивании активаций. Мы делаем это, загружая последний слой весов, от которых мы изначально отказались, и используем только веса, привязанные к индексу класса, который мы ищем, чтобы повторно взвесить наше вложение. Первоначально на этот крутой трюк мне обратил внимание сотрудник Insight Daweon Ryu. Например, на изображении ниже мы используем веса класса Siamese cat, чтобы повторно взвесить активации в нашем наборе данных (выделено зеленым). Не стесняйтесь проверить прилагаемый блокнот, чтобы увидеть подробности реализации.

Давайте посмотрим, как это работает, взвесив наши активации в соответствии с классом 284 в Imagenet, Siamese cat.

Поиск изображений, похожих наdataset/bottle/2008_000112.jpg, с использованием взвешенных функций…

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

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

Это большой шаг вперед, но поскольку мы используем модель, предварительно обученную в Imagenet, мы ограничены 1000 классами Imagenet. Эти классы далеко не всеобъемлющие (например, в них отсутствует категория для людей), поэтому в идеале мы хотели бы найти что-то более гибкое. Кроме того, что, если бы мы просто хотели найти кошек без ввода изображения?

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

Текст - ›Текст

В конце концов, не так уж и много

Вложения для текста

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

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

Как и раньше, мы создадим индекс, на этот раз содержащий все векторы GloVe. Затем мы можем поискать похожие слова в наших вложениях.

Например, поиск said возвращает следующий список из [word, distance]:

  • ['said', 0.0]
  • ['told', 0.688713550567627]
  • ['spokesman', 0.7859575152397156]
  • ['asked', 0.872875452041626]
  • ['noting', 0.9151610732078552]
  • ['warned', 0.915908694267273]
  • ['referring', 0.9276227951049805]
  • ['reporters', 0.9325974583625793]
  • ['stressed', 0.9445104002952576]
  • ['tuesday', 0.9446316957473755]

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

Серьезная проблема

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

Изображение ‹-› Текст

Столкновение миров

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

Впервые в этом уроке мы будем тренировать нашу собственную модель, черпая вдохновение из замечательной статьи под названием DeViSE. Мы не будем его точно повторно реализовывать, хотя будем сильно опираться на его основные идеи. (Чтобы увидеть другой, немного другой взгляд на бумагу, ознакомьтесь с реализацией fast.ai в их уроке 11.)

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

Обычно классификаторы изображений обучаются выбирать категорию из многих (1000 для Imagenet). Это означает, что на примере Imagenet последний слой представляет собой вектор размером 1000, представляющий вероятность каждого класса. Это означает, что наша модель не имеет семантического понимания того, какие классы похожи на другие: классификация изображения cat как dog приводит к такой же ошибке, как и его классификация как airplane.

В нашей гибридной модели мы заменяем этот последний слой модели на вектор слов нашей категории. Это позволяет нашей модели научиться сопоставлять семантику изображений с семантикой слов и означает, что похожие классы будут ближе друг к другу (поскольку вектор слов для cat ближе к dog, чем к airplane). Вместо цели размером 1000 со всеми нулями, кроме единицы, мы прогнозируем семантически богатый вектор слов размером 300.

Делаем это, добавляя два плотных слоя:

  • Один промежуточный слой размером 2000
  • Один выходной слой размером 300 (размер векторов слов GloVe).

Вот как модель выглядела при обучении на Imagenet:

Вот как это выглядит сейчас:

Обучение модели

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

Это обучение занимает немного времени, но все же намного быстрее, чем на Imagenet. Для сравнения: на моем ноутбуке, у которого нет графического процессора, потребовалось около 6–7 часов.

Важно отметить, насколько амбициозен этот подход. Обучающие данные, которые мы здесь используем (80% нашего набора данных, то есть 800 изображений), ничтожны по сравнению с обычными наборами данных (Imagenet имеет миллион изображений, на 3 порядка больше ). Если бы мы использовали традиционную технику обучения с использованием категорий, мы не ожидали бы, что наша модель будет работать очень хорошо на тестовом наборе, и, конечно же, не ожидали бы, что она вообще будет работать на совершенно новых примерах.

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

Добавление тегов

Теперь мы можем легко извлекать теги из любого изображения, просто передавая наше изображение в нашу обученную сеть, сохраняя вектор размером 300, который выходит из него, и находя самые близкие слова в нашем индексе английских слов от GloVe. Давайте попробуем с этим изображением - оно относится к классу bottle, хотя и содержит множество элементов.

Вот сгенерированные теги:

  • [6676, 'bottle', 0.3879561722278595]
  • [7494, 'bottles', 0.7513495683670044]
  • [12780, 'cans', 0.9817070364952087]
  • [16883, 'vodka', 0.9828150272369385]
  • [16720, 'jar', 1.0084964036941528]
  • [12714, 'soda', 1.0182772874832153]
  • [23279, 'jars', 1.0454961061477661]
  • [3754, 'plastic', 1.0530102252960205]
  • [19045, 'whiskey', 1.061428427696228]
  • [4769, 'bag', 1.0815287828445435]

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

Поиск изображений по тексту

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

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

Хорошо, неплохие результаты - но мы могли бы получить это из любого классификатора, который был обучен только на этикетках! Давайте попробуем что-нибудь посложнее, выполнив поиск по ключевому слову ocean, которого нет в нашем наборе данных.

Это замечательно - наша модель понимает, что ocean аналогична water, и возвращает множество элементов из класса boat.

А как насчет поиска street?

Здесь возвращенные изображения взяты из множества классов (car, dog, bicycles, bus, person), но большинство из них содержат улицу или находятся рядом с ней, несмотря на то, что мы никогда не использовали эту концепцию при обучении нашей модели. Поскольку мы задействуем внешние знания с помощью предварительно обученных векторов слов, чтобы изучить сопоставление изображений с векторами, которое является более семантически богатым, чем простая категория, наша модель может хорошо обобщаться на внешние концепции.

За словами

Английский язык далеко продвинулся, но недостаточно, чтобы изобрести слово для всего. Например, на момент публикации этой статьи не было английского слова «кошка, лежащая на диване», что было бы вполне допустимым запросом для ввода в поисковую систему. Если мы хотим искать несколько слов одновременно, мы можем использовать очень простой подход, используя арифметические свойства векторов слов. Оказывается, суммирование двух векторов слов обычно работает очень хорошо. Поэтому, если бы мы просто выполняли поиск наших изображений, используя средний вектор слов для cat и sofa, мы могли бы надеяться получить изображения, которые очень похожи на кошек, очень похожи на диван или с кошкой на диване.

Давайте попробуем использовать это гибридное встраивание и поиск!

Это фантастический результат, поскольку на большинстве этих изображений есть какая-то версия пушистого животного и дивана (мне особенно нравится крайнее левое изображение во втором ряду, которое похоже на мешок с пушистым мехом рядом с диваном)! Наша модель, которая была обучена только на отдельных словах, может обрабатывать комбинации двух слов. Мы еще не создали Google Image Search, но это определенно впечатляет для относительно простой архитектуры.

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

Заключение

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

Хотите узнать о прикладном искусственном интеллекте у ведущих специалистов Кремниевой долины или Нью-Йорка? Узнайте больше о программе Искусственный интеллект.

Вы - компания, работающая в области искусственного интеллекта, и хотели бы принять участие в программе Insight AI Fellows Program? Не стесняйтесь связаться.