Perseus: фреймворк для универсальной персонализации на основе гетерогенных событий

от автора

Привет! Я Олег Лашинин, руковожу направлением рекомендательных систем в Т-Банке. Когда в экосистеме десятки сервисов — от покупки продуктов в супермаркетах до оформления ипотеки, хочется, чтобы модель понимала пользователя целиком, а не по кусочкам. Но каждая команда собирает свои данные, у событий разные схемы, а в новых сервисах нет истории. 

Большинство моделей было построено только на данных того сервиса, где они применяются. Мы решили эту проблему, объединив все действия пользователя в единую последовательность, и на ее основе построили фреймворк Perseus.  Он позволяет масштабировать ML персонализацию на разные продукты и сервисы компании, так как является гибким инструментов для работы с экосистемными данными. В разных задачах нам удалось сразу повысить бизнес-метрики от 3% до  17% — даже если у пользователя не было ни одной покупки.

Как мы пришли к идее фреймворка

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

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

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

Пришла идея, что можно представить пользователя в виде одной последовательности, составленной из покупок в разных магазинах. Далее можно обратиться к одной из самых известных трансформерных моделей — SASRec. Она рассматривает действия пользователя, отсортированные по времени. 

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

Мы расширили идею в трех направлениях:

  1. Входные данные модели — это последовательность покупок сразу во всех магазинах, а не только в одном. Теперь модель знает все покупки клиента во всех магазинах сразу.

  2. Для каждого магазина есть своя матрица эмбеддингов товаров. Если модель на 10 партнеров, мы обучаем 10 разных независимых матриц item эмбеддингов на выходе. Но для одного сэмпла пользователь-заказ обучается только одна соответствующая матрица товаров магазина, где был совершен заказ.

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

Мы собрали модельку и начали проводить эксперименты. Больше всего нас интересовал вопрос, сможем ли мы предсказать корзину первого заказа точнее, чем взять самые популярные товары как предсказания? Здесь мы сразу получили +10% качества в среднем. Если пользователь уже покупал товары в одном магазине, а потом совершал покупку в новом магазине, то там мы заранее вырастили качество предсказания следующего заказа на столько процентов.

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

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

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

Важно, что доменов данных мало, а задач, в которых мы хотим их использовать, много. Возникла идея собрать все домены данных в одном месте, правильно их обработать и использовать для различных задач. Такое хранилище мы назвали Event Hub. А поверх него построили универсальный фреймворк Perseus, позволяющий использовать одни и те же данные для множества самых разных задач.

Архитектура Perseus: как мы строим универсальный эмбеддинг пользователя

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

Во многих рекомендательных системах пользователь описывается не одной строкой признаков, а длинной историей действий. Он мог смотреть товары, лайкать контент, покупать, слушать треки, писать поисковые запросы, ставить дизлайки или взаимодействовать с продуктом десятками других способов. При этом у разных событий разные схемы: у покупки есть цена и категория, у прослушивания — артист и длительность, у поиска — текст запроса, у лайка — объект взаимодействия.

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

Процесс обработки данных: история событий пользователя: → энкодеры признаков → эмбеддинги событий → sequence backbone → эмбеддинг пользователя → task-specific head → рекомендации, ранжирование, класс или числовой прогноз

Процесс обработки данных: история событий пользователя: → энкодеры признаков → эмбеддинги событий → sequence backbone → эмбеддинг пользователя → task-specific head → рекомендации, ранжирование, класс или числовой прогноз

Ключевая сущность во фреймворке — объект в фиксированный момент времени. Для каждого примера задается client_id и timestamp, а модель получает только события, которые произошли раньше этого timestamp. Это важно для избежания ситуации, когда модель видит будущее. Мы явно контролируем, какая история была доступна модели на момент предсказания, и не подмешиваем будущие взаимодействия.

Внутри Perseus есть несколько основных слоев.

Работа с данными. Пользователь задает basis: таблицу объектов для обучения или инференса. В ней есть пользователь, timestamp, optional context и target. Для задач рекомендаций и ранжирования дополнительно используются artifacts — например, каталог айтемов, которые можно рекомендовать или скорить.

Признаки и энкодеры. Признаки могут находиться в событиях, контексте или артефактах каталога. Например, item_id может встречаться в истории пользователя, а item — в таблице каталога. При этом они могут использовать один и тот же encoder, то есть общую таблицу эмбеддингов. Это удобно для next-item prediction и похожих задач, где входные и выходные item-представления должны жить в одном пространстве.

Слой backbone отвечает за то, чтобы превратить историю пользователя в один общий эмбеддинг. Backbone состоит из нескольких частей: event_aggregator объединяет признаки одного события, context_aggregator обрабатывает контекстные признаки, а history_aggregator агрегирует последовательность событий вместе с выходом context_aggregator. В качестве history aggregator можно использовать разные sequence-модели: Transformer/BERT-like, ModernBERT-like, HSTU, LiGR, DA-Net, Mamba-like-варианты и другие реализации, которые вы сами можете добавить. 

Слой task head. Один и тот же подход к построению пользовательского эмбеддинга можно использовать для разных задач:

  • retrieval — подобрать top-k объектов из каталога;

  • ranking — проскорить и отсортировать заданный список кандидатов;

  • classification — предсказать класс пользователя или объекта;

  • regression — предсказать числовую величину.

Например, в retrieval-сценарии Perseus строит эмбеддинг пользователя из истории, строит эмбеддинги айтемов из каталога и считает скор как dot product между ними. Дальше можно обучаться с full-catalog cross entropy, random uniform или in-batch negatives, а качество считать стандартными retrieval-метриками вроде Recall@K, NDCG@K, MRR@K и coverage.

Разделение пайплайна на этапы. Perseus отдельно готовит датасет, отдельно обучает модель, отдельно считает эмбеддинги пользователей и отдельно скорит каталог. Это не просто архитектурная аккуратность: в больших рекомендательных системах такое разделение позволяет переиспользовать тяжелые промежуточные артефакты. Например, если истории пользователей не изменились, но мы хотим поменять доступный каталог, можно не пересчитывать backbone-эмбеддинги пользователей, а только заново проскорить новый набор айтемов.

В итоге Perseus решает не только задачу «обучить еще один SASRec». Он закрывает более широкий класс проблем: 

  • как единообразно работать с гетерогенными пользовательскими историями; 

  • как явно фиксировать temporal protocol;

  • как сравнивать разные sequence-архитектуры на одной подготовке данных;

  • как масштабировать офлайн-инференс без переписывания пайплайна под каждый эксперимент.

Как мы используем фреймворк

В Т-Банке есть различные данные о действиях клиентов, которые можно агрегировать в цепочки последовательностей. Сейчас в нашем Event-hub хранятся различные данные:

  • О транзакциях — самый большой источник данных, который помогает определить интересы клиентов.

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

  • Действия клиентов с банковскими продуктами. Они позволяют лучше понимать заинтересованность клиентов в продуктах Т-Банка.

  • Действия клиентов в разделе «Шопинг». Эти события позволяют лучше понять интересы наших клиентов с точки зрения ecom-направления. Здесь много различной информации: товары, отели, билеты на самолеты, продукты питания и так далее.

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

Сейчас Perseus работает в нескольких направлениях:

  • В Шопинге помогает оценивать склонность клиентов к определенным товарам, продуктам питания и партнерским скидкам.

  • В повышенных кэшбэках оценивает склонности клиентов к определенным офферам, которые выдаются раз в месяц.

  • В предиктивной поддержке заранее предсказывает тему обращения клиента в и предлагает варианты решения вопроса.

Мы активно внедряемся в другие бизнес линии Т-Банка, например в направление дебетовых и кредитных продуктов.

Как можно использовать фреймворк

Мы выкладываем фреймворк Perseus в открытый доступ и отдельным репозиторием примеры использования Perseus на открытых датасетах.  Мне видится три основных сценария его использования.

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

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

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

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

Что мы планируем дальше

Будем развивать фреймворк, и для этого у нас есть несколько направлений:

  1. Исследования предобучения кросс-доменных моделей для персонализации. Мы провели некоторое количество экспериментов, но пока не получили значимых приростов качества от этого упражнения. По нашим результатам получалось так, что обучение модели с нуля (в end-to-end-формате) сводится примерно к такому же качеству, что и предобученная модель, но требует меньше ресурсов и упрощает пайплайн. Мы все равно верим, что возможно получить приросты в качестве от предобучения на кросс-доменных данных для движения в сторону фундаментальной модели.

  2. Движение в сторону объединения трансформеров с градиентными бустингами на хороших табличных признаках. Если есть хорошие «рукотворные» признаки и табличная постановка задачи для градиентного бустинга, не стоит ожидать, что Perseus сможет ее победить. В этом случае он мог бы стать хорошим генератором «скора» для бустинга. Но у нас есть примерное представление, как сделать так, чтобы Perseus обучался сразу со всеми признаками в end-to-end-формате.

  3. Интеграция Perseus в онлайн-сценарии с расчетом рекомендаций на лету, где мы не только умеем обрабатывать много событий по клиентам, но и применяем фреймворк в момент пользовательского запроса.

На этом у меня все. Будем рады фидбэку и надеемся, что Perseus вам пригодится!

ссылка на оригинал статьи https://habr.com/ru/articles/1061236/