Привет, Хабр ????‍♂️

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

Схема нашей рекомендательной системы
Схема нашей рекомендательной системы

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

Рекомендательные системы

Обсудим базу. Есть человек, о нём у нас имеется какая-то информация, обычно её не то, чтобы много. Нам известно о том, какие товары он просматривал, добавлял в избранное/корзину и, что самое важное – покупал. Если повезёт, также будем знать, какого он пола, возраста и в каком районе живёт. О товарах у нас также есть информация: категория, стоимость, вес, габариты, название, описание, КБЖУ в случае продуктов и т.д. Стоит помнить, что действия пользователя происходят в каком-то контексте, он зашёл на платформу в какой-то месяц, в какой-то день недели, в какое-то время дня, за окном у пользователя такая-то погода, и т.п. Всё это может повлиять на конечные предпочтения человека и соответствующие рекомендации. Далее вся эта информация передаётся пока что в некий чёрный ящик под названием рекомендательная система. Мы ещё не знаем, как она конкретно работает, но на выходе у неё стоит список товаров, которые показывается текущему пользователю в текущем контексте:

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

  1. Первая разновидность – это статистические. Они основаны на сборе статистики о товарах и дальнейшем построении правил по типу: “С этим товаром чаще брали…”. Например, пользователи часто покупают бургер и картошку фри вместе. Что порекомендовать человеку, который пока что взял только один бургер? Очевидно, что картошку фри. Кстати говоря, моя предыдущая статья и была посвящена модификации одного популярного алгоритма этой породы.

    С этим подходом есть несколько проблем: во-первых, не совсем понятно, как в такой системе продвигать новые товары, по которым ещё толком не успело накопиться достаточно статистики (проблема холодного старта). Во-вторых, в силу схемы подсчёта чаще будут рекомендоваться самые популярные товары, что не всегда хорошо. В-третьих, мы не учитываем индивидуальные предпочтения пользователя. Что, если пользователь ненавидит картошку фри и с бургером всегда берёт греческий йогурт? "Нет, ешь картошку!" - говорим мы ему из раза в раз. Такого нетипичного пользователя в подобной системе мы не отследим и легко потеряем.

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

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

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

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

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

Настраиваемый автоэнкодер

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

И тут после очередной прочитанной статьи по Stable Diffusion внезапно появилась мысль: а что если нейросеть по заданному набору параметров будет предсказывать целый заказ в скрытом представлении (эмбединге) и только после этого декодировать его в ранжированный список товаров, т.е. как бы генерировать целый заказ? Отлично, подумали мы, давайте пробовать.

С декодером было всё ясно, эмбединг заказа после нескольких слоёв расширяем до списка всех товаров и прогоняем через софтмакс. А вот с энкодером поинтереснее. Что вообще из себя представляет эмбединг заказа? Эмбединги товаров, пользователей и категорий у нас уже были получены после сингулярного разложения соответствующих матриц. И так появилась простая, но элегантная идея: эмбединг заказа - это нормированная сумма эмбедингов входящих в него товаров в том же самом евклидовом пространстве. Стоит отметить, что это далеко не очевидная гипотеза, которая в нашем конкретном случае сработала неплохо. Мы могли бы реализовать end-to-end архитектуру, устранив вопрос интерпретации скрытого представления, но тем не менее выбрали раздельную модель обучения, и тут встаёт вопрос - зачем?

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

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

Нас сейчас интересует элегантно обведённая красным квадратом область. Здесь вырисовывается основная идея. Блок со статистическим рекомендером достаёт нам ассоциативные правила к просматриваемому товару. Мы сортируем эти товары в порядке значимости, берём эмбединги первых n из них, домножаем на положительный коэффициент меньше единицы, приплюсовываем к эмбедингу заказа и нормируем полученный вектор. Вуаля! Получаем эмбединг заказа, смещённый в сторону просматриваемого товара. Теперь даже новый пользователь будет получать ассоциативные рекомендации с учётом контекста, в котором он находится. Здесь срабатывает то, что мы можем интерпретировать эмбединг заказа, как суммарный эмбединг входящих в него товаров, что собственно и позволяет делать такое вот смещение.

Оставшиеся нюансы

Остаются не освещёнными ещё несколько вопросов

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

- Какая лосс-функция используется для энкодера?
- Косинусное расстояние

- Какая лосс-функция используется для декодера и какой таргет?
- MSE с таргетом из нормированного multi-hot вектора заказа

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

- Как кодируете месяц, день недели и время?
- В виде пары синус-косинус соответствующей частоты. Например, время кодируем следующей парой чисел: cos(\frac {\pi*h} {12}), sin(\frac {\pi*h} {12}), где h - время в часах от 0 до 23.

Результаты

  1. Во-первых, мы объединили холодные и горячие рекомендации в одну систему. Когда система монолитна и ничего не болтается по-отдельности, этим проще управлять и модернизировать. Такой подход позволяет получать более стабильные результаты.

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

  3. В-третьих, мы получили некую универсальную систему, ориентированную и на пользователя, и на товар, и на контекст.

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

Спасибо за внимание, желаю всем обучаемых и производительных моделей!

Комментарии (0)