Решения
GNN на GPU: GraphSAGE/GAT и выборка
Задача страницы. Инженерный гид по построению графовых моделей (GNN) на GPU: GraphSAGE и GAT, мини‑батч‑обучение с neighbor sampling, офлайн расчёт эмбеддингов и онлайн‑сервинг для рекомендаций/поиска/аналитики. Разберём пайплайны single‑/multi‑GPU, кэш‑план (HBM↔UVA↔NVMe), метрики p50/p95, экономику, конфиги и траблшутинг. Смежные темы: производительность и тюнинг, распределёнка, хранилища/ETL, сервинг (ссылки в конце).
TL;DR
- Два режима:
Interruptible (train/offline‑embed) — обучение/перерасчёт эмбеддингов узлов/рёбер по расписанию.
On‑Demand (serving) — быстрая выдача по готовым эмбеддингам (retrieval/ANN), опционально «до‑вычисление» локальным k‑hop. - Mini‑batch + sampling: слои GraphSAGE/GAT с fanout на каждый слой (напр. [15, 10]), выборка без/с возвращением, importance/random‑walk; фьюзинг выборки и копирования в GPU, pinned/UVA.
- GraphSAGE vs GAT: GraphSAGE — базовый для крупных графов (стабилен и лёгок), GAT — лучше локального внимания, но тяжелее по памяти/латентности (число «голов» и размер скрытого слоя — главный рычаг).
- Кэш/память: горячие фичи/узлы — в HBM; тёплые — pinned host (UVA/zero‑copy); холодные — NVMe mmap. Контролируйте fanout и «cap» для high‑degree узлов.
- Инференс: слой‑за‑слоем по всему графу (layer‑wise full‑graph) для офлайна, или батч‑инференс по партиям; выгрузка эмбеддингов → ANN‑индекс и ранжирование. См. https://cloudcompute.ru/solutions/recsys/
- Метрики: step_time, loader_time, edges_per_sec, gpu_util/HBM, dup_ratio (дубли узлов при выборке), качество (ROC‑AUC/NDCG@K), и пиковая VRAM.
- Тюнинг: AMP (FP16/BF16), pinned/zero‑copy, предвыборка, микробатчинг, фиксированный cap степеней, шардирование по GPU/NCCL. См. https://cloudcompute.ru/solutions/performance-tuning/, https://cloudcompute.ru/solutions/fp8-bf16/
Сценарии (когда это нужно)
- Рекомендательные системы: user‑item граф, link prediction для кандидатов, офлайн эмбеддинги узлов → ANN retrieval → ранкер DLRM. См. https://cloudcompute.ru/solutions/recsys/
- Антифрод/транзакции: граф платежей/сессий; классификация узлов/рёбер, детект аномалий по окрестности.
- Социальные/контентные графы: друзья‑друзей, co‑view/co‑buy; персональная навигация/поиск.
- Знания/каталоги: enrichment каталога связями (brand↔category↔item), маршрутизация контента по близости.
Архитектуры и пайплайны

1) Обучение (mini‑batch GraphSAGE/GAT с neighbor sampling)
Parquet (nodes, edges, features) on NVMe/Object
└─> Graph Store (CSR/CSC, degree caps, feature mmap)
└─> Neighbor Sampler (fanout per layer, UVA/pinned)
└─> GPU: GNN Forward (L layers, AMP)
└─> Loss (node/edge classification or link prediction)
└─> Backward + Optimizer
└─> Checkpoint + Metrics
Особенности: fanout=[f1,f2,…], cap high‑degree узлов, предвыборка «горячих» фичей в HBM‑кэш, перекрытие sampler↔forward (prefetch, 2 очереди).
2) Офлайн‑эмбеддинги → ANN для сервинга
Trained GNN ──> Layer-wise Inference over full graph
└─> Node Embeddings (FP16/FP32)
└─> Write Parquet (NVMe)
└─> ANN Index Build (GPU)
└─> Serving: Retrieval → Ranker
Особенности: батч‑инференс без выборки, слой‑за‑слоем; результат — эмбеддинги на узел/тип узла.
3) Онлайн‑сценарий (добавление новых узлов/рёбер)
Stream/Kafka ─> Micro-batch ETL ─> Update Graph Store ─┬─> On-demand local k-hop encode (fast path)
└─> Nightly full refresh embeddings (slow path)
Баланс fast/slow‑path: холодный старт действует через локальную окрестность с ограниченным fanout и меньшим числом слоёв.
Профили GPU и ориентиры
Инженерные ориентиры для обучения GraphSAGE/GAT при U≈0.7, L=2–3, fanout≈[15,10], dim=128–256, AMP включён. Фактическая скорость зависит от распределения степеней, коллизий и I/O.
Профиль GPU | Память | Типичный стек | Обучение (edges/sec)* | Инференс (nodes/sec)** | Комментарии |
24 ГБ (Compact) | 24 ГБ | GraphSAGE 2‑слоя, dim=128 | 2–6 млн | 0.5–1.5 млн | Базовые графы, аккуратный fanout/cap. |
48 ГБ (Balanced) | 48 ГБ | GraphSAGE/GAT (4‑8 голов), dim=256 | 6–12 млн | 1.5–3 млн | Баланс качества/скорости. |
80 ГБ (HQ) | 80 ГБ | GAT большой/высокий fanout, dim=256–384 | 10–20+ млн | 3–6 млн | Тяжёлые графы, аггр. фичи, многослойные сети. |
* «edges/sec» — посещённые рёбра за шаги (с учётом выборки).
** «nodes/sec» — офлайн‑инференс узлов (layer‑wise).
Тюнинг и распределёнка: https://cloudcompute.ru/solutions/multi-gpu/, https://cloudcompute.ru/solutions/performance-tuning/
Конфиги и скелеты кода
Docker Compose (train + offline‑infer + ANN‑build)
version: "3.9"
x-env: &env
DATA_DIR: /data/graph
CHECKPOINT_DIR: /checkpoints
PRECISION: "fp16" # bf16|fp16|fp32
MODEL: "graphsage" # graphsage|gat
LAYERS: "2"
HIDDEN_DIM: "256"
FANOUT: "15,10"
BATCH_SIZE: "2048"
NEGATIVE_SAMPLING: "uniform" # для link prediction: uniform|hard
UVA_ENABLE: "true"
PINNED_POOL_MB: "4096"
services:
gnn-train:
image: cloudcompute/gnn-train:latest
environment: *env
deploy:
resources:
reservations:
devices: [{ capabilities: ["gpu"] }]
volumes:
- /nvme/graph:/data/graph
- /nvme/ckpt:/checkpoints
command: ["python","train.py","--data","/data/graph","--ckpt","/checkpoints"]
gnn-infer:
image: cloudcompute/gnn-infer:latest
environment: *env
deploy:
resources:
reservations:
devices: [{ capabilities: ["gpu"] }]
volumes:
- /nvme/graph:/data/graph
- /nvme/emb:/emb
- /nvme/ckpt:/checkpoints
command: ["python","infer_full_graph.py","--data","/data/graph","--out","/emb"]
ann-build:
image: cloudcompute/vector-index:latest
volumes:
- /nvme/emb:/emb
- /nvme/index:/index
command: ["python","build_index.py","--emb","/emb","--out","/index/main"]
K8s (онлайн‑сервинг эмбеддингов + ANN)
apiVersion: apps/v1
kind: Deployment
metadata: { name: gnn-serving }
spec:
replicas: 3
selector: { matchLabels: { app: gnn-serving } }
template:
metadata: { labels: { app: gnn-serving } }
spec:
containers:
- name: serving
image: cloudcompute/gnn-serving:latest
ports: [{ containerPort: 9100 }]
env:
- { name: PRECISION, value: "fp16" }
- { name: ANN_INDEX_PATH, value: "/index/main" }
volumeMounts:
- { name: index, mountPath: /index }
- { name: emb, mountPath: /emb }
resources:
limits: { nvidia.com/gpu: 1, cpu: "4", memory: "24Gi" }
volumes:
- name: index ; hostPath: { path: /nvme/index }
- name: emb ; hostPath: { path: /nvme/emb }
Конфиг пайплайна (YAML)
graph:
nodes: "/data/graph/nodes.parquet" # id, type, features[*]
edges: "/data/graph/edges.parquet" # src, dst, type, ts
features:
dim: 256
dtype: "fp16"
sampling:
fanout: [15, 10]
with_replacement: false
degree_cap: 50
prefetch_batches: 2
uva: true
train:
task: "link_prediction" # node_classification|link_prediction
batch_size: 2048
epochs: 5
lr: 0.001
negative_sampling: "uniform"
fp_precision: "fp16"
model:
type: "graphsage" # graphsage|gat
layers: 2
hidden_dim: 256
heads: 4 # для GAT
dropout: 0.1
infer:
layerwise_full_graph: true
shard: 8
output_embeddings_path: "/emb"
serving:
ann_topk: 200
min_score: 0.05
Python (скелет): GraphSAGE/GAT + neighbor sampling (PyTorch)
import torch, torch.nn as nn, torch.nn.functional as F
from torch.cuda.amp import autocast, GradScaler
# Предполагаем наличие loader, который выдаёт батчи k-hop подграфов:
# for seeds, blocks, labels in loader: blocks = [ (x, edge_index), ... ]
class SAGE(nn.Module):
def __init__(self, in_dim, hidden, out_dim, layers=2):
super().__init__()
self.lins = nn.ModuleList()
dims = [in_dim] + [hidden]*(layers-1) + [out_dim]
for a, b in zip(dims[:-1], dims[1:]):
self.lins.append(nn.Linear(a, b))
def forward(self, x, blocks):
h = x
for i, (x_src, edge_index) in enumerate(blocks):
h_dst = h[:x_src.shape[0]] # convention: dst first
h = self.lins[i](h)
h = F.relu(h)
# mean aggregation (псевдокод)
# h = aggregate_mean(h, edge_index)
return h
class GAT(nn.Module):
def __init__(self, in_dim, hidden, out_dim, layers=2, heads=4):
super().__init__()
self.layers = nn.ModuleList()
for i in range(layers):
h_in = in_dim if i==0 else hidden*heads
h_out = out_dim if i==layers-1 else hidden
self.layers.append(nn.MultiheadAttention(embed_dim=h_out*heads, num_heads=heads, batch_first=True))
def forward(self, x, blocks):
h = x
for attn, (x_src, edge_index) in zip(self.layers, blocks):
# attention over neighborhood (псевдокод: соберите соседей по edge_index)
h, _ = attn(h, h, h, need_weights=False)
h = F.elu(h)
return h
def train(model, loader, feats, optimizer, epochs=5, device="cuda"):
scaler = GradScaler()
model.to(device).train()
for ep in range(epochs):
for seeds, blocks, labels in loader:
x = gather_features(feats, blocks).to(device, non_blocking=True) # UVA/pinned
labels = labels.to(device, non_blocking=True)
optimizer.zero_grad(set_to_none=True)
with autocast(enabled=True):
out = model(x, blocks)
loss = F.binary_cross_entropy_with_logits(out, labels.float()) # для link prediction
scaler.scale(loss).backward()
scaler.step(optimizer); scaler.update()
Инференс слой‑за‑слоем (псевдокод)
def full_graph_inference(model, graph, feats, batch_nodes):
model.eval()
# для каждого слоя вычисляем представления узлов батчами, переиспользуя k-hop соседей
H = feats
for l in range(model_layers):
for seeds in iter_batches(all_nodes, batch_nodes):
neigh = neighbors_of(seeds, graph) # без выборки — все соседи слоя
x = gather_feats(H, seeds, neigh)
H[seeds] = model_layer_forward(l, x, neigh)
return H


Наблюдаемость/метрики/алерты
Perf/Latency:
- gnn_step_time_seconds (p50/p95), gnn_loader_time_seconds, gnn_forward_time_seconds, gnn_backward_time_seconds.
- gnn_edges_per_sec, gnn_nodes_per_batch, gnn_dup_ratio (доля дублей узлов в батче).
- gpu_utilization, gpu_memory_bytes, gpu_mem_peak_bytes, pinned_host_bytes, nvme_{read,write}_mb_s.
- sampler_queue_depth, prefetch_ahead_batches.
Quality (задача):
- Классификация узлов/рёбер: roc_auc, f1, pr_auc.
- Link‑prediction: roc_auc, hits@K, ndcg@K, mrr@K.
Алерты (примеры):
- gnn_loader_time / gnn_step_time > 0.4 — CPU/I/O узкое место: увеличить prefetch, включить UVA, поднять workers и pinned‑pool.
- gpu_mem_peak/HBM > 0.9 — уменьшить fanout, degree_cap, batch_size, перейти на FP16/BF16.
- dup_ratio > 0.3 — много дублей узлов: снижайте fanout, применяйте sampling без возвращения/importance.
- edges_per_sec ↓ при стабильном loader — перегрузка модели (особенно GAT): уменьшить heads/hidden, сократить слои.
Дашборды и логирование: https://cloudcompute.ru/solutions/monitoring-logging/, https://cloudcompute.ru/solutions/llm-inference/observability/
Экономика и формулы
Обозначения: f_l — fanout слоя l, B — размер батча (узлов‑семян), L — число слоёв, Eps — edges/sec, N — число узлов в графе, U — целевая загрузка GPU, c_gpu — цена/час.
- Сколько узлов/рёбер в батче (оценка):
Nodes_per_batch ≈ B × (1 + f₁ + f₁·f₂ + … + ∏_{i=1}^L f_i)
Edges_per_batch ≈ B × (f₁ + f₁·f₂ + … + ∏_{i=1}^L f_i) - Память под фичи в батче:
Mem_feats ≈ Nodes_per_batch × dim × bytes_per_comp (добавьте промежуточные тензоры и граф‑структуры). - Время эпохи:
T_epoch ≈ (Total_edges_visited / Eps); где Total_edges_visited ≈ (|Seeds|/B) × Edges_per_batch. - Стоимость эпохи:
Cost_epoch ≈ c_gpu × T_epoch / U. - Офлайн инференс:
T_infer ≈ N / nodes_per_sec, Cost_infer ≈ c_gpu × T_infer / U.
Планирование бюджета и компромиссов — см. https://cloudcompute.ru/solutions/cost-planner/, https://cloudcompute.ru/solutions/throughput-vs-latency/
Безопасность/политики
- PII/идентификаторы: храните хэш‑ID; маскируйте чувствительные атрибуты; разграничивайте доступ к узлам/рёбрам по тенантам.
- Ретеншн: TTL для временных подграфов/эмбеддингов/чекпоинтов; аудит выгрузок.
- Изоляция: пулы GPU для тренинга (Interruptible) и сервинга (On‑Demand); отдельные бакеты для графа и эмбеддингов.
- Экспорт моделей/индексов: фиксируйте версии и схемы, журналируйте операции экспорта.
Подробнее: https://cloudcompute.ru/solutions/security/, https://cloudcompute.ru/solutions/storage-data/
Траблшутинг
Симптом | Возможная причина | Решение |
CUDA OOM при обучении | Завышенный fanout/batch_size, high‑degree узлы | Уменьшить fanout/батч, ограничить degree cap, включить AMP, вынести «холодные» фичи в pinned‑host |
GPU простаивает | Медленный sampler/I/O | Увеличить prefetch/num_workers, UVA/zero‑copy, хранить CSR/фичи на NVMe, прогрев кэша |
Взрыв памяти в GAT | Много «голов» и большой hidden | Снизить heads/hidden, уменьшить слои, перейти на GraphSAGE |
Качество не растёт | Пересемплирование лёгких соседей | Importance‑sampling, баланс классов/негативов, регуляризация/Dropout |
Переносимая инстанс‑утечка | Дубликаты и пересечение батчей | Dedup узлов в батче, контроль dup_ratio, sampling без возвращения |
Плохая онлайн‑скорость | Тяжёлый GAT на сервинге | Предрассчитывать эмбеддинги офлайн; онлайн — локальный k‑hop GraphSAGE |
Дрифт эмбеддингов | Изменился граф/каталог | Регулярный перерасчёт, канареечный индекс, мониторинг метрик качества |
Нестабильная утилизация | Конкуренция задач на GPU | Ограничить конкурентность, разнести тренинг/инференс по пулам GPU |
См. также: https://cloudcompute.ru/solutions/interruptible-patterns/, https://cloudcompute.ru/solutions/performance-tuning/
Как запустить в cloudcompute.ru
- Откройте Шаблоны запусков: https://cloudcompute.ru/solutions/templates/ и выберите GNN (Train + Infer) или GNN Serving + ANN.
- Выберите профиль GPU: 24/48/80 ГБ по размеру графа, dim, типу модели (GraphSAGE/GAT) и SLA.
- Подключите диски: /nvme/graph (узлы/рёбра/фичи), /nvme/ckpt, /nvme/emb, /nvme/index.
- Задайте параметры пайплайна по config.yaml (fanout, degree cap, batch, precision, задача).
- Для продакшна: пулы Interruptible (обучение/офлайн‑эмбеды) и On‑Demand (retrieval), автоскейл по U/queue, дашборды и алерты.
Дополнительно:
https://cloudcompute.ru/solutions/triton-inference-server/ — сервинг моделей/эмбеддингов.
https://cloudcompute.ru/solutions/recsys/ — retrieval→ranking стек.
https://cloudcompute.ru/solutions/rapids/ и https://cloudcompute.ru/solutions/spark-rapids/ — GPU‑ETL перед графом.
https://cloudcompute.ru/solutions/multi-gpu/ — распределёнка и NCCL.
https://cloudcompute.ru/solutions/performance-tuning/ — низкоуровневый тюнинг.
https://cloudcompute.ru/solutions/cost-planner/ — планирование бюджета.
Чек‑лист перед продом
- Достигнуты целевые edges_per_sec/nodes_per_sec и step_time p95.
- Подобраны fanout/degree_cap/batch_size под HBM и стабильный p95.
- AMP (FP16/BF16) включён; UVA/pinned‑pool настроены; кэш горячих узлов/фичей реализован.
- Отработан офлайн‑инференс и сборка ANN‑индекса; версионирование эмбеддингов.
- Дашборды/алерты: loader_time, edges_per_sec, dup_ratio, HBM/pinned/NVMe, качество (ROC‑AUC/Hits@K).
- Политики PII/ретеншна/экспорта внедрены; разнесены пулы On‑Demand/Interruptible.
- Канареечный релиз индекса/модели и план отката готовы; нагрузочный прогон ≥ 30 мин.
Навигация
- Хаб «Решения»: https://cloudcompute.ru/solutions/
- Рекомендательные системы: https://cloudcompute.ru/solutions/recsys/
- RAPIDS (cuDF/cuML): https://cloudcompute.ru/solutions/rapids/
- Spark RAPIDS: https://cloudcompute.ru/solutions/spark-rapids/
- Хранилища и данные: https://cloudcompute.ru/solutions/storage-data/
- Производительность и тюнинг: https://cloudcompute.ru/solutions/performance-tuning/
- Throughput vs Latency: https://cloudcompute.ru/solutions/throughput-vs-latency/
- Multi‑GPU: https://cloudcompute.ru/solutions/multi-gpu/
- Планирование стоимости: https://cloudcompute.ru/solutions/cost-planner/
- Мониторинг и логи: 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/