Как известно, в рекомендательных системах есть несколько стадий построения рекомендаций: сначала происходит генерация кандидатов, а затем — одна или несколько стадий ранжирования. В статьях уделяют не очень много внимания ранним стадиям. Но на практике они довольно важны. И важно, как измерять их качество.
Чаще всего кандидато-генерация устроена как объединение разных источников:
- самые популярные объекты,
- похожее на историю пользователя,
- ANN — похожее по эмбеддингам (например, HNSW),
- комбинация предыдущих методов на разных уровнях: например, взять категории из истории пользователя (или из ANN, или популярные), а потом из них взять популярные объекты.
Хотя каждый метод тут может быть несложным, вся комбинация получается достаточно нетривиальной, чтобы задуматься: а как её можно оптимизировать? А для этого нужно, конечно, определить, что именно надо оптимизировать, т.е. какой метрикой измерять качество кандидато-генерации (далее будем говорить именно про эту стадию, хотя всё то же самое относится и к ранним стадиям ранжирования).
Существуют разные подходы. Иногда качество просто не замеряют (ну или просто "на глаз") и системно не оптимизируют эту стадию. Иногда каким-то образом замеряют общую релевантность кандидатов. И если система порекомендовала что-то странное, то это считают багом в том числе и кандидато-генерации. Иногда эту релевантность даже противопоставляют тому, что оптимизируется в финальной стадии. Т.е. кандидаты должны быть уже достаточно релевантными (как бы это ни измерялось), а финальное ранжирование выберет из них наиболее engaging (привлекательные/кликабельные/...).
Иногда, особенно в статьях, используют метрики вроде HitRate@k, Recall@k, Precision@k, MRR, NDCG и т.д., фокусируясь только на положительных (релевантных) документах. При этом релевантным считается тот документ, с которым пользователь впоследствии взаимодействовал. Мне этот подход нравится больше предыдущих, хотя тут большая проблема с разными смещениями: например, пользователи чаще взаимодействуют с теми объектами, которые система сама же и рекомендует.
Но в какой-то момент я попытался сформулировать другой подход к кандидато-генерации и с тех пор являюсь его приверженцем. К счастью, оказалось, что я такой не единственный — этот подход уже используется в разных системах (например, в комментариях давали ссылку про Instagram). Но не уверен, что его можно назвать стандартом индустрии — точно есть большие системы, в которых он не используется.
Подход основывается на таком принципе:
Или, простыми словами, цель — найти топ. Топ определяется никакой не релевантностью, а просто текущим финальным ранкером. Те кандидаты, которые в итоге выбираются финальным ранкером, — хорошие, остальные — не очень. Если ранкер поменяется (а он может меняться и довольно часто), то поменяется и оценка качества.
(Тут может быть модификация для многостадийного ранжирования: качество ранней стадии можно оценивать либо с помощью именно финального ранкера, либо с помощью ранкера следующей стадии. Т.е. кандидаты, прошедшие следующую стадию, но не прошедшие финальную, могут считаться как отрицательными, так и положительными. Я не знаю, как лучше.)
Этот принцип превращает кандидато-генерацию в довольно утилитарную задачу с вполне определенной целью. А вся сложность с objectives (какие таргеты и лоссы использовать) перекладывается на финальную стадию ранжирования.
Хотя этот подход и не идеален, лично я считаю его единственным состоятельным, т.е. только с ним можно долгосрочно системно улучшать качество всех стадий и не упереться в фундаментальную проблему. По крайней мере, я не понимаю, как это делать с другими подходами.
В следующий раз я раскрою тему чуть глубже и напишу про плюсы и минусы этого подхода.
Чаще всего кандидато-генерация устроена как объединение разных источников:
- самые популярные объекты,
- похожее на историю пользователя,
- ANN — похожее по эмбеддингам (например, HNSW),
- комбинация предыдущих методов на разных уровнях: например, взять категории из истории пользователя (или из ANN, или популярные), а потом из них взять популярные объекты.
Хотя каждый метод тут может быть несложным, вся комбинация получается достаточно нетривиальной, чтобы задуматься: а как её можно оптимизировать? А для этого нужно, конечно, определить, что именно надо оптимизировать, т.е. какой метрикой измерять качество кандидато-генерации (далее будем говорить именно про эту стадию, хотя всё то же самое относится и к ранним стадиям ранжирования).
Существуют разные подходы. Иногда качество просто не замеряют (ну или просто "на глаз") и системно не оптимизируют эту стадию. Иногда каким-то образом замеряют общую релевантность кандидатов. И если система порекомендовала что-то странное, то это считают багом в том числе и кандидато-генерации. Иногда эту релевантность даже противопоставляют тому, что оптимизируется в финальной стадии. Т.е. кандидаты должны быть уже достаточно релевантными (как бы это ни измерялось), а финальное ранжирование выберет из них наиболее engaging (привлекательные/кликабельные/...).
Иногда, особенно в статьях, используют метрики вроде HitRate@k, Recall@k, Precision@k, MRR, NDCG и т.д., фокусируясь только на положительных (релевантных) документах. При этом релевантным считается тот документ, с которым пользователь впоследствии взаимодействовал. Мне этот подход нравится больше предыдущих, хотя тут большая проблема с разными смещениями: например, пользователи чаще взаимодействуют с теми объектами, которые система сама же и рекомендует.
Но в какой-то момент я попытался сформулировать другой подход к кандидато-генерации и с тех пор являюсь его приверженцем. К счастью, оказалось, что я такой не единственный — этот подход уже используется в разных системах (например, в комментариях давали ссылку про Instagram). Но не уверен, что его можно назвать стандартом индустрии — точно есть большие системы, в которых он не используется.
Подход основывается на таком принципе:
Главная задача ранних стадий состоит в том, чтобы найти наилучшие документы с точки зрения финального ранжирования.
Или, простыми словами, цель — найти топ. Топ определяется никакой не релевантностью, а просто текущим финальным ранкером. Те кандидаты, которые в итоге выбираются финальным ранкером, — хорошие, остальные — не очень. Если ранкер поменяется (а он может меняться и довольно часто), то поменяется и оценка качества.
(Тут может быть модификация для многостадийного ранжирования: качество ранней стадии можно оценивать либо с помощью именно финального ранкера, либо с помощью ранкера следующей стадии. Т.е. кандидаты, прошедшие следующую стадию, но не прошедшие финальную, могут считаться как отрицательными, так и положительными. Я не знаю, как лучше.)
Этот принцип превращает кандидато-генерацию в довольно утилитарную задачу с вполне определенной целью. А вся сложность с objectives (какие таргеты и лоссы использовать) перекладывается на финальную стадию ранжирования.
Хотя этот подход и не идеален, лично я считаю его единственным состоятельным, т.е. только с ним можно долгосрочно системно улучшать качество всех стадий и не упереться в фундаментальную проблему. По крайней мере, я не понимаю, как это делать с другими подходами.
В следующий раз я раскрою тему чуть глубже и напишу про плюсы и минусы этого подхода.