Решения

Эмбеддинги на GPU: батч‑планирование и хранение

Задача страницы. Дать практический рецепт вычисления эмбеддингов на облачных GPU: выбор модели и формата, батч‑планирование под VRAM, оффлайн‑ингест и онлайн‑эмбеддинг для запросов, хранение/квантизация векторных представлений и метрики производительности/стоимости.

TL;DR

  • Два основных контура: оффлайн‑ингест (массовые эмбеддинги документов) и онлайн‑эмбеддинг (быстрые векторы запросов).
  • Ускорение на GPU даёт максимум выигрыша при крупных батчах и политике fp16/bf16 с аккуратным планированием VRAM.
  • Храните векторы в fp16 или квантуйте до int8/PQ, если нужен огромный объём и быстрый поиск (см. /solutions/rag/vector-db/).
  • Ключевые метрики: T_embed (ms/запрос), QPS, recall после компрессии, цена за 1M эмбеддингов.

Связанные разделы:
/solutions/rag//solutions/rag/vector-db//solutions/rag/evaluation//solutions/llm-inference/observability//solutions/llm-inference/costs//solutions/cost-planner//solutions/monitoring-logging/

Модель эмбеддингов: как выбирать

Критерии:

  • Языки/домены: рус/англ, код/юридический/медицинский.
  • Размер и латентность: чем больше dim и модель, тем выше качество, но выше T_embed.
  • Совместимость с индексом: cosine/IP‑метрика, нормировка L2.
  • Стоимость: fp16 на одной GPU обычно даёт лучший баланс цена/скорость.

Практика:

  • Для онлайн‑чатов и RAG — компактные энкодеры (низкая латентность), dim 384–1024.
  • Для сложных доменов — средние/крупные энкодеры + rerank по необходимости (см. /solutions/rag/vector-db/).

Предобработка текста и чанкование

  • Очистка HTML/PDF, нормализация пробелов, стандартные кавычки/дефисы.
  • Чанкование: 256–512 токенов (чат/QA), 768–1024 (аналитика), overlap 10–20%.
  • Метаданные: doc_id, section, lang, timestamp, tags.
  • Дедупликация шинглами/абзацами.

Подробнее: /solutions/rag/.

Батч‑планирование под VRAM

Прикидка памяти (упрощённо):

				
					VRAM ≈ B × (SeqLen × Hidden × bytes_per_elem × k_act) + Overhead
# B — batch size; k_act ~ 2–3 для активаций/временных буферов
# fp16/bf16: 2 байта/элемент; fp32: 4 байта/элемент

				
			

Правила:

  • Используйте fp16/bf16, torch.no_grad() и автокаст.
  • Включайте pinned memory и передачу non_blocking=True.
  • Подберите Batch Size эмпирически по «колену» p95 и утилизации.
  • Для коротких последовательностей выше throughput даёт укрупнение батча, для длинных — умное SeqLen‑ограничение.

Пример (PyTorch, mean‑pooling):

				
					import torch, numpy as np
from transformers import AutoTokenizer, AutoModel

device = torch.device("cuda:0")
tok   = AutoTokenizer.from_pretrained("./embedder")
model = AutoModel.from_pretrained("./embedder").to(device).eval()

@torch.inference_mode()
def embed_texts(texts, max_length=512, batch_size=256, dtype=torch.bfloat16):
    outs = []
    with torch.autocast("cuda", dtype=dtype):
        for i in range(0, len(texts), batch_size):
            batch = texts[i:i+batch_size]
            enc = tok(batch, padding=True, truncation=True,
                      max_length=max_length, return_tensors="pt")
            enc = {k: v.to(device, non_blocking=True) for k,v in enc.items()}
            h = model(**enc).last_hidden_state    # [B, T, H]
            mask = enc["attention_mask"].unsqueeze(-1)  # [B, T, 1]
            emb = (h * mask).sum(dim=1) / mask.sum(dim=1).clamp_min(1)  # mean-pool
            emb = torch.nn.functional.normalize(emb, p=2, dim=1)        # для cosine=IP
            outs.append(emb.detach().cpu())
    return torch.cat(outs, dim=0).numpy().astype(np.float16)  # хранить fp16

				
			

Онлайн‑эмбеддинг запросов

Цель: p95 T_embed_q ≤ 20–40 мс при умеренной длине (≤ 256 токенов).
Практика:

  • Держите модель “hot” в VRAM, прогрейте токенайзер.
  • Фиксируйте/урезайте max_length для запросов.
  • Считайте пачками: объединяйте параллельные запросы по 8–64 (микро‑батч) в очереди.
  • Отдельный пул для длинных запросов (см. /solutions/llm-inference/multi-model/).
  • Метрики и алерты: /solutions/llm-inference/observability/.

Мульти‑GPU, MIG и шардирование

  • Data‑параллель для оффлайн‑ингеста: разрезайте датасет по узлам/картам, объединяйте результаты.
  • MIG: выделяйте маленькие слайсы для онлайн‑эмбеддинга (низкая латентность), крупные — для оффлайн‑батчей. См. /solutions/mig/.
  • Шардирование по tenant/doc_id для параллельного расчёта и обновлений.

Хранение и форматы

Размер (прикидка):

Mem ≈ N × dim × bytes_per_elem

# Пример: 2M × 768 × 2 байта(fp16) ≈ ~2.95 ГБ (без оверхеда индекса)

Рекомендации:

  • fp16 как базовый формат хранения; для экономии — int8/PQ (см. ниже).
  • Храните рядом метаданные (Parquet/JSONL): doc_id, chunk_id, offset, lang, ts.
  • Версионируйте «корпус@версия, модель@версия, предобработка@хэш».
  • Держите «горячие» коллекции на NVMe, индексы — в VRAM/памяти сервера поиска.
  • Интеграция с поиском: /solutions/rag/vector-db/.

Квантизация эмбеддингов: int8 и PQ

Зачем: снизить хранение и ускорить поиск на больших N.

A) Простая row‑wise int8 (симметричная)

  • Один масштаб на вектор (или per‑dim).
  • Храните scale и zero_point (для симметричной — zero_point=0).
				
					import numpy as np

def quantize_int8_rowwise(x: np.ndarray):
    # x: [N, dim] float16/32, L2-нормализован (желательно)
    norms = np.max(np.abs(x), axis=1, keepdims=True) + 1e-8
    scale = norms / 127.0
    q = np.clip(np.round(x / scale), -127, 127).astype(np.int8)
    return q, scale.astype(np.float32)

def dequantize_int8_rowwise(q: np.ndarray, scale: np.ndarray):
    return (q.astype(np.float32) * scale).astype(np.float32)

				
			
  • Плюсы: простота, ×2–×4 экономия; Минусы: небольшой спад качества косинусной близости.
  • Для сравнения cosine/IP лучше хранить нормированные векторы и пересчитывать норму после де‑кванта.

B) Product Quantization (PQ)

  • Делит вектор на m субвекторов и кодирует каждый кодом bits (4/6/8).
  • Существенно сокращает память (см. /solutions/rag/vector-db/), небольшой спад recall → компенсируйте nprobe/rerank.

Качество эмбеддингов

  • Нормируйте L2, используйте cosine как IP c нормировкой.
  • Проверяйте двуязычность/мультиязычность вашего энкодера.
  • Оффлайн‑оценка: Recall@K/MRR на валид‑запросах; онлайновая — CSAT/deflection.

Подробнее: /solutions/rag/evaluation/.

Ингест‑пайплайн (офлайн): от текстов к индексу

[Scrape/Docs] → Clean → Chunk → Embed (GPU, batched) → Store (fp16/int8) → Build Index (GPU) → Persist

Псевдокод:

				
					def ingest(docs, embedder, vecdb, batch=2048):
    # 1) Clean & chunk
    chunks = list(generate_chunks(docs, size=512, overlap=64))  # см. /solutions/rag/
    # 2) Embed on GPU
    vecs = embedder(chunks, batch_size=batch, max_length=512)
    # 3) (Опц.) Quantize & persist
    # q, scale = quantize_int8_rowwise(vecs)
    save_vectors(vecs, meta=chunks.meta)  # fp16 обычно достаточно
    # 4) Build index on GPU
    vecdb.build(vecs, kind="IVF-PQ", nlist=4096, m=32, bits=8)
    vecdb.persist()

				
			

Детали индексов и параметров: /solutions/rag/vector-db/.

Онлайн‑поиск (RAG): latency‑бюджет

Разложение задержки:

T_total ≈ T_embed_q + T_search + T_rerank + T_LLM

  • Минимизируйте T_embed_q батчированием запросов и фиксированным max_length.
  • Держите индексы на GPU, T_search ≤ 50–150 мс (p95), смотрите /solutions/rag/vector-db/.
  • Стримьте ответ LLM (см. /solutions/llm-inference/streaming/).

Наблюдаемость и стоимость

Метрики:

  • embed_latency_ms p50/p95, embed_qps, размер батча, seq_len.
  • GPU: util/HBM, PCIe/NVLink, загрузка токенизатора (CPU).
  • Ингест: время на 1M токенов/доков; онлайн: T_embed_q и ошибки.

Экономика (оценка цены за 1M эмбеддингов):

Embeddings_per_hour ≈ QPS × 3600

Cost_per_1M_embed  ≈ (GPU_hour_price × Num_GPU) / (Embeddings_per_hour / 1e6)

Для токен‑экономики и сравнения со стоимостью LLM‑ответов см. /solutions/llm-inference/costs/ и планировщик /solutions/cost-planner/.

Безопасность и приватность

  • Маскируйте PII до эмбеддинга, храните маппинг токенов‑замен отдельно.
  • Логируйте метаданные событий (без сырого текста), см. /solutions/llm-inference/guardrails/ и /solutions/security/.

Как это запустить в cloudcompute.ru

  • Шаблоны в /solutions/templates/:
    “Embeddings‑Batcher”: оффлайн‑ингест с fp16, pin‑memory, профилем VRAM;
    “Embeddings‑API”: онлайн‑эмбеддинг с микро‑батчами, фикс. max_length, метрики и алерты;
    “RAG‑VectorDB (GPU)”: сборка индекса IVF‑Flat/IVF‑PQ.
  • Планирование цены/режимов: /solutions/cost-planner/.
  • Наблюдаемость: /solutions/llm-inference/observability/, логи — /solutions/monitoring-logging/.

Чек‑лист перед продом

  • Выбрана модель эмбеддингов (языки/домен/latency).
  • Настроены батчи и dtype (fp16/bf16), подтверждён VRAM‑бюджет.
  • Определены размеры чанков и метаданные; включён дедуп.
  • Решена схема хранения: fp16 или int8/PQ; зафиксированы версии.
  • Собраны индексы и подтверждён recall/latency (валидация).
  • Включены метрики/алерты; рассчитана цена за 1M эмбеддингов.
  • Настроены guardrails и маскирование PII.