Привет, Хабр! Поговорим о RecSys?
Что нужно для построения рекомендательной системы, которая будет полезна бизнесу? Топовые метрики, максимум предсказательной силы, machine learning на полную? Проверим.
Сегодня я покажу:
Как (и почему) мы дропнули в 3 раза ранжирующие метрики в пет-проекте по рекомендациям фильмов
Как искали свой идеальный алгоритм
Как подобрали релевантные рекомендации на самые разные запросы
Будем говорить обо всех аспектах экспериментов в RecSys: метрики, визуальный анализ, workflow, инфраструктура. И проверим результат в онлайн-приложении. Рекомендации от моделей из статьи можно потестить здесь: https://recsysart.ru/
Превью:
Выкатим рекомендательную модель из соревнования в онлайн?
Я начинала пет-проект с простой идеи - сделать онлайн рекомендации фильмов с помощью модели, которую когда-то построила для соревнования (и заняла с ней 4 место). Немного предыстории:
Соревнование по рекомендательным системам на датасете онлайн-кинотеатра Kion. Проводилось совместно MTS и ODS. Ссылка
Задача: порекомендовать юзерам с тестовой недели 10 фильмов/сериалов для просмотра.
Целевая метрика: Mean Average Precision at 10 (MAP@10). Оценивает сразу предсказательную силу модели (способность рекомендовать айтемы, которые реально окажутся во взаимодействиях) и качество ранжирования (способность продвигать такие айтемы в списке рекомендаций на топовые позиции).
Моё решение: 4 место на приватном лидерборде. Двухэтапная модель с коллаборативной фильтрацией на первом этапе, накрученными эвристиками, подобранными фичами и градиентным бустингом в финале. Все решения с более высоким скором - сложные ансамбли из нескольких моделей, включающие помимо прочего пару нейронок.
Технические детали модели: на первом этапе Implicit ItemKNN на косинусных расстояниях. Модель рекомендует 100 кандидатов для каждого юзера, для всех кандидатов считаются фичи. Примеры фичей: хайп (наклон линии тренда, давность медианы распределения дат просмотров айтема), аудитория (доля молодой аудитории, доля женской аудитории), статичные фичи (пол и возраст для юзеров, жанры для айтемов). Финальные рекомендации строит Catboost: решает задачу классификации с целью отличать, какие айтемы из кандидатов окажутся в просмотрах.
Приложение с онлайн-рекомендациями я разработала вместе с Григорием Гусаровым в качестве практики по MLOPs. И мы вместе с ним вывели модель в онлайн. Итак, 4 место в соревновании, осмысленный подбор фичей, отличные результаты на кросс-валидации по ранжирующим метрикам. Казалось бы, что могло пойти не так? Подберём кино к “Аладдину”?
Стойте… Что это? Брутальный боевик, русский военный фильм и комедийный сериал про семейные отношения - в подборке к сказочному “Аладдину” от Disney. Что происходит? Давайте разбираться.
Я ещё не раз буду показывать сегодня подборки от разных алгоритмов на примере топ-3 рекомендаций к определенному фильму, представляя, что у юзера есть только 1 айтем в истории просмотров. Это не отражает реальный анализ алгоритмов, но именно такой формат - самый удобный для статьи.
Итак, расскажу историю по шагам, как…
Как мы дропнули Mean Average Precision в 3 раза для отличных рекомендаций
Шаг 1. Понимаем, что нужно отказаться от максимизации MAP и Recall
В двух словах: MAP и Recall - ключевые метрики для оценки предсказательной силы модели и качества ранжирования (подробности здесь). Почему тогда я предлагаю отказаться от их максимизации в нашей задаче? Всё просто: модель из соревнования, показавшая максимум на этих метриках, часто выдаёт айтемы очень далекие от айтемов в истории просмотров юзеров (как в примере с “Аладдином” выше). В чём причина?
В датасетах онлайн-сервисов популярность айтемов часто распределена согласно степенному закону. Парочка хитов сильно перевешивает во взаимодействиях прочие айтемы. Смотрим, что мы имеем в Кионе:
Что там в топе просмотров? На 3, 4 и 5 месте - именно те фильмы, которые модель порекомендовала на запрос “Аладдин”. Почему это произошло?
Мы оптимизируем градиентный бустинг на предсказание вероятностей взаимодействия юзеров с тем или иным айтемом. И оказывается, что вероятность взаимодействия с айтемом-хитом по факту выше, чем вероятность взаимодействия с чем-то релевантным истории просмотров юзера. Отсюда бустинг имеет bias в сторону хитов и начинает рекомендовать их всем и каждому. Для ранжирующего лосса логика схожая.
В статьях (например здесь) это называют “Popularity bias” - ситуация, когда рекомендательные модели отдают предпочтение более популярным айтемам, даже если менее популярный айтем понравился бы юзеру больше или в той же степени, что и популярный. Как можно проверить popularity bias на метриках? Например, можно посчитать пересечение рекомендаций модели с популярным алгоритмом. Для модели из соревнования мы получим 62%. То есть, больше половины наших рекомендаций для юзеров - это простая подборка популярных айтемов.
Похожие проблемы бывают не только у бустинга. Посмотрим, какие рекомендации предлагала модель первого этапа до того, как её результат прошёл реранжирование? Это простая коллаборативная фильтрация на косинусных расстояниях, которая была выбрана по отличными MAP и Recall на кросс-валидации:
“Мстители” сразу на 2 и на 3 месте в рекомендациях. Популярные айтемы заполняют собой полку рекомендаций и на этот запрос, и на многие другие. Пересечение модели с популярным алгоритмом: 41%. Масштаб проблемы меньше, чем у бустинга, но всё равно очень ощутим.
Я показываю, что модели с высокими Recall и MAP могут активно подтягивать айтемы из топа взаимодействий в топ рекомендаций (замечу: ”могут” не значит “делают всегда”). Что это значит для рекомендательной системы? Зависит от кейса. Если мы рекомендуем всем пользователям нашего онлайн-супермаркета вкуснейший новый хлеб из пекарни, побивший рекорды продаж на прошлой неделе - мы будем в плюсе. А вот если в онлайн-кинотеатре мы всем пользователям без разбора в личной подборке рекомендуем русскую комедию “Прабабушка лёгкого поведения” - у нас большие проблемы. Кейс с “Прабабушкой” реальный. Фильм занимает 6 место в топе просмотров в датасете и очень не вовремя попадает в рекомендации у самых разных алгоритмов.
Очевидно, что с моей моделью из соревнования хороших рекомендаций не сделать. И мы с Григорием в рамках того же пет-проекта решили построить другую модель, которая способна будет порекомендовать релевантный фильм на вечер, что-то близкое к production решению онлайн-кинотеатра. Рекомендации должны быть релевантные, персонализированные и хорошо отвечающие историям просмотров юзеров.
Recall и MAP в этом не помогают, а мы в машинном обучении очень любим максимизировать. Давайте на этот раз выберем метрику поинтереснее. Serendipity.
Шаг 2. Максимизируем Serendipity
Serendipity простыми словами - это способность удивлять пользователя неизвестными, но релевантными для него айтемами. Считать Serendipity можно по-разному, но независимо от формулы, суть остается такой же: мы награждаем модель за угаданные не-популярные айтемы и не награждаем за угаданные популярные. При этом конечная цель - одновременно релевантные и в значительной степени персонализированные рекомендации. Мы взяли реализацию Serendipity из Rectools. Формула здесь.
Забудем на время о двухэтапных моделях и попробуем для начала очень тщательно подобрать бейзлайн. Экспериментировать будем с алгоритмом коллаборативной фильтрации ItemKNN bm25 из библиотеки implicit. С помощью гипер-параметров такая модель отлично может менять своё отношение к популярности айтемов: как “наказывать” за популярность, так и “поощрять” при расчёте скора. Все подробности об использовании алгоритма bm25 в задаче ItemKNN рекомендаций можно почитать здесь.
Метрики - это хорошо, но иногда проблемы моделей быстрее увидеть глазами. Визуальный анализ мы сделали обязательной частью экспериментов. Показываю мини-приложение, которое даёт возможность сравнить рекомендации разных алгоритмов на примере реальных юзеров прямо в Jupyter ноутбуке (тестим по ссылке):
Чтобы проводить визуальный анализ, мы сохраняли рекомендации от моделей с высокими метриками в базу данных и просматривали их на небольшом списке юзеров. Мы подобрали юзеров максимально разнообразно и по жанрам в просмотрах, и по самому количеству просмотров, и по популярности айтемов. Конечная цель такого анализа - подсвечивать проблемы алгоритмов и делать вывод, в правильном ли направлении мы движемся в наших экспериментах.
Что показал визуальный анализ для модели bm25 с максимумом Serendipity? Новые проблемы. На полках начинают появляться странные и неактуальные айтемы вместо актуальных, но более популярных. Модель, по-видимому, имеет bias в сторону непопулярного контента. Результат:
“Американский пирог” после “Гладиатора”: в погоне за Serendipity мы “наказали” айтемы за популярность слишком сильно и полностью потеряли релевантные рекомендации.
Ещё один пример “излишнего” Serendipity в подборке рекомендаций к “Чернобылю”:
Хайповый сериал от HBO на первом месте получает в рекомендации документальный российский фильм 91 года про маньяка-убийцу. Если вы не знаете фильмы в этой подборке, это не удивительно, каждый из них в датасете Киона набрал не больше 150 просмотров. Serendipity в действии: мало-популярные фильмы получают неоправданно высокие скоры от модели.
Пересечение с популярным алгоритмом: 1%. Recall упал в 4 раза, MAP в 5 раз от модели с соревнования. Гипер-параметры модели: K=200, K1=5, B=0.7
Шаг 3. Максимизируем Recall без популярного
Ищем свой идеал дальше, и пока что отвлечемся вновь на popularity bias. Чтобы легко видеть его у моделей на этапе кросс-валидации, мы ввели ряд легко интерпретируемых метрик. Одна из них - recall модели без учета рекомендаций, которые были бы предложены популярным алгоритмом. Как насчёт того, чтобы его максимизировать? Для расчёта метрики просто удаляем из тестовых интеракций все айтемы, которые были бы рекомендованы популярным алгоритмом и считаем Recall оставшихся айтемов. Модели, которые получат на этой метрике высокие скоры, явно должны уметь одновременно давать релевантные, и не самые очевидные рекомендации. То что нужно? Проверим рекомендации от модели с максимумом Recall без популярного:
“Мстители” в запросе “Аладдин”. Мы ведь это уже видели сегодня? Попробуем другой запрос:
Да, мы любим и смотрим Марвел. Пользователи Киона любят и смотрят Марвел. Но мы не можем постоянно рекомендовать Марвел на любые фильмы, хоть немного близкие жанру фантастики.
Последняя модель всё ещё страдает от popularity bias. Мы уменьшили в рекомендациях количество айтемов из топ 10 популярного, но всё ещё активно рекомендуем из топ 100. Recall без популярного очень легко интерпретировать, метрика даёт хорошее представление о происходящем, но не подходит для прямой максимизации.
Пересечение модели с популярным алгоритмом: 13%. Recall и MAP понизились примерно в 2 раза от модели в соревновании. Гипер-параметры модели: K=200, K1=0.1, B=0.7
Шаг 4. Ищем баланс
Тупик? Если говорить только о метриках, то да. У нас нет цели для прямой максимизации, и нужно каким-то образом искать баланс. Здесь мы подключаем на полную визуальный анализ. С ним мы отвечаем на ключевой вопрос: подходит ли модель для решения своей бизнес задачи. В нашем случае мы ищем тематичные и релевантные подборки фильмов на большинство запросов.
Мы сделали поиск гипер-параметров bm25 через grid search и отобрали модели, которые показали себя достаточно хорошо по совокупности метрик. Помимо параметров самой модели мы также подобрали эвристики, чтобы модель не училась на слишком давней истории взаимодействий юзеров и не подтягивала оттуда не релевантные популярные айтемы.
На кросс-валидации мы искали высокие показатели по метрикам Recall без популярного, Serendipity, Mean Inverse User Frequency (MIUF), и низкие по пересечению с популярным алгоритмом.
Расскажу в двух словах о MIUF. Mean Inverse User Frequency показывает склонность модели рекомендовать айтемы из длинного правого хвоста распределения популярности. Чем выше метрика - тем больше айтемов с небольшим количеством просмотров есть в подборках. Формула здесь.
Наша цель - релевантные рекомендации без popularity bias, но ни одну из метрик нельзя максимизировать (или минизировать) напрямую. Финальный баланс между высокой предсказательной силой алгоритма и низким popularity bias подбирался по визуальному анализу. Среди моделей-лидеров с хорошими метриками на кросс-валидации мы искали алгоритм, который не имеет серьёзных промахов на всём многообразии запросов - не скатывается в популярное и не бьёт мимо цели. Посмотрим, что получилось?
“Аладдин” заслужил сегодня свою семейную подборку.
Отлично! Фантастические подборки стали разнообразнее. Проверим последний пример?
Опс… Категория последнего айтема “для взрослых”, и у нас даже нет на него постера. “Последний богатырь” - тоже мимо. Зато дальше в рекомендациях вполне релевантные и тематичные айтемы, из которых можно было бы собрать хорошую полку.
Похожие проблема будут и в других запросах. В неплохие подборки рекомендаций алгоритм может порой подмешивать фильмы, явно выбивающиеся по жанру. Фильмы для взрослых в запросе “Гладиатор”, русские комедии - вместе с мрачными американскими детективами. В конце концов, это всего лишь коллаборативная фильтрация - мы предлагаем фильмы на основе того, как часто они встречаются вместе в историях просмотров юзеров онлайн-кинотеатра.
Пересечение с популярным алгоритмом у модели 12%. MAP и Recall в 2 раза ниже модели с соревнования. В целом результаты похожи на прошлый эксперимент, но мы сделали шаг от предсказательной силы в сторону Serendipity. Гипер-параметры модели: K=50, K1=0.1, B=0.8. Модель обучается на 20 последних интеракциях каждого юзера, давность интеракций не более 60 дней.
Результаты кросс-валидации для всех моделей: сводная таблица
Все метрики считались для первых 10 айтемов в списке рекомендаций (k=10).
Что максимизируем | Модель | MAP | Recall | Recall_no_pop | Serendipity | MIUF | Popular intersection |
---|---|---|---|---|---|---|---|
- | Random | 0.000 | 0.000 | 0.001 | 0.00001 | 15.6 | 0% |
- | Popular | 0.097 | 0.218 | 0.000 | 0.00004 | 4.5 | 100% |
MAP & Recall | Competition 2-stage: cosine + catboost | 0.107 | 0.226 | 0.062 | 0.00017 | 5.2 | 62% |
MAP & Recall | Implicit сosine | 0.090 | 0.196 | 0.072 | 0.00017 | 5.6 | 41% |
Serendipity | Implicit bm25 | 0.020 | 0.048 | 0.053 | 0.00045 | 10.0 | 1% |
Recall без популярного | Implicit bm25 | 0.048 | 0.120 | 0.093 | 0.00017 | 6.4 | 13% |
Баланс метрик | Implicit bm25 | 0.046 | 0.116 | 0.091 | 0.00020 | 6.7 | 12% |
Что дальше?
Итак, у нас есть сильный, изрядно затюненный бейзлайн, у которого бывают проблемы с лишними айтемами в подборках рекомендаций. Будем улучшать результат двухэтапной моделью.
Наш путь к построению финальной двухэтапной модели я расскажу во второй части статьи. Мы будем делать реранжирование, подбирать фичи для градиентного бустинга, продолжим дропать MAP, и увидим наконец хорошие рекомендации к “Гладиатору”. Также я опишу наш подход к валидации сложных двухэтапных моделей.
В третьей части статьи я опишу MLOPs составляющие проекта: workflow экспериментов и инфраструктуру приложения.
А сейчас предлагаю поговорить о том, насколько вообще правомерно (и необходимо) проводить визуальный анализ при оценке алгоритмов.
Плюсы и минусы визуального анализа
Первое важное ограничение: неумение обобщать
Сегодня я на нескольких ярких примерах показала, как меняются рекомендации от алгоритма к алгоритму. В процессе экспериментов мы просматривали десятки подобных примеров. Законный вопрос: как можно узнать, что не произошло оверфита именно на наши запросы?
Полноценный визуальный анализ тысячи запросов для каждой модели стоил бы слишком дорого. Мы не знаем, что происходит в рекомендациях за пределами просмотренного и не можем обобщить выводы на весь датасет. Это важно, и я распишу по пунктам подход, который я использую в своих проектах:
Ищу закономерности в ошибках. Это главная цель визуального анализа - видеть общие ошибки. Один раз увидеть русскую комедию среди детективов - ничего не значит. Постоянно видеть несвоевременные русские комедии среди различных подборок - звоночек о том, что у алгоритма есть проблема.
Строю гипотезы о причинах ошибок. Почему вылезают русские комедии? Посмотрим, что было в EDA. А, вот же - треть просмотров приходится на российский контент, и в топе просмотров есть пара комедий. Нет ли у модели popularity bias?
Проверяю гипотезы на метриках, если возможно. Популярные русские комедии в разных подборках, смотрим метрики: высокий Recall, не слишком высокий Recall без популярного, низкий Mean Inverse User Frequency - диагностируем popularity bias. Стоит поменять параметры модели, чтобы решить проблему.
Добавляю рандомных юзеров. Это помогает мне подтверждать старые гипотезы (снова сплошные “Мстители” в фантастических запросах) и видеть новые проблемы (что тут делает фильм для взрослых?).
Если есть возможность - модель, отобранную для прода, активно проверяю онлайн на новых запросах. Цель аналогична добавлению рандомных юзеров.
Второе важное ограничение: bias исследователя
Исследователь вносит bias, принимая решение о выборе модели, основываясь на личных ощущениях “правильности” рекомендаций. Для нашего пет-проекта с фильмами это не слишком серьёзная проблема, но для production сервиса важно предпринять ряд дополнительных шагов, чтобы нивелировать эффект субъективности мнения исследователя. Например:
Привлечь к оценкам рекомендаций экспертов в предметной области
Привлечь к оценкам рекомендаций реальных юзеров приложения
Выкатить модель в АБ тест и проверить результат на бизнес метриках
Мотивация для использования визуального анализа
Описанные мной ограничения визуального анализа очень серьёзные: невозможность обобщить выводы, субъективность оценок. Почему тогда я предлагаю использовать его в оценке алгоритмов? У меня есть аргументы.
Можно ли сказать, что выбор метрики для максимизации не вносит bias в результат эксперимента? Если идеальным вариантом мы считали бы расчёт реальной пользы от модели при её использовании в сервисе, то любая метрика, посчитанная на оффлайн данных, окажется смещенной оценкой.
Во-первых, потому что мы зависим от оффлайн данных. Самый простой пример проблемы - feedback loop (или зацикленность рекомендаций). Оффлайн данные содержат в себе результат работы прошлой рекомендательной модели, и во время обучения и оценки на них нового алгоритма мы невольно подстраиваемся под результаты прошлой модели.
Во-вторых, потому что математическая логика, заложенная в метрику, приближает реальную полезность от модели, но не может оценить её точно. Мы не можем заранее во всём многообразии понять все подводные камни от максимизации выбранной метрики на конкретном датасете. Пока не начнём видеть ошибки алгоритмов, которые её максимизируют. Например, мы увидели, как максимизация MAP и Recall может вносить bias в сторону популярных айтемов. Serendipity - bias в строну непопулярных. Нашей задачей становится поиск того баланса нескольких метрик, который наилучшим образом отражает реальную полезность модели.
Финальная цель любой рекомендательной системы - принести business value. Например, осчастливить пользователей, увеличивая их лояльность и life-time value, и как следствие - прибыльность бизнеса. В других случаях - увеличить покупки сопутствующих или маржинальных товаров, напрямую поднимая выручку и прибыль компании. Оффлайн метрики оценивают алгоритмы математически, следуя заложенной в них логике, но только проксируют реальный business value, который может принести модель. Аналогично, визуальный анализ - ещё один способ проксирования возможного business value от рекомендательной модели. Это дополнительный инструмент для оценки алгоритмов, который может сравнить результат работы моделей с human level performance и подсветить проблемные места.
Рекомендательные модели работают онлайн здесь.
Визуальный анализ в Jupyter ноутбуке можно потестировать здесь.
Наша команда
Тихонович Дарья
ML инженер в группе рекомендательных систем MTS BigData
Лидер проекта, ведущий разработчик. Linkedin
Гусаров Григорий
ML инженер (NLP, RecSys)
Разработчик и соавтор проекта. Linkedin
За ревью спасибо @asash и @egor_labintcev