Two-Tower и Retrieval
Двухбашенные модели, ANN-индексы (FAISS, ScaNN), candidate retrieval.
Two-Tower — как искать среди миллионов за миллисекунды
Загрузка интерактивного виджета...
У тебя 100 миллионов айтемов. Для каждого пользователя нужно найти топ-1000 кандидатов за <50мс. Прогнать нейросеть 100М раз? Невозможно. Two-Tower решает это: user и item кодируются независимо, поиск — через приближённый поиск ближайших соседей.

Как работает
User Tower берёт признаки пользователя (история, демография, контекст) и кодирует в вектор. Item Tower — признаки айтема (категория, описание, популярность) в другой вектор. Совместимость = скалярное произведение или косинусное сходство.
- Обучение: пары (user, pos_item) + негативные примеры → контрастивный лосс
- Инференс: все item-эмбеддинги считаем заранее и кладём в индекс
- Онлайн: считаем только user-эмбеддинг → ANN-поиск по индексу → топ-K кандидатов
ANN-индексы: FAISS, ScaNN, HNSW
ANN (Approximate Nearest Neighbors) — приближённый поиск ближайших соседей. Точный поиск по 100М векторам — O(n). ANN — почти O(1) за счёт индексации. Потеря точности ~1-5%, но скорость — миллисекунды.
- FAISS (Meta) — стандарт индустрии. IVF + PQ для больших объёмов
- ScaNN (Google) — оптимизирован для скалярного произведения
- HNSW — граф, хорош для высокой точности. Hnswlib, Qdrant, Milvus
import faiss
dim = 64 # размерность эмбеддингов
index = faiss.IndexFlatIP(dim) # точный поиск
index.add(item_embeddings) # добавляем все айтемы
D, I = index.search(user_emb, k=100) # топ-100 ближайшихНа собесе
Негативные примеры — ключ к качеству
Без негативов модель не умеет различать: все айтемы одинаково «хорошие». Откуда брать негативы? Случайные айтемы из каталога (in-batch negatives — самый простой: другие позитивы в батче становятся негативами), hard negatives (айтемы из топа, которые не кликнули — учат модель различать похожие).
Проблемы и решения
- Sampling bias: популярные айтемы чаще попадают в негативы → коррекция через log-Q
- Обновление индекса: новые айтемы нужно быстро добавлять → инкрементальное обновление
- Ограниченная выразительность: dot-product не ловит сложные паттерны → дальше ранжируем тяжёлой моделью
- Коллапс эмбеддингов: все вектора сходятся в одну точку → temperature в лосс-функции + нормализация
🎯 Суть для собеса