Какие недостатки у Mixigen 1.0?
Главный недостаток — оптимизация неправильной метрики. Если полноту считать по положительным действиям с порекомендованными объектами, то он не выучит ничего нового по сравнению с продакшеном. А если по органическим положительным действиям — то баис будет в другую сторону. Например, в музыкальных рекомендациях в колонках, где мы как раз впервые внедрили этот алгоритм, стало выгодно рекомендовать только треки с простыми названиями, иначе пользователи вряд ли могут сами попросить включить такие треки.
Хотелось перейти к принципу, который я описывал в серии постов об измерении качества генерации кандидатов:
Второй недостаток: часто высказывалась мысль о том, что фиксированные веса для всех источников — это недостаточно гибко. Например, для холодных пользователей не очень хочется брать много кандидатов из матричного разложения, которое про этих пользователей почти ничего не знает, а можно просто взять больше популярных объектов. И продуктовые команды начинали сами сегментировать все запросы и на разных сегментах запускать отдельные версии Миксиджена. Трудоемко и не оптимально.
Наконец, чисто технически, для первой версии нужны были длинные списки кандидатов от всех источников — а это даже больше, чем нужно ранжированию. Извлекать такие списки в продакшене и логировать было тяжеловато, поэтому мы их ретроспективно восстанавливали, и это было довольно затратно по ресурсам.
И мы придумали новую схему, которая решала эти проблемы, динамически подстраивалась под запрос и при этом была относительно простой.
В новой версии модель Миксиджена оценивает про каждого кандидата, насколько он понравится финальному ранжированию. При этом модель может использовать все запросные фичи, а про кандидатов — только их источник и позицию в этом источнике. В качестве таргета берём ранг в финальном ранжировании или бинарную метку — попал ли в итоговый список порекомендованного. Лучше обучаться в listwise режиме (например, с cross entropy loss), потому что таргет зависит не только от самого кандидата.
Мы предполагаем (и проверили на практике, см. приложенную картинку), что предсказание такой модели монотонно убывает с рангом внутри источника при фиксированных остальных фичах. Поэтому в рантайме нам не нужны все предсказания сразу для всех кандидатов из всех источников. Можно сначала оценить первых кандидатов из каждого источника и запустить процедуру k-way merge: поддерживать кучу из очередных кандидатов из каждого источника, каждый раз доставать из неё наилучшего кандидата и класть обратно следующего из того же источника. В момент, когда кладём нового кандидата, для него как раз и нужно вычислить предсказание модели.
И всё это можно делать даже до того, как мы делаем обращаемся в сами источники (поэтому можно и меньше кандидатов от них запрашивать). Нужно только успеть извлечь фичи запросов, но это и так почти всегда должно быть первым шагом.
Для обучения нужно чуть-чуть больше логировать в продакшене, чем обычно: источник кандидата, позицию внутри источника, количество извлеченных кандидатов из каждого источника, а также — если используем ранг как таргет — ранг, источник и позицию для не порекомендованных кандидатов (тут можно сильно сэмплировать — как по реквестам, так и кандидатов внутри реквестов).
Базовая идея на этом заканчивается. В следующий раз расскажу про чуть больше нюансов, модификации и сравнение этого подхода с более популярным — дополнительной стадией ранжирования.
Главный недостаток — оптимизация неправильной метрики. Если полноту считать по положительным действиям с порекомендованными объектами, то он не выучит ничего нового по сравнению с продакшеном. А если по органическим положительным действиям — то баис будет в другую сторону. Например, в музыкальных рекомендациях в колонках, где мы как раз впервые внедрили этот алгоритм, стало выгодно рекомендовать только треки с простыми названиями, иначе пользователи вряд ли могут сами попросить включить такие треки.
Хотелось перейти к принципу, который я описывал в серии постов об измерении качества генерации кандидатов:
Главная задача ранних стадий состоит в том, чтобы найти наилучшие документы с точки зрения финального ранжирования.
Второй недостаток: часто высказывалась мысль о том, что фиксированные веса для всех источников — это недостаточно гибко. Например, для холодных пользователей не очень хочется брать много кандидатов из матричного разложения, которое про этих пользователей почти ничего не знает, а можно просто взять больше популярных объектов. И продуктовые команды начинали сами сегментировать все запросы и на разных сегментах запускать отдельные версии Миксиджена. Трудоемко и не оптимально.
Наконец, чисто технически, для первой версии нужны были длинные списки кандидатов от всех источников — а это даже больше, чем нужно ранжированию. Извлекать такие списки в продакшене и логировать было тяжеловато, поэтому мы их ретроспективно восстанавливали, и это было довольно затратно по ресурсам.
И мы придумали новую схему, которая решала эти проблемы, динамически подстраивалась под запрос и при этом была относительно простой.
В новой версии модель Миксиджена оценивает про каждого кандидата, насколько он понравится финальному ранжированию. При этом модель может использовать все запросные фичи, а про кандидатов — только их источник и позицию в этом источнике. В качестве таргета берём ранг в финальном ранжировании или бинарную метку — попал ли в итоговый список порекомендованного. Лучше обучаться в listwise режиме (например, с cross entropy loss), потому что таргет зависит не только от самого кандидата.
Мы предполагаем (и проверили на практике, см. приложенную картинку), что предсказание такой модели монотонно убывает с рангом внутри источника при фиксированных остальных фичах. Поэтому в рантайме нам не нужны все предсказания сразу для всех кандидатов из всех источников. Можно сначала оценить первых кандидатов из каждого источника и запустить процедуру k-way merge: поддерживать кучу из очередных кандидатов из каждого источника, каждый раз доставать из неё наилучшего кандидата и класть обратно следующего из того же источника. В момент, когда кладём нового кандидата, для него как раз и нужно вычислить предсказание модели.
И всё это можно делать даже до того, как мы делаем обращаемся в сами источники (поэтому можно и меньше кандидатов от них запрашивать). Нужно только успеть извлечь фичи запросов, но это и так почти всегда должно быть первым шагом.
Для обучения нужно чуть-чуть больше логировать в продакшене, чем обычно: источник кандидата, позицию внутри источника, количество извлеченных кандидатов из каждого источника, а также — если используем ранг как таргет — ранг, источник и позицию для не порекомендованных кандидатов (тут можно сильно сэмплировать — как по реквестам, так и кандидатов внутри реквестов).
Базовая идея на этом заканчивается. В следующий раз расскажу про чуть больше нюансов, модификации и сравнение этого подхода с более популярным — дополнительной стадией ранжирования.