Управление разнообразием рекомендаций

Управление разнообразием рекомендаций

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

Введение

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

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

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

Информационный пузырь в рекомендациях

Ranking vs Beyond-Accuracy metrics: choose your fighter

Представьте, что вы только начали работать с рекомендательными системами. Первое, с чем вы сталкиваетесь, — это вопрос: как оценить, насколько хороши ваши рекомендации? Проведя небольшой ресерч, понимаете — надо фокусироваться на ранжирующих метриках. Базовый пул — HitRate@K, Precision@K, MAP@K, Recall@K, и, конечно же, NDCG@K. С ними все логично: если вы угадали и порекомендовали товар, который в дальнейшем купит пользователь, то вам плюс в карму. Если еще и угаданные товары располагаете выше в ленте, чтобы пользователь увидел их первее — то цены вашей модели нет!

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

Двигаемся дальше. Кажется, наша модель стала умнее и научилась (очень хорошо!) угадывать следующие покупки пользователей. Например, для книжного червя, который заказывал на WB только книги, она рекомендует книги; для садовода — семена и различные удобрения. Вроде как с задачей справились. Катим в прод? Вряд ли. Оценив рекомендации вашей модели глазами, вы с высокой вероятностью придете в уныние, так как лента будет однообразна. При всей своей высокой релевантности такие подборки плохи с точки зрения удержания пользователя и исследования нового контента. 

Примерно так выглядела бы лента WB, если бы мы не растили разнообразие

Углубляясь в ресерч, вы понимаете — просто топить за ранжирующие метрики мало! Нужно контролировать и Beyond-Accuracy (BA) метрики, иначе рекомендации рискуют превратиться в унылый список самых популярных или однотипных товаров. Ключевые BA-метрики, которые нас интересуют:

  • Pop-Bias — не хотим, чтобы выдача забивалась хитами продаж.
  • Diversity — не хотим, чтобы рекомендации зацикливались на одном типе товаров. 
  • Novelty — привносим что-то новое в ленту. Пользователь должен знать, что у нас можно не только книжки заказывать!
  • Serendipity — «вау-эффект», композиция новизны и релевантности (подробнее в нашем посте).

А теперь плохие новости. Как только мы начинаем сознательно поднимать BA-метрики, классические ранжирующие (NDCG@K, Precision@K и прочие) начинают с высокой вероятностью проседать.

Представьте: мы специально увеличиваем разнообразие по категориям в выдаче. Допустим, раньше модель рекомендовала пользователю 200 книг — и хоть в какую-то да попадала. NDCG@K при этом был высоким, потому что большая часть ленты состояла из товаров, максимально похожих на те, что пользователь уже покупал. Но теперь мы внедряем разнообразие, и вместо 200 книг модель начинает предлагать, скажем, 10 книг, 10 картин по номерам, 10 различных канцелярских принадлежностей и так далее. Лента становится более интересной и богатой, но шанс угадать именно книгу, которую пользователь собирался купить, резко падает. Итог — NDCG@K и другие ранжирующие метрики проседают.

Что с этим делать? Растить разнообразие или «попадания» в товар? Выход базовый — провести A/B-тест с разными балансами BA- и ранжирующих метрик. Ведь в этой битве сильнейших 🔮 побеждает не тот, у кого выше NDCG@K, а тот, кто максимизирует бизнес-метрики. 


Методы управления разнообразием

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

И теперь расскажу подробнее о тех подходах, что мы пробовали. Про квоты и якорные товары уже рассказывали в этом посте. Мы пошли дальше и решили проверить новый способ — управление разнообразием через изменение инференса нашей кандидатной модели, BERT4Rec. 

1. Якорные товары

История пользователя — это эхо его текущих интересов. Пусть есть пользователь, у которого в истории 15 взаимодействий с техникой, 30 с одеждой и 20 со спортивными товарами. Если модель ориентируется только на последние 30 взаимодействий, то она выделит технику и одежду, игнорируя интерес пользователя к спорту. В таком случае мы рискуем «забыть» о интересах пользователя к другим категориям.

Чтобы избежать этого, можно ввести ограничения на количество товаров по категориям. Например, по 5 товаров из каждой категории истории пользователя — техники, одежды и спорта. Такой подход помогает сделать представление о пользователе более сбалансированным и полным, не давая модели зацикливаться только на последних предпочтениях.

Эти товары и будут теми самыми якорными, которые напомнят пользователю о его интересах и, возможно, побудят вернуться к спорту!

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

2. Квоты

Квоты применяются на этапе финального отбора товаров в выдаче. Сначала для каждого пользователя мы генерируем большой пул товаров, а затем группируем их по категориям. Если товаров в категории слишком много, выбираем в ней топ-K товаров с наивысшим скором (допустим, метрика «релевантности» у нас есть) и отбрасывая остальные. Таким образом, мы напрямую увеличиваем разнообразие товаров в выдаче, даже если якорные товары оказались идентичными, что бывает, когда история пользователя например, слишком короткая.

3. Category-Split Inference

Квоты — это здорово, но у них есть свои ограничения. По сути они работают как фильтр: сначала мы генерируем много кандидатов, а потом отсекаем лишнее. Но что, если в самом пуле кандидатов нет разнообразия? Например, пользователь, который заказывал только чай, получит рекомендации, состоящие из чая и чайных наборов. В таком случае квоты не помогут, так как разнообразие товаров в пуле кандидатов невысокое. Более того, было бы славно иметь «ручку», которой можем явно контролировать число категорий в выдаче от нашей модели.

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

Чтобы ответить на этот вопрос, нужно понимать, как происходит текущий инференс. В процессе обучения наша кандидатная модель, BERT4Rec, формирует представления товаров (они же эмбеддинги, или вектора). На инференсе она принимает на вход историю пользователя и также создает для нее эмбеддинг. Все, что остается — найти топ-N ближайших товаров в векторном пространстве (по любимой вами метрике схожести). Товаров у нас много, даже после фильтрации остаются миллионы, поэтому для ускорения векторного поиска мы используем faiss — можно представить его как мешок, наполненный векторами всех товаров, из которого для каждого пользователя мы вытягиваем топ-N наиболее релевантных.

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

Чтобы выбрать подходящие мешки, нужны вектора категорий. Самый простой способ — усреднить эмбеддинги товаров внутри категории. Более high-level — «зашить» информацию о категориях в саму модель, например дополнительно обучив BERT4Rec предсказывать не только товары, но и их категории. Тогда почти бесплатно получаем вектора не только товаров, но и их категорий.

Схема Category-Split Inference. На данном примере для каждого пользователя выбираем три ближайшие категории. Далее, внутри faiss-индекса каждой категории ищем ближайшие 2 товара.

Заключение

Мы рассмотрели три способа управления разнообразием. Первый — выбор якорных товаров при подготовке датасета. Два других метода применяются на этапе инференса: квоты — когда мы обычным способом генерируем больше товаров, чем требуется от модели-кандидата, а потом перегруппируем их так, чтобы в итоговой выдаче были все категории из этого большого пула товаров; и Category-Split Inference — когда мы выбираем наиболее релевантные для пользователя категории, и затем генерируем товары только из них. 

Пока что сохраняем интригу, но в скором времени вернемся к вам с результатами A/B-теста по увеличению разнообразия методом category-split inference.

Спасибо, что дочитали, и до новых встреч!

Report Page