блюдо по ингредиентам подобрать

Photo2recipe: рецепт блюда по одному фото

блюдо по ингредиентам подобрать. Смотреть фото блюдо по ингредиентам подобрать. Смотреть картинку блюдо по ингредиентам подобрать. Картинка про блюдо по ингредиентам подобрать. Фото блюдо по ингредиентам подобрать

Вступление

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

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

Photo2Ingredients

Итак, на первом этапе наш алгоритм с помощью нейросетевых методов определяет состав блюда, изображенного на фото, то есть решает задачу photo2ingredients. Однако для создания такой нейросети, способной решать photo2ingredients task, необходим большой обучающий датасет: в нашем случае это должны быть фото еды с размеченными ингредиентами. Чтобы собрать такой набор данных мы взяли за основу скреппер из проекта ChefNet и с помощью него скоскрепили данные с американского сайта рецептов allrecipes.com. Помимо самих рецептов на сайте содержатся фотографии готовых блюд, а также списки ингредиентов, необходимых для их приготовления. Их мы и взяли в качестве состава блюда. Еще раз подчеркнем, что данные с сайта мы использовали именно для обучения модели первого этапа, которая распознает еду на фотографии, а для рекомендаций рецептов мы выбрали другую базу данных, на русском языке и в бОльшей степени ориентированную на русскую кухню, чем рецепты с американского сайта.

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

блюдо по ингредиентам подобрать. Смотреть фото блюдо по ингредиентам подобрать. Смотреть картинку блюдо по ингредиентам подобрать. Картинка про блюдо по ингредиентам подобрать. Фото блюдо по ингредиентам подобрать блюдо по ингредиентам подобрать. Смотреть фото блюдо по ингредиентам подобрать. Смотреть картинку блюдо по ингредиентам подобрать. Картинка про блюдо по ингредиентам подобрать. Фото блюдо по ингредиентам подобрать

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

Получившиеся train и val датасеты содержат 162547 (80%) и 40648 (20%) фото соответственно, и при этом все блюда присутствуют в обеих выборках, как обучающей, так и валидационной.

Предобработка изображений

Изначально все изображения в датасете имели разрешение 250×250 пикселей. На этапе предобработки мы сжали изображения до размера 224×224 и вычли среднее значение для каждого пикселя. Такая техника широко используется в компьютерном зрении. При обучении нейросети каждый пиксель рассматривается как отдельный признак, и получается, что после вычитания среднего все признаки будут центрированы вокруг 0. Подобная предобработка позволяет избежать взрыва градиентов и делает обучение более эффективным.

Извлечение ингредиентов

Для извлечения ингредиентов по фотографиям мы рассмотрели две различные нейросетевые архитектуры: encoder-decoder и encoder-classifier.

Первая модель основана на архитектуре из статьи. Она использует предобученную сверточную нейронную нейросеть (CNN) в качестве энкодера. В экспериментах мы использовали ResNet-50 без последнего полносвязного слоя. Выход ResNet-50 подается на GRU слой с hidden_size = 512. Архитектура модели представлена на рисунке ниже:

блюдо по ингредиентам подобрать. Смотреть фото блюдо по ингредиентам подобрать. Смотреть картинку блюдо по ингредиентам подобрать. Картинка про блюдо по ингредиентам подобрать. Фото блюдо по ингредиентам подобрать

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

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

В качестве энкодера мы попробовали три предобученные модели: Resnet- 50, Resnet-101 и Densenet161. Densenet161 показала наилучший результат, поэтому мы остановились на ней. Классификатор состоит из трех полносвязанных слоев, а на выход последнего слоя навешивается сигмоида. Затем все ингредиенты, для которых выходное значение больше порога (мы взяли порог 0.25, который был установлен эмпирическим путем), добавляются в итоговый список ингредиентов. Архитектура второй модели представлена на рисунке ниже:

блюдо по ингредиентам подобрать. Смотреть фото блюдо по ингредиентам подобрать. Смотреть картинку блюдо по ингредиентам подобрать. Картинка про блюдо по ингредиентам подобрать. Фото блюдо по ингредиентам подобрать

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

Весь код написан на Python, на Pytorch.

Изменение метрик качества на валидации представлено на рисунках ниже:

Результаты первой модели:

блюдо по ингредиентам подобрать. Смотреть фото блюдо по ингредиентам подобрать. Смотреть картинку блюдо по ингредиентам подобрать. Картинка про блюдо по ингредиентам подобрать. Фото блюдо по ингредиентам подобрать

Результаты второй модели:

блюдо по ингредиентам подобрать. Смотреть фото блюдо по ингредиентам подобрать. Смотреть картинку блюдо по ингредиентам подобрать. Картинка про блюдо по ингредиентам подобрать. Фото блюдо по ингредиентам подобрать

Эксперименты показывают, что вторая модель значительно превосходит первую. Она достигает значения F1 равного 0,53, в то время как первая только 0,24.

Ingredients2recipe

Скрепинг рецептов

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

блюдо по ингредиентам подобрать. Смотреть фото блюдо по ингредиентам подобрать. Смотреть картинку блюдо по ингредиентам подобрать. Картинка про блюдо по ингредиентам подобрать. Фото блюдо по ингредиентам подобрать

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

Матчинг рецептов

Для матчинга мы реализовали и протестировали три разных метода:

1) подход на основе предобученных эмбенддингов;

2) подход на основе TF-IDF;

3) подход с использованием изображений.

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

Подход на основе предобученных эмбенддингов

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

1) word2vec. Модель Skipgram для русского языка, обученная на Национальном Корпусе Русского языка (НКРЯ) от RusVectores (проект NLPL). Тексты рецептов и ингредиенты были предварительно обработаны с помощью UDpipe для получения лемм и pos-тегов.

2) fasttext. Модель, предобученная на НКРЯ, из NLPL.

3) ELMO. Модель от DeepPavlov, предобученная на Википедии для русского языка.

Подход на основе TF-IDF

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

Подход с использованием изображений

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

Сравнение методов матчинга

Для оценки качества методов матчинга мы выбрали случайных 50 рецептов из базы собранной по allrecipes.com и использовали соотвествующие им ингредиенты, переведенные на русский язык, для поиска наиболее подходящих рецептов. При этом мы предлагали топ-10 блюд для каждого примера. Затем затем мы вручную (с перекрытием аннотаторов равным трем) оценили релевантность предложенных рецептов и вычислили MAP@10, усреднив оценки между аннотаторами. Результаты приведены в таблице ниже:

блюдо по ингредиентам подобрать. Смотреть фото блюдо по ингредиентам подобрать. Смотреть картинку блюдо по ингредиентам подобрать. Картинка про блюдо по ингредиентам подобрать. Фото блюдо по ингредиентам подобрать

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

Единый framework

Заключение

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

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

Благодарность

Эта работа результат совместных трудов большой команды из шести человек: @IlyaShchuka, @saydashtatar, @vladislove_p, @alenusch и я, ваша покорная слуга и рассказчица @mashkka_t. Спасибо вам огромное за совместную работу над проектом и креативные идеи!

Обучение

Так как я являюсь руководителем курсов по Machine Learning в OTUS, приглашаю всех желающих на наши бесплатные демоуроки, зарегистрироваться на которые можно по ссылкам ниже:

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *