Векторное доранжирование в Wildberries

Векторное доранжирование в Wildberries

Тришин Александр
Эта и другие статьи про рекомендации в Wildberries выходят в рамках телеграм канала @wildrecsys

Привет! Меня зовут Тришин Александр, я Data Scientist в команде персональных рекомендаций Wildberries. 

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

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

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


Мотивация: зачем это нужно

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

Выдача подборки товаров для дома без доранжирования (сверху) и с доранжированием (снизу), scores = cosine similarity.

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

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

  1. Фичей много, и для разных задач нужны разные. Где-то важен недавний клик, где-то покупки за полгода, где-то принадлежность пользователя с соцдем группе. Возвращаясь к примеру с поиском футболки: можно использовать гендер пользователя и предсказанную покупательскую способность как фичи. Тогда в выдаче будут мужские футболки подходящего ценового сегмента. Но тогда не будет учитываться размер одежды пользователя, стиль одежды, который он предпочитает. А если этот мужчина вчера покупал кроссовки, то можно предположить, что спортивные футболки будут релевантнее, чем другие. Нужны дополнительные фичи, чтобы это учесть, и так можно продолжать очень долго.
  2. Они дорогие. Каждую фичу надо где-то считать, где-то хранить, поддерживать в актуальном состоянии. Более того, часть информации учтена в самих источниках. Так, в похожих товарах уже учитывается пол на уровне item-to-item рекомендаций. Нужен ли в таком случае пол отдельной фичей? Вряд ли.
  3. Переиспользование боль. Каждый новый сценарий требует пересмотра всего пайплайна: какие фичи взять, как их доставлять, как обучать модель. Особенно обидно делать всё это ради небольшой акции, которая идет несколько дней или недель. 

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

Пример персонализации поисковой выдачи через векторное доранжирование.

Что такое векторное доранжирование

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

Преимущества у подхода следующие:

  1. универсальность вектора пользователя — один и тот же вектор можно использовать в десятках сценариев — от главной до поиска.
  2. нет привязки к конкретным фичам — достаточно вектора небольшой размерности (достаточно 64 или 128)
  3. встраиваемость — есть список товаров, есть пользователь — считаем скоры, ранжируем, показываем.

Чтобы векторное доранжирование работало, нужны две вещи: модель, которая строит векторы, и инфраструктура, которая позволяет ими быстро пользоваться. Расскажем о каждой подробнее.

Как устроена модель

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

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

Как работает инфраструктура

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

На этапе ранжирования:

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

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

Что дальше?

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

Решение этой проблемы состоит в развитии модели, которая сможет адекватно учитывать более шумный фидбек (клики) и в развитии инфраструктуры, позволяющей инферить эту модель в Near Real Time режиме и быстро обновлять вектор пользователя. О наших наработках в этом направлении я расскажу в следующем посте.



Report Page