Рекомендательные системы обычно состоят как минимум из двух стадий: кандидатогенерация и ранжирование. "Кандген" из больших каталогов айтемов отбирает сотни-тысячи, ранжирование еще дальше фильтрует небольшое множество кандидатов с прошлых стадий и превращает в отранжированную итоговую выдачу.
Чтобы обучить кандген модельку, чаще всего используется contrastive learning. Самый популярный нынче вариант — это sampled softmax loss. У него много разных названий, пожалуй, два других самых известных — это InfoNCE и NTExent. По названию можно понять в чём суть: чтобы посчитать вероятность позитива, вместо софтмакса по всей коллекции айтемов сэмплируем небольшое количество негативов. Можно считать, что мы таким образом аппроксимируем исходный софтмакс по всей коллекции. Почему бы не сделать полный софтмакс? Это медленно. Что-то подобное, кстати, уже делали во времена word2vec в качестве альтернативы иерархическому софтмаксу.
Cпособов сэмплировать негативы несколько. Самый очевидный — сэмплировать равномерно по всей коллекции. Градиент лосса с таким софтмаксом будет несмещенной оценкой градиента лосса для софтмакса по всей коллекции (it's nice actually). Подход рабочий, особенно если используются трансдуктивные эмбеды по айдишникам: не нужно делать никаких особенных телодвижений для получения векторов, только лукап по таблице эмбеддингов.
Теперь, если вы вдруг обучаете нейросетку над айтемом, т.н. айтем башню, то равномерно сэмплировать негативы уже больновато. Нужно целиком прогонять эту нейросетку для каждого сэмплированного негатива. Да еще и данные, которые идут на вход нейросетке, тоже надо откуда-то доставать. По счастью есть еще один потенциальный источник негативов, in-batch negatives: когда мы набираем батч из пар <юзер, айтем>, айтемы других пар из батча можно переиспользовать как негативы для текущей пары. Так как эмбеды всех пар мы и так считаем, это бесплатно. В мульти-гпу сетапе так вообще можно использовать в качестве негативов айтемы со всех гпу-карточек — cross-device in-batch negatives.
Однако оценка градиента становится смещённой. Ин-батч негативы не совсем "случайны". Вероятность айтема попасть в батч пропорциональна частоте его появления в данных, aka unigram distribution. Чем популярнее айтем, тем чаще он появляется в батче, а значит используется как негатив для остальных пар из батча. Эффект довольно легко интерпретировать: модель часто видит в качестве негативов популярные айтемы и начинает их больше штрафовать, "меморизуя" их популярность. С какой-то точки зрения это полноценный popularity debiasing, см. Contrastive Learning for Debiased Candidate Generation in Large-Scale Recommender Systems by DAMO Academy, Alibaba Group.
Смещение оценки градиента приводит к падению
Ещё не все проблемы решены: хоть у нас теперь и правильное распределение, но в негативах не встречаются объекты, редко попадающие в выдачу, aka стюпиды aka изи негативы. А когда мы выкатываемся в продакшн, эти стюпиды попадут в ANN индекс и мы на них будем плохо работать. В качестве фикса нужно добавить щепотку равномерно сэмплированных негативов. Получаем технику Mixed Negative Sampling от Google: Mixed Negative Sampling for Learning Two-tower Neural Networks in Recommendations.
Кроме Гугла
ин-батч негативы || logQ || MNS используют такие компании, как JD.com, Pinterest, Meta, Instacart, Miscrosoft, Alibaba, Etsy, eBay, Walmart, Baidu.
Fun fact: Yoshua Bengio это всё исследовал еще в начале нулевых, см. раз и два.
P.S: оригинал поста на линкедине.
P. P. S: у Миши @WazowskiRecommends есть хороший пост на эту же тему, я его специально не перечитывал, чтобы сделать ансамблирование :)