Two-tower — retrieval
Раздельные башни user/item → векторы в общем пространстве, близость = dot-product. Item-векторы предсчитываются → подбор кандидатов масштабируется через ANN. Обучение — in-batch negatives с logQ-коррекцией.
🖱 Онлайн: кликай — выдача меняется
Кликай фильмы, которые тебе «зашли». Справа — что порекомендует two-tower прямо сейчас, без всякого пользователя в системе. Модель не переобучается: твои клики сворачиваются (fold-in) в один сессионный вектор — центроид их эмбеддингов — и мы переранжируем замороженные item-векторы. Так в проде делают мгновенную сессионную персонализацию.
Кликни пару фильмов слева — здесь появится выдача.
Карта item-эмбеддингов (item-башня): топ-400 фильмов
Это те самые замороженные векторы фильмов, которые в проде кладут в ANN-индекс. Точки спроецированы в 2D (PCA), цвет — основной жанр.
обучение и проекция эмбеддингов…
Теория простым языком
Two-tower — это модель для retrieval: две раздельные «башни» (нейросети) переводят пользователя и фильм в векторы одного пространства, а близость — это их скалярное произведение. Хитрость в том, что векторы фильмов можно посчитать заранее, и тогда подбор кандидатов — это один matrix-vector (а на больших каталогах — ANN-поиск).
Две башни
Почему раздельно — это и есть ключ к скорости. Эмбеддинги всех фильмов считаются один раз офлайн и кладутся в индекс. На запрос мы считаем только вектор пользователя и ищем ближайшие item-векторы.
Отсюда важное следствие про context-фичи (время, устройство, запрос): item-векторы предрассчитаны офлайн, поэтому request-time контекст обычно кладут в user/query-башню или в ранкер — но не в item-башню, иначе её нельзя было бы закешировать.
▸Почему понадобился two-tower retrieval
Как обучается: in-batch negatives
Брать негативы по одному дорого. Хитрый приём: внутри одного батча из пар (пользователь, его фильм) для каждого пользователя все остальные фильмы батча — это негативы. Один проход даёт сразу много негативов бесплатно.
Подвох и его починка: logQ-коррекция
У in-batch negatives есть коварный баг. Популярные фильмы чаще попадают в батч, а значит чаще оказываются «негативом» для чужих пользователей — и модель учится их подавлять. В итоге она задвигает хиты и тащит наверх шум.
# офлайн-обучение
для каждого батча пар (u, i):
U = user_tower(u) # (B, d)
V = item_tower(i) # (B, d)
S = U @ Vᵀ − logP(i) # (B, B), logQ-коррекция по столбцам
loss = softmax_CE(S, диагональ = позитив)
# офлайн один раз
item_emb = item_tower(все фильмы) # кладём в ANN-индекс
# на запрос
u_vec = user_tower(пользователь)
кандидаты = ANN.top_k(item_emb, u_vec)▸Формулы: башни, скор, in-batch softmax с logQ
Каждая башня — MLP над эмбеддингом id:
В батче из пар — softmax-кросс-энтропия, где правильный класс для строки это её диагональ, с logQ-коррекцией по кандидатам:
Вычитание и есть поправка на то, что популярные айтемы чаще попадают в батч как негативы.
Где это в общей картине
Two-tower — это первый этап двухстадийной схемы: дёшево достать сотни кандидатов из миллионов (retrieval), а потом отдельная тяжёлая модель их переранжирует (ranking). На наших данных по точности он в одном ряду с baseline — но его ценность не в NDCG на 9k фильмов, а в том, что он масштабируется на каталог в миллионы через ANN. (Двухстадийность подробно — в следующих фазах.)
Сильные стороны
- Масштабируется: item-эмбеддинги предсчитываются, retrieval = ANN-поиск за миллисекунды.
- In-batch negatives дают много негативов почти бесплатно.
- Легко добавить признаки (контент, контекст) в башни — основа продовых ретриверов.
Слабые стороны
- Без logQ-коррекции in-batch negatives ломают модель (popularity bias) — мы это видели.
- Раздельные башни не моделируют тонкие user-item взаимодействия (это работа ranking-этапа).
- Холодный старт и in-batch false negatives (свой айтем как чужой негатив).
⚠️ Что может пойти не так
- In-batch popularity bias: без logQ-коррекции популярные айтемы подавляются — точность падает почти до нуля (видели: 0.001 → 0.028).
- False negatives в батче: айтем, который реально нравится пользователю, может оказаться чужим «негативом» в том же батче.
- Два этапа: two-tower — это retrieval, а не финальное ранжирование. Сравнивать его по NDCG с ranking-моделями некорректно.
- Холодный старт: новому id неоткуда взять эмбеддинг (решается признаками в башне).
🧠 Проверь себя: Зачем в two-tower нужна logQ-коррекция?
Где встречается в жизни
Two-tower — рабочая лошадка retrieval-этапа в YouTube, рекламе, маркетплейсах: миллионы кандидатов, ANN-поиск, in-batch negatives с коррекцией. Дальше отобранных кандидатов переранжирует более тяжёлая модель — об этом в фазе про двухстадийную архитектуру.