Решения
Рекомендательные системы на GPU: DLRM и двухбашенные модели
Задача страницы. Практический гид по построению рекомендательных систем на GPU: DLRM (Dense+Sparse, большие эмбеддинги), двухбашенные модели (two‑tower) для быстрого кандидатообразования, негатив‑семплинг, оффлайн‑батчи и онлайн‑сервинг с низкой латентностью. Дадим пайплайны (retrieval→ranking→rerank/diversity), sizing по профилям 24/48/80 ГБ, конфиги (Docker/K8s/YAML), метрики (CTR/AUC/NDCG/latency), экономику и траблшутинг. Предполагается локальный NVMe‑кэш, режимы On‑Demand (онлайн‑рекомендации) и Interruptible (оффлайн‑тренинг/ингест), контейнеризация и наблюдаемость.
TL;DR
- Архитектура в проде: Two‑tower retrieval (ANN на GPU) → DLRM‑ранкер → [опц.] Rerank/диверсификация/правила.
- Тренинг: оффлайн батчи, чекпоинт‑рестарт, негатив‑семплинг (in‑batch/hard negatives), FSDP/ZeRO/шардирование эмбеддингов.
- Данные/фичи: разреженные категориальные (ID/хэши), числовые (нормировка), взаимодействия (feature crossing). Хранилище фичей на NVMe. См. https://cloudcompute.ru/solutions/storage-data/
- Наблюдаемость: CTR/AUC/NDCG@K, latency p50/p95, QPS, калибровка (ECE), дрифт фичей/лейблов. См. https://cloudcompute.ru/solutions/monitoring-logging/, https://cloudcompute.ru/solutions/llm-inference/observability/
- Экономика: Cost_per_1M_recs ≈ (c_gpu × 1e6 × t_infer) / (3600 × U); размер эмбеддингов: Mem = Σ |V_i| × d_i × bytes × multipliers. См. https://cloudcompute.ru/solutions/cost-planner/, https://cloudcompute.ru/solutions/throughput-vs-latency/
- Пулы: On‑Demand для онлайн‑скара (низкая латентность), Interruptible для тренинга/переиндексации. См. https://cloudcompute.ru/solutions/interruptible-patterns/
- Мульти‑GPU/мульти‑нод: DP/FSDP/шардирование таблиц (row/table/column), NCCL‑топологии. См. https://cloudcompute.ru/solutions/multi-gpu/
Сценарии (когда это нужно)
- E‑commerce/маркетплейсы: персонифицированные ленты, блок «Похожие», up‑/cross‑sell.
- Контент/медиа: рекомендации видео/музыки/статей; гибридные сигналы (контент+коллаборатив).
- Финтех/реклама: next‑best‑offer, bid‑рекомендации, ограничение частоты.
- B2B/SaaS: рекомендации функций/тем/документации, персональные дайджесты.
- Поиск по каталогу: двухбашенный retrieval (ANN) для быстрых кандидатов, ранжирование DLRM.
Архитектуры и пайплайны

1) Онлайн‑сервинг (retrieval → ranking → rerank)
Request(user_id, ctx)
└─> Feature Builder (real-time)
├─> User tower embed(u) # two-tower
├─> ANN Search on Item Index (GPU) # top-N candidates
└─> Feature Join (candidates + ctx)
└─> DLRM Ranker (dense + sparse + crosses)
└─> Rerank (diversity/business rules)
└─> Top-K + Response (JSON)
Особенности: кэш user‑эмбеддингов в HBM, шардированный ANN‑индекс на GPU, быстрый join фичей, p95 latency контролируется размером кандидатов/фичей/MLP.
2) Оффлайн‑тренинг (батчи, негатив‑семплинг)
Logs/Events ─┬─> ETL → Feature Store (NVMe)
├─> Negative Sampling (in-batch/hard)
└─> Trainer (FSDP/ZeRO, AMP)
├─> Two-tower (user/item)
└─> DLRM (sparse tables + MLP)
└─> Checkpoint/Export
├─> Item Tower → ANN Index Build (GPU)
└─> Ranker Weights → Serving
3) Обновление каталога/индекса (репликация без простоя)
New Item Embeddings ─> Shadow ANN Index ─> Warmup/QA ─> Swap alias ─> Traffic shift
Профили GPU и ориентиры (онлайн‑сервинг)
Оценка по количеству одновременных онлайн‑рекомендаций при U≈0.7, ANN на GPU, K=200 кандидатов, ранкер DLRM среднего размера. Для оффлайна используйте формулы в «Экономике».
Профиль GPU | Память | Типовой стек | Real‑time RPS* | Комментарии |
24 ГБ (Compact) | 24 ГБ | Two‑tower retrieval + лёгкий DLRM | 100–300 | Малая глубина фичей, компактные эмбеддинги (32–64). |
48 ГБ (Balanced) | 48 ГБ | Two‑tower + средний DLRM | 300–700 | Баланс latency/качества, стабильный p95. |
80 ГБ (HQ) | 80 ГБ | Крупный рангер + расширенные фичи | 700–1500 | Глубокий MLP, много фичей, аггрегаты по сессии. |
* Диапазон зависит от числа кандидатов, размера эмбеддингов/фичей, глубины MLP и I/O.
Вместимость on‑device кэша эмбеддингов (инференс, FP16, бюджет 75% HBM)
Профиль | dim=64 | dim=128 |
24 ГБ | ≈ 151 млн | ≈ 75 млн |
48 ГБ | ≈ 302 млн | ≈ 151 млн |
80 ГБ | ≈ 503 млн | ≈ 252 млн |
Для тренинга учитывайте умножители памяти (оптимизатор/градиенты/активации), см. «Экономика».
Конфиги и скелеты кода
Docker Compose (онлайн‑retrieval + DLRM‑ranker)
version: "3.9"
x-env: &env
MODELS_DIR: /models
CACHE_DIR: /var/cache/recsys
PRECISION: "fp16" # bf16|fp16
TOPK: "200"
RERANK_K: "50"
ANN_INDEX_PATH: "/index/items"
USER_CACHE_HOT: "true"
services:
recsys-serving:
image: cloudcompute/recsys-serving:latest
environment: *env
deploy:
resources:
reservations:
devices: [{ capabilities: ["gpu"] }]
ports: ["9000:9000"]
volumes:
- /nvme/models:/models
- /nvme/recsys-cache:/var/cache/recsys
- /nvme/index:/index
command: ["python", "serve.py", "--host=0.0.0.0", "--port=9000"]
Docker Compose (оффлайн‑тренинг two‑tower + DLRM)
version: "3.9"
services:
recsys-train:
image: cloudcompute/recsys-train:latest
environment:
DATA_DIR: /data
CHECKPOINT_DIR: /checkpoints
PRECISION: fp16
NEGATIVE_SAMPLING: "in_batch" # in_batch|hard|mixed
BATCH_SIZE: "65536"
FSDP: "true"
LR: "3e-4"
deploy:
resources:
reservations:
devices: [{ capabilities: ["gpu"] }]
volumes:
- /mnt/logs:/data
- /nvme/ckpt:/checkpoints
command: ["python", "train.py"]
K8s (онлайн‑сервинг, 1 GPU/под)
apiVersion: apps/v1
kind: Deployment
metadata:
name: recsys-serving
spec:
replicas: 3
selector: { matchLabels: { app: recsys-serving } }
template:
metadata: { labels: { app: recsys-serving } }
spec:
containers:
- name: serving
image: cloudcompute/recsys-serving:latest
ports: [{ containerPort: 9000 }]
env:
- { name: PRECISION, value: "fp16" }
- { name: TOPK, value: "200" }
- { name: RERANK_K, value: "50" }
volumeMounts:
- { name: models, mountPath: /models }
- { name: cache, mountPath: /var/cache/recsys }
- { name: index, mountPath: /index }
resources:
limits: { nvidia.com/gpu: 1, memory: "24Gi", cpu: "4" }
volumes:
- name: models ; hostPath: { path: /nvme/models }
- name: cache ; hostPath: { path: /nvme/recsys-cache }
- name: index ; hostPath: { path: /nvme/index }
Конфиг пайплайна (YAML)
schema:
dense: ["price", "discount", "session_time", "age_norm"]
sparse: ["user_id", "item_id", "brand", "category", "geo", "device"]
crosses:
- ["brand","category"]
- ["geo","device"]
two_tower:
user_tower:
emb_dims: { user_id: 64, geo: 16, device: 8 }
mlp: [256, 128, 64]
item_tower:
emb_dims: { item_id: 64, brand: 16, category: 16 }
mlp: [256, 128, 64]
loss: "bpr" # bpr|softmax|sampled_softmax
neg_sampling: "in_batch" # in_batch|hard|mixed
dlrm_ranker:
embedding_dims: { user_id: 64, item_id: 64, brand: 16, category: 16, geo: 16, device: 8 }
bottom_mlp: [256, 128]
top_mlp: [256, 128, 1]
interactions: "dot" # dot|concat|cross
loss: "bce"
serving:
ann:
type: "gpu_hnsw" # gpu_flat|gpu_ivf|gpu_hnsw
topk: 200
rerank:
k: 50
diversity_lambda: 0.2
thresholds:
min_score: 0.05
Python (скелет): двухбашенный тренинг с in‑batch негативами
import torch, torch.nn as nn, torch.nn.functional as F
class Tower(nn.Module):
def __init__(self, emb_dims, mlp_layers):
super().__init__()
self.embs = nn.ModuleDict({k: nn.Embedding(num_embeddings=card, embedding_dim=dim)
for k, (card, dim) in emb_dims.items()})
dims = [sum(dim for _, dim in emb_dims.values())] + mlp_layers
self.mlp = nn.Sequential(*[nn.Linear(dims[i], dims[i+1]) for i in range(len(dims)-1)])
def forward(self, x_sparse):
e = [self.embs[k](x_sparse[k]) for k in self.embs] # [B, dim]
h = torch.cat(e, dim=-1)
return F.normalize(self.mlp(h), dim=-1)
class TwoTower(nn.Module):
def __init__(self, user_cfg, item_cfg):
super().__init__()
self.user = Tower(user_cfg["emb_dims"], user_cfg["mlp"])
self.item = Tower(item_cfg["emb_dims"], item_cfg["mlp"])
def forward(self, user_sparse, item_sparse):
u = self.user(user_sparse) # [B, D]
v = self.item(item_sparse) # [B, D]
return u, v
def bpr_loss(u, v):
# in-batch negatives: scores = u @ v.T
s = u @ v.T # [B, B]
pos = s.diag()
neg = s - torch.diag_embed(pos)
loss = -torch.log(torch.sigmoid(pos.unsqueeze(1) - neg)).mean()
return loss
# Тренинг-цикл (AMP + FSDP/ZeRO по необходимости)
Python (скелет): онлайн‑сервинг retrieval→ranking
def retrieve_candidates(user_vec, ann_index, topk=200):
# ann_index.search(user_vec) -> ids, distances
ids, d = ann_index.search(user_vec, topk)
return ids
def rank_candidates(features_batch, dlrm_model):
# features_batch: объединённые dense+sparse фичи для user×items
with torch.cuda.amp.autocast():
scores = dlrm_model(features_batch) # [B, 1]
return scores
def recommend(user_features):
user_vec = user_tower(user_features["sparse"])
cand_ids = retrieve_candidates(user_vec, ann_index, topk=cfg.topk)
feats = feature_join(user_features, cand_ids) # dense+sparse join
scores = rank_candidates(feats, dlrm_model)
reranked = diversify(cand_ids, scores, lambda_=0.2)
return topk(reranked, k=cfg.rerank_k)


Наблюдаемость/метрики/алерты
Offline (качество):
- recsys_auc, recsys_ndcg@k, recsys_map@k, recsys_mrr@k, recsys_ece (калибровка).
- recsys_hardneg_share — доля «жёстких» негативов; recsys_label_leak_check.
Online (прод):
- Latency: recsys_latency_seconds{stage=feature|ann|rank|rerank} (p50/p95).
- Throughput: recsys_qps, recsys_batch_size_effective.
- CTR/CVR/Revenue‑per‑Mille: агрегаты по трафику/сегментам.
- Drift: recsys_feature_drift_{mean,std}, recsys_score_drift.
- GPU: recsys_gpu_utilization, recsys_gpu_mem_peak_bytes, recsys_nvme_{read,write}_mb_s.
Алерты (примеры):
- recsys_latency_p95 > SLA — уменьшить TOP‑K, упростить MLP, включить FP16/BF16/фьюзинг, добавить GPU.
- recsys_auc_drop > threshold — регресс качества; откат модели/индекса.
- gpu_mem_peak/HBM > 0.9 — уменьшить размеры эмбеддингов/батч, разделить сервисы (ANN/ранкер) по пулам.
- recsys_feature_drift > threshold — пересобрать нормировку/калибровку, обновить фичи.
Подробнее: https://cloudcompute.ru/solutions/monitoring-logging/ • https://cloudcompute.ru/solutions/llm-inference/observability/
Экономика и формулы
Обозначения: c_gpu — цена GPU/час, U — целевая загрузка, t_infer — среднее время инференса одной рекомендации (сек).
- Стоимость 1 млн рекомендаций (онлайн):
Cost_per_1M_recs ≈ (c_gpu × 1e6 × t_infer) / (3600 × U). - Сколько GPU (онлайн):
GPU_count = ceil( (QPS × t_infer) / U ). - Время тренинга:
T_epoch ≈ N_samples / (throughput_samples_per_sec × GPU_count × U). - Память эмбеддингов (тренинг):
Mem_params = Σ_i |V_i| × d_i × bytes
Mem_opt ≈ multipliers × Mem_params (Adam: ~2× для m,v; +градиенты).
Итог: Mem_total ≈ (1 + multipliers + градиенты + активации) × Mem_params.
Для инференса можно держать on‑device кэш hot‑ID, cold‑ID — на CPU/NVMe (UVA/pinned), см. https://cloudcompute.ru/solutions/performance-tuning/ - Задержка retrival→rank:
Latency_total ≈ t_ann(topk) + t_join + t_rank(k) + t_rules. Балансируйте topk/rerank_k.
Подробно про компромисс throughput↔latency: https://cloudcompute.ru/solutions/throughput-vs-latency/ • Планирование бюджета: https://cloudcompute.ru/solutions/cost-planner/
Безопасность/политики
- PII/персонализация: хэшируйте пользовательские идентификаторы; разделяйте пользовательские/товарные фичи по бакетам; шифрование «в канале/на диске».
- Ретеншн: события/логи — TTL; обучающие выборки — версионирование/аудит; без хранения исходных PII в фичах.
- Доступ: разграничение по тенантам/региону; отдельные пулы GPU; журналирование экспорта моделей/индексов.
- Защита от утечки сигналов: фильтрация лейблов/фичей, анти‑label‑leakage проверки.
Подробнее: https://cloudcompute.ru/solutions/security/ • https://cloudcompute.ru/solutions/storage-data/
Траблшутинг
Симптом | Возможная причина | Решение |
Latency p95 ↑ | Большой TOP‑K/тяжёлый ранкер/медленный join | Снизить TOP‑K, упростить MLP, предварительный фильтр, ускорить фичестор (NVMe) |
CTR не растёт при AUC↑ | Модель некалибрована/не учтён бизнес‑контекст | Калибровка (Platt/Isotonic), бизнес‑правила/диверсификация, онлайн‑A/B |
Память HBM OOM | Крупные эмбеддинги/батчи | FP16/BF16, уменьшить d, шардировать таблицы, вынос cold‑ID на CPU/NVMe |
Обучение «взрывается» | Слишком агрессивные hard‑negatives/LR | Ослабить hard‑negatives, reduce LR, gradient clipping |
Фичи «разъехались» | Скью между тренингом и продом | Единый фичестор, версионирование трансформов, тест «тренинг=прод» |
Перенасыщение популярных ID | Частотные дисбалансы | Частотное семплирование, регуляризация/декорреляция фичей |
Падение recall@K в retrieval | Недостаточный ANN/квантование | Поднять efSearch/nprobe, уменьшить PQ, увеличить размер индекса |
Дрифт показателей | Смена сезона/каталога | Регулярные переобучения, онлайн‑апдейты эмбеддингов, детект дрифта |
См. также: https://cloudcompute.ru/solutions/performance-tuning/ • https://cloudcompute.ru/solutions/interruptible-patterns/
Как запустить в cloudcompute.ru
- Откройте Шаблоны запусков: https://cloudcompute.ru/solutions/templates/ — выберите RecSys (Serving) и/или RecSys (Training + Index Build).
- Выберите профиль GPU: 24/48/80 ГБ — по глубине модели/объёму эмбеддингов и SLA.
- Смонтируйте диски: /nvme/models, /nvme/recsys-cache, /nvme/index, для тренинга — /mnt/logs и /nvme/ckpt.
- Заполните переменные окружения из docker-compose.yml (ANN, TOP‑K, precision, batching).
- Для продакшна: раздельные пулы On‑Demand/Interruptible, автоскейл по U/latency/QPS, дашборды и алерты, канареечный деплой.
Дополнительно:
- Сервинг/оптимизация: https://cloudcompute.ru/solutions/triton-inference-server/
- CI/CD контейнеров: https://cloudcompute.ru/solutions/containers-ci-cd/
- Хранилища и данные: https://cloudcompute.ru/solutions/storage-data/
- Мульти‑GPU/распределёнка: https://cloudcompute.ru/solutions/multi-gpu/
Чек‑лист перед продом
- Согласованы целевые метрики: AUC/NDCG@K/CTR uplift.
- Стабильный p95 latency для feature→ANN→rank→rerank; запас по U ≥ 0.2.
- Индекс кандидатов прогрет; стратегия shadow‑index → alias‑swap задеплоена.
- Единый фичестор и идентичные трансформы в тренинге/проде.
- Настроены алерты: latency/QPS/HBM/recall@K/дрифт.
- Политики PII/ретеншна/доступов внедрены.
- Чекпоинты/откат модели и индекса готовы.
- Нагрузочный прогон ≥ 30 мин на целевом профиле/трафике.
Навигация
- Хаб «Решения»: https://cloudcompute.ru/solutions/
- Шаблоны запусков: https://cloudcompute.ru/solutions/templates/
- Планирование стоимости: https://cloudcompute.ru/solutions/cost-planner/
- Throughput vs Latency: https://cloudcompute.ru/solutions/throughput-vs-latency/
- Производительность и тюнинг: https://cloudcompute.ru/solutions/performance-tuning/
- Multi‑GPU: https://cloudcompute.ru/solutions/multi-gpu/
- Хранилища и данные: https://cloudcompute.ru/solutions/storage-data/
- Безопасность: https://cloudcompute.ru/solutions/security/
- Мониторинг и логи: https://cloudcompute.ru/solutions/monitoring-logging/
- Наблюдаемость инференса: https://cloudcompute.ru/solutions/llm-inference/observability/
- Interruptible‑паттерны: https://cloudcompute.ru/solutions/interruptible-patterns/
- Triton Inference Server: https://cloudcompute.ru/solutions/triton-inference-server/
- CI/CD контейнеров: https://cloudcompute.ru/solutions/containers-ci-cd/