![image](https://habrastorage.org/webt/w4/qo/hx/w4qohxd9gujf6kayzuow0bww9dc.png)
Каждый день полтора миллиона людей ищут на Ozon самые разные товары, и к каждому из них сервис должен подбирать похожие (если пылесос все-таки нужен помощней) или сопутствующие (если к поющему динозавру нужны батарейки). Когда видов товаров тоже много, решить задачу помогает модель Word2Vec. Разбираемся, как она работает и как создавать векторные представления для произвольных объектов.
Мотивация
Чтобы построить и обучить модель, мы используем стандартную для machine learning технику embedding, когда каждый объект превращается в вектор фиксированной длины, и близким объектам соответствуют близкие векторы. Практически всем известным моделям требуется, чтобы данные на входе были фиксированной длины, и набор векторов — простой способ привести их к такому виду.
Один из первых embedding-методов — word2vec. Мы адаптировали этот метод для нашей задачи, в качестве слов у нас используются товары, а в качестве предложений — пользовательские сессии. Если вам все понятно, смело пролистывайте к результатам.
Далее я расскажу об архитектуре модели и о том, как она работает. Поскольку мы имеем дело с товарами, нужно научиться строить такие их описания, которые, с одной стороны, содержат достаточно информации, а с другой — понятны для алгоритма машинного обучения.
![image](https://habrastorage.org/webt/y0/pj/fz/y0pjfzmvk5o-aulmjygpnjrphji.png)
На сайте у каждого товара есть карточка. Она состоит из названия, текстового описания, характеристик и фотографии. Также в нашем распоряжении есть данные о взаимодействии пользователей с товаром: просмотры, добавление в корзину или избранное сохраняются в логах.
Есть два принципиально разных способа построения векторного описания товара:
— использовать контент — сверточные нейронные сети для извлечения признаков из фотографий, рекуррентные сети или мешок слов для анализа текстового описания;
— использование данных о взаимодействиях пользователей с товаром: какие товары и как часто смотрят/добавляют в корзину вместе с данным.
Мы остановимся на втором способе.
Данные для модели Prod2Vec
Для начала разберемся, какие данные мы используем. В нашем распоряжении все клики пользователей на сайте, их можно разбить на пользовательские сессии — последовательности кликов с промежутками не более 30 минут между соседними кликами. Для обучения модели мы используем данные порядка 100 млн. пользовательских сессий, в каждой из которых нас интересуют только просмотры и добавления товаров в корзину.
Пример реальной сессии пользователя:
![image](https://habrastorage.org/webt/q5/ov/fe/q5ovfeg-qfqarxgzxyzcfq5vssk.png)
Каждому товару в сессии соответствует его контекст — все товары, которые пользователь добавил в корзину в этой сессии, а также товары, которые смотрят вместе с этим. Модель prod2vec строится на основе предположения, что похожие товары чаще всего имеют похожие контексты.
Например:
![image](https://habrastorage.org/webt/ch/_m/tp/ch_mtpiawhaak2ddrks2pjxvgae.png)
Таким образом, если предположение верно, то, например, чехлы для одной и той же модели телефона будут иметь похожие контексты (тот самый телефон). Мы проверим эту гипотезу, построив векторы товаров.
Модель Prod2Vec
Когда мы ввели понятия товара и его контекста, опишем саму модель. Это нейронная сеть с двумя полносвязными слоями. Число входов первого слоя равно числу товаров, для которых мы хотим построить векторы. Каждый товар на входе будет закодирован вектором из нулей с единственной единицей — местом этого товара в словаре.
Число нейронов на выходе первого слоя равно размерности векторов, которые мы хотим в итоге получить, например 64. На выходе последнего слоя опять стоит число нейронов, равное числу товаров.
![image](https://habrastorage.org/webt/nf/0i/bf/nf0ibftkdqs3bkun8jn_qkwodfo.jpeg)
Будем тренировать модель, чтобы предсказывать контекст, зная товар. Такая архитектура называется Skip-gram (ее альтернатива — CBOW, где мы предсказываем товар по его контексту). Во время обучения на вход отдается товар, на выходе ожидается товар из его контекста (вектор из нулей с единицей на соответствующем месте).
По сути это многоклассовая классификация, и для обучения модели можно использовать cross entropy loss. Для одной пары слово — слово из контекста она записывается следующим образом:
где — предсказание сети для товара из контекста, — общее число товаров, — предсказание сети для товара .
После обучения модели мы можем отбросить второй слой — он не понадобится для получения векторов. Матрица весов первого слоя (размером число товаров х 64) при этом является словарем векторов товаров. Каждому товару соответствует одна строка матрицы длины 64 — это и есть вектор, соответствующий товару, который можно использовать в других алгоритмах.
Но эта процедура не работает для большого количества товаров. А у нас их, напомним, полтора миллиона.
Почему не работает Prod2Vec
— Функция потерь содержит множество операций взятия экспоненты — это долго и неустойчиво вычислительно.
— В результате градиенты считаются для всех весов сети — а их могут быть десятки миллионов.
Для решения этих проблем подходит метод negative sampling, используя который, мы учим сеть не только предсказывать контекста для товара, но еще и учим не предсказывать товары, которые точно в контекст не входят. Для этого нам нужно генерировать негативные примеры — для каждого товара подбирать те, которые не нужно для него предсказывать. И здесь наличие огромного количества товаров нам помогает. При выборе для товара случайной пары, мы имеем очень маленькую вероятность того, что это окажется товар из контекста.
В результате для каждого товара в контексте мы случайно генерируем 5-10 товаров, которые в контекст не входят. При этом товары сэмплируются не равномерным распределением, а пропорционально частоте их встречаемости.
Функция потерь теперь похожа на ту, что используется при бинарной классификации. Для одной пары слово — слово из контекста она выглядит так:
В этих обозначениях обозначает столбец матрицы весов второго слоя, соответствующий товару из контекста, — то же самое для случайно выбранного товара, — строка матрицы весов первого слоя, соответствующая основному товару (это именно тот вектор, который мы строим для него). Функция .
Отличие от предыдущей версии в том, что нам не надо на каждой итерации обновлять все веса сети, нужно обновить лишь те, которые соответствуют малому числу товаров (первый товар — тот для которого мы предсказываем, остальные — либо товар из его контекста, либо случайно выбранный). Одновременно с этим мы избавились от огромного числа взятий экспоненты на каждой итерации.
Другой прием, который в свою очередь улучшает качество полученной модели — subsampling. В этом случае мы намеренно реже берем для обучения часто встречающиеся товары, чтобы получить лучший результат для редких товаров.
Результаты
Похожие товары
Итак, мы научились получать векторы для товаров, теперь нужно проверить адекватность и применимость нашей модели.
На следующей картинке представлен товар и его ближайшие соседи по косинусной мере близости.
![image](https://habrastorage.org/webt/n7/rp/ja/n7rpjaf-eyfsmq7mtmd6womojfw.jpeg)
Результат выглядит хорошо, но необходимо численно проверить, насколько хороша наша модель. Для этого мы применили ее для задачи товарных рекомендаций. Для каждого товара мы рекомендовали ближайшие в построенном векторном пространстве. Модель prod2vec мы сравнивали с куда более простой, основанной на статистике совместных просмотров и добавлений товаров в корзину. Для каждого товара в сессии был взят список из 7 рекомендаций к нему. Объединение всех рекомендованных товаров в сессии сравнивалось с тем, что человек реально добавил в корзину. Используя prod2vec, более чем в 40% сессий мы рекомендовали хотя бы один товар, который потом был добавлен в корзину. Для сравнения, более простой алгоритм показывает качество 34%.
Полученное векторное описание позволяет не только искать для товаров ближайшие (что может делать и более простая модель, пусть и с худшим качеством). Мы можем рассмотреть какие интересные побочные результаты можно показать, используя нашу модель.
Векторная арифметика
Для иллюстрации того, что вектора несут в себе реальный смысл о товарах, мы можем попробовать применить для них векторную арифметику. Как и в хрестоматийном примере о word2vec (king — man + woman = queen), мы можем например задаться вопросом о том, какой товар находится на примерно таком же расстоянии от принтера, как пылесборник — от пылесоса. Здравый смысл подсказывает что это должен быть какой-то расходник, а именно картридж. Наша модель способна уловить такие закономерности:
![image](https://habrastorage.org/webt/m1/j5/ac/m1j5aca_jsyjupowx9yapcorpmo.png)
Визуализация пространства товаров
Чтобы еще лучше понять результаты, мы можем визуализировать векторное пространство товаров на плоскости, снизив размерность до двух (в данном примере мы использовали t-SNE).
![image](https://habrastorage.org/webt/_d/v8/m1/_dv8m1fmgufpknn_l1klly2wqwi.png)
Хорошо видно, что близкие товары образуют кластеры. Например, хорошо видны кластера с текстилем для спальни, мужской и женской одеждой, обувью. Еще раз отметим, что данная модель построена только на основе истории взаимодействия пользователей с товарами, мы не использовали при обучении сходство изображений или текстовых описаний.
Из иллюстрации пространства также видно, как с помощью модели можно подбирать к товарам аксессуары. Для этого нужно взять товар из ближайшего кластера, например для футболок рекомендовать спортивные товары, а для теплых свитеров — шапки.
Планы
Сейчас мы внедряем модель prod2vec в продакшн для расчета товарных рекомендаций. Также полученные векторы можно использовать как признаки для других алгоритмов машинного обучения, которыми занимается наша команда (предсказание спроса на товары, ранжирование в поиске и каталогах, персональные рекомендации).
В дальнейшем мы планируем внедрить полученные эмбеддинги на сайт в real-time. Для всех просмотренных товаров в сессии будут находиться ближайшие, что будет мгновенно отражаться в персонализированной выдаче. Также мы планируем интегрировать в нашу модель анализ изображений и сходства по векторному описанию, что сильно улучшит качество получаемых векторов.
Если вы знаете, как лучше это сделать (или переделать) — приходите в гости (а еще лучше работать).
Ссылки:
- Mikolov, Tomas, et al. "Distributed representations of words and phrases and their compositionality." Advances in neural information processing systems. 2013.
- Grbovic, Mihajlo, et al. "E-commerce in your inbox: Product recommendations at scale." Proceedings of the 21th ACM SIGKDD International Conference on Knowledge Discovery and Data Mining. ACM, 2015.
- Grbovic, Mihajlo, and Haibin Cheng. "Real-time Personalization using Embeddings for Search Ranking at Airbnb." Proceedings of the 24th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining. ACM, 2018.
Комментарии (7)
Alexey_mosc
13.12.2018 10:22Хороший подход. Я делаю похожее для слов и текстов. У вас следующим шагом может быть кластеризация пользователей с использованием векторов просмотренных товаров. Могу подсказать вариант как сделать.
arbochkarev Автор
13.12.2018 11:49Классно что у тебя есть идеи по поводу этого, будет интересно послушать :) Моя телега: @artembochkarev.
rawman
13.12.2018 11:49с нетерпением жду кода посмотреть как реализовали.
еще вопрос к вам, раз вы так глубоко погрузились в тему, можно ли использовать технологию для определения 2-х одинаковых товаров?
к примеру только по названию, допустим названия сильно по разному написаны, некоторые слова названия стоят на разных местах, есть или нет разные не значащие символы типо точек в разных местах, сокращения слов и т.д.arbochkarev Автор
13.12.2018 11:51Привет, спасибо за вопрос! Действительно, можно придумать как использовать этот алгоритм для определения одинаковых товаров, но в нашем случае нужно товары матчить раньше (когда их только заводят на сайте и для них нет никакой статистики). Для этого можно как раз использовать признаки извлеченные из названия, текстового описания, бренда, характеристик товара итд. Но это уже совсем другая история…
chudinov
ждем prod2vec в гитхабе?
arbochkarev Автор
Мы в процессе написания продакшн кода для модели, не планировали выкладывать код, пока он не будет до конца нами внедрен и протестирован.
S_A
Зачем его ждать. В керасе есть embeddings layer уже готовый. Готовите данные и учите что хотите.