Как стать автором
Обновить

Эмбеддинги пользователя в DMP. Эксперименты, оптимизация, внедрение

Время на прочтение7 мин
Количество просмотров4.7K

Всем привет! Мы из команды ML проекта DMP (Data Management Platform) в AdTech Rambler Group. В этой статье поговорим про эмбеддинги.

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

Общее про DMP и зачем нам эмбеддинги?

Начнем с того, что у Rambler Group есть свой стек RTB-технологий (real-time-bidding), которые позволяют продавать и откручивать современную programmatic-рекламу, подбирая для конкретного пользователя наиболее оптимальные объявления. Еще у нас есть много логов пользовательского поведения, из которых нужно извлечь сигнал об их предпочтениях для персонализации рекламы. Здесь и появляется DMP.

DMP – это инструмент для создания единого профиля пользователя. Делается это путем сбора, обработки и структурирования событийных логов пользователей различных активов Rambler Group. Конечная цель DMP – построение и хранение аудиторных сегментов, которые используются для выделения целевых аудиторий и таргетирования онлайн-рекламы в системе RTB.

Сегментация пользователей
Сегментация пользователей

Машинное обучение – один из ключевых способов построения сегментов в нашей DMP. В проде работает ML-пайплайн, который ежедневно обучает порядка тысячи моделей и размечает пользователей более чем на 3 тысячи сегментов.

Текущее решение служит нам верой и правдой уже несколько лет, однако оно не лишено недостатков:

  • фичи для моделей считаются в разное время, что усложняет логику работы пайплайна и непредсказуемо влияет на качество сегментов;

  • расчет разнородных фич требует больших вычислительных ресурсов; 

  • для отдельных моделей требуется кастомизация фич и эксперименты ad hoc;

  • достигли предела по качеству с имеющимися подходами к генерации фич;

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

ЭКСПЕРИМЕНТЫ С ЭМБЕДДИНГАМИ

О наших данных

Каждый день мы получаем порядка 1 млрд событий пользовательских сессий, что составляет 3 терабайта сырой информации. Это данные счетчика «Рамблер/топ-100» – сервиса веб-аналитики портала «Рамблер», который существует более 20 лет. Эти логи содержат следующие поля: анонимный идентификатор (cookie), url, domain, title и ряд других признаков, описывающих детали сессии пользователя. 

Ниже скриншот с Lenta.ru – одного из медиаресурсов Rambler Group. Красным выделены киллер-фичи большинства наших моделей: домен сайта и title страницы.

Domain и title - ключевые признаки в наших моделях
Domain и title - ключевые признаки в наших моделях

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

На первом этапе мы взяли как фичу title страницы по урлу, т.к. он зачастую  несет в себе самый сильный сигнал о поведении пользователя. Title – это текстовая строка, содержащая информацию о контенте страницы. Эмбеддинги слов тайтлов мы получили с помощью классики дистрибутивной семантики – модели FastText из библиотеки DeepPavlov, которая была обучена на корпусе российской «Википедии» и контента новостного сайта издания Lenta.ru. Эмбеддинг тайтла – усреднение эмбеддингов токенов, входящих в него. Эмбеддинг пользователя, в свою очередь, получается усреднением эмбеддингов тайтлов по логу событий.

Event encoder & User Encoder

Baseline с усреднением эмбеддингов по логам пользователей дает неплохой результат. Но могут ли нам помочь более «умные» способы обработки логов текстовых данных? В начале 2021 года в индустрии обработки естественного языка, конечно, правят трансформеры, однако использование таких моделей в продакшне требует больших вычислительных ресурсов. Мы решили начать с рекуррентных нейронных сетей. Архитектуру модели поделили на 2 этапа: Event Encoder и UserEncoder.

Схема построения эмбеддингов
Схема построения эмбеддингов

На первом этапе (Event Encoder) получаем эмбеддинги событий из лога пользователя. Веса эмбеддингов тайтла инициализируем по логике описанного выше baseline с помощью предобученной модели FastText. Помимо этого, добавляем фичу домена, конкатенируем эмбеддинги тайтла и домена, пропускаем через линейный слой и получаем Event embedding.

Архитектура Event Encoder
Архитектура Event Encoder

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

Event Encoder возвращает тензор (batch x user history x event_embedding_size).

User Encoder – финальный штрих пайплайна, в котором больше всего простора для творчества. Он принимает на вход последовательность эмбеддингов событий, полученных на предыдущем этапе, передает их в архитектуру на основе рекуррентных нейронных сетей и возвращает эмбеддинги пользователя.

Далее расскажем про три подхода к архитектуре User Encoder, с которыми мы экспериментировали.

Supervised User Encoder

Исходя из особенностей наших данных, а также задач, которые мы решаем, первое, что мы попробовали – это получить эмбеддинги из Supervised модели с использованием репрезентативной целевой переменной (например, сегмент пола или категории возрастов – таких данных у нас много, и они хорошего качества). В итоге решается задача классификации, где основной блок архитектуры – это рекуррентная сеть (в нашем случае – GRU). На этапе применения модели достаем эмбеддинги с последнего скрытого слоя GRU. Несмотря на то, что такая модель переобучается под целевой сегмент, оказалось, она неплохо обобщается и на другие downstream-задачи. Baseline побили!

Metric Learning Encoder

Параллельно мы экспериментировали с моделями на основе metric learning. Цель такого подхода – научиться отличать эмбеддинги, которые относятся к заданному пользователю, от тех, которые ему не принадлежат.

Нам приглянулся фреймворк pytorch-metric-learning, в котором реализовано множество алгоритмов из популярных статей по теме на чистом pytorch. Для обучения модели нужно обязательно задать функцию потерь и опционально – miner. Miner – это способ поиска таких позитивных и негативных пар эмбеддингов, которые являются «сложными» для модели и, тем самым, способствуют более качественной оптимизации. Ну а дальше идет всем известный цикл обучения модели в pytorch:

from pytorch_metric_learning import miners, losses
miner = miners.MultiSimilarityMiner()
loss_func = losses.TripletMarginLoss()

# your training loop
for i, (data, labels) in enumerate(dataloader):
	optimizer.zero_grad()
	embeddings = model(data)
	hard_pairs = miner(embeddings, labels)
	loss = loss_func(embeddings, labels, hard_pairs)
	loss.backward()
	optimizer.step()

В нашем случае мы сперва прогоняли эмбеддинги событий через слой рекуррентной НС, получая эмбеддинги пользователей, а дальше оптимизировали NTXentLoss (Normalised Temperature-Scaled Cross-Entropy Loss). В качестве майнера мы выбрали MultiSimilarutyMiner. Несмотря на то, что многие функции потерь в metric learning были придуманы для задач компьютерного зрения, ничего не мешает применять эти техники и в других областях машинного обучения.

Next Event Predictor Encoder

Венцом наших стараний стала self-supervised архитектура, основная цель которой – предсказать эмбеддинг следующего события пользователя. Одна из статей, которой мы вдохновлялись, – Representation Learning with Contrastive Predictive Coding. Ключевая идея авторов – извлекать обобщающие представления данных с помощью авторегрессионных моделей.

 Архитектура Next Event Predictor
Архитектура Next Event Predictor

На вход поступает лог (последовательность) эмбеддингов событий пользователя. На каждом шаге последовательности «i» делается предсказание эмбеддинга для шага «i+1». Как только вся последовательность обработана, мы имеем предсказания для всех событий пользователя. 

Дальше логика очень похожа на metric learning. Мы хотим выучить представления пользователей, иначе говоря, чтобы предсказанный на каждом шаге последовательности эмбеддинг события пользователя был как можно больше похож на оригинальный и как можно меньше – на эмбеддинг события случайного пользователя. Считаем соответствующие скалярные произведения, суммируем по всей истории пользователя и передаем в функцию потерь – обычную кросс-энтропию… Профит!

ВЫБОР МОДЕЛИ

Мы провели 3 эксперимента и сравнили их итоги с baseline. Качество мы оценивали с помощью офлайн-метрик на нескольких downstream-задачах, которые для нас наиболее приоритетны.

Все экспериментальные модели оказались лучше baseline. Далее нужно было принять решение, какую модель мы будем внедрять в продакшн. Metric learning работал слишком медленно, поэтому от него мы отказались в первую очередь. Возможно, мы не самым удачным образом подобрали функцию потерь и другие параметры. Так или иначе, эта область показалась нам очень интересной и мы планируем найти время, чтобы провести еще одну итерацию экспериментов.

Supervised модель отлично работала на целевом таргете, относительно неплохо обобщалась на другие downstream-задачи и была проста в реализации. Наконец, модель Next Event Predictor показала лучшие результаты в среднем на всех downstream задачах, лишь немного уступив Supervised модели на целевом таргете. 

В итоге приняли решение использовать модель Next Event Predictor. А дальше нам предстояло самое интересное – довести экспериментальный код до продакшна!

РАЗРАБОТКА И ОПТИМИЗАЦИЯ ПАЙПЛАЙНА

Когда пришло время выводить модель в прод, мы поняли, что не успеваем в течение дня рассчитать порядка 300 млн эмбеддингов. Что интересно, «узкие» места были по большей части связаны с вычислениями на CPU, а не на GPU. Это вызвано сложной логикой расчета признаков для нейросети, в которую входят:

  • токенизация слов;

  • парсинг урлов, обработка доменов;

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

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

  • фильтрация дубликатов событий и многое другое.

Так или иначе, нам удалось кратно ускорить работу пайплайна. Одна из ключевых оптимизаций – перенос вышеупомянутых операций на Apache Spark и создание витрины на hdfs с кэшированными признаками для модели. Обучение и применение модели происходит локально на видеокартах, данные мы качаем из hdfs по партициям и на этапе применения обрабатываем параллельно. 

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

Инфраструктура проекта представлена на картинке:

Инфраструктура проекта
Инфраструктура проекта

ВМЕСТО ЗАКЛЮЧЕНИЯ

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

Теги:
Хабы:
+5
Комментарии5

Публикации

Информация

Сайт
rambler-co.ru
Дата регистрации
Численность
1 001–5 000 человек
Местоположение
Россия