Решения

FP8 и BF16: выбор формата вычислений

Задача страницы. Помочь выбрать формат чисел (FP8/BF16/FP16/FP32) под обучение и инференс на GPU в https://cloudcompute.ru: когда и как включать смешанную точность, где уместен FP8, как контролировать стабильность и экономику без потери качества.

TL;DR

  • BF16 — дефолт для обучения: широкая поддержка, стабильные градиенты, минимальная потеря качества. FP16 — только при явной необходимости и грамотной настройке loss scaling.
  • FP8 — для ускорения матмулов/MLP/Attention: хранение активаций/весов в FP8 с аккумулированием в BF16/FP32 даёт прирост throughput и экономию VRAM. Требует калибрации amax и исключений (LayerNorm/Softmax в BF16).
  • Гибрид: MHA/MLP в FP8, всё чувствительное (нормировки, редукции, софтмакс, логиты, целевые функции) — в BF16.
  • Инференс: FP8 + INT8‑кэш/KV даёт лучшую цену за токен; TTFT (time‑to‑first‑token) и стабильность — за счёт BF16 в узких местах.
  • Наблюдаемость — обязательна: NaN/Inf, amax‑гистограммы, p50/p95 латентности; см. https://cloudcompute.ru/solutions/monitoring-logging/ и https://cloudcompute.ru/solutions/llm-inference/observability/.
  • Экономика: считайте Cost_per_1M_tokens, Cost_per_epoch, Cost_per_image от c_gpu, U (целевая загрузка) и TPS/FPS; см. https://cloudcompute.ru/solutions/cost-planner/ и https://cloudcompute.ru/solutions/throughput-vs-latency/.
  • Мульти‑GPU: FSDP/ZeRO с BF16 — база; FP8 в матрицах — надстройка (см. https://cloudcompute.ru/solutions/multi-gpu/).
  • Режимы: On‑Demand — стабильность/латентность важнее, больше BF16; Interruptible — массовая генерация, агрессивнее FP8 (чанки ≤ 120 сек), см. https://cloudcompute.ru/solutions/interruptible-patterns/.

Сценарии

  • Обучение больших трансформеров: BF16 (веса/активации) + выборочно FP8 в GEMM/Attention; оптимайзер/аккумуляторы — FP32.
  • LoRA/QLoRA‑дообучение: хранение адаптеров в 16‑бит, вычисления в BF16, иногда FP8 на форварде для MLP.
  • Инференс LLM: префилл/декод в FP8 (актив/веса) с аккумулированием в BF16; LayerNorm/Softmax/KV‑редукции — BF16; KV‑кэш INT8/FP8.
  • CV (детекция/сегментация/диффузия): обучение — BF16; инференс — FP16/BF16, для пост‑процессинга/детализации BF16; иногда FP8 на backbone.
  • Гео/CV‑тайлы/видеоаналитика: FP8 на feature‑экстракции, BF16 в декодерах/постпроцессе; NVDEC/NVENC — отдельно (см. https://cloudcompute.ru/solutions/performance-tuning/).
  • HPC‑фрагменты в ML‑пайплайн: редукции/статистика — BF16/FP32, матмулы — FP8.

Архитектуры/пайплайны (ASCII)

A) Обучение (BF16 + выборочно FP8)

				
					Даталоадер → Аугментации → [Autocast BF16]
                    → (Attention/MLP: FP8 GEMM, Accum BF16)
                    → Нормировки/Softmax: BF16
                    → Потери: FP32
                    → Backward: Grad Scale / Clip
                    → Оптимайзер: FP32 master weights
                    → FSDP/ZeRO (шардинг, чекпоинт)
Мониторинг: loss, NaN/Inf, amax, step_time(p50/p95), gpu_util/hbm


				
			

B) Инференс (FP8 приоритетно, BF16 в «хрупких» местах)

				
					Запрос → Токенизация → Префилл (FP8 GEMM, Accum BF16)
      → KV-кэш (INT8/FP8) → Декод (loop)
      → Нормировки/Softmax(logits): BF16
      → Постпроцессинг/стриминг SSE/WebSocket
Метрики: TTFT, TPS(tok/s), p95 latency, drop, gpu_util/hbm
				
			

Профили GPU / VRAM / ориентиры скорости

Профиль

Видеопамять

Рекоменд. формат обучения

Рекоменд. формат инференса

Ориентиры скорости*

Параллельные задачи/GPU

Режим

24 ГБ (Compact)

24 ГБ

BF16 (всё), FP8 точечно в MLP малых моделей

FP8 префилл/декод, BF16 LN/Softmax

+1.2–1.6× к FP16 при FP8‑GEMM

1–2

On‑Demand/Interruptible

48 ГБ (Balanced)

48 ГБ

BF16 база, FP8 на Attention/MLP средних моделей

FP8 на матрицах, BF16 на «хрупких»

+1.5–2.0× к FP16, −30–40% VRAM

2–3

Оба

80 ГБ (HQ)

80 ГБ

BF16 (полномасштабные батчи), FP8 выборочно на 30B+

FP8 повсеместно + INT8 KV

+1.8–2.5× к FP16, −35–50% VRAM

3–4

Оба

*Ориентиры носят инженерный характер и зависят от модели/секвенции/батча.

Конфиги и скелеты

1) Общий YAML‑флаг для формата вычислений

				
					compute:
  dtype: "bf16"          # bf16 | fp16 | fp8
  accum_dtype: "fp32"    # для оптимайзера/редукций
  fp8:
    enabled: true
    format: "e4m3"       # e4m3 | e5m2
    amax_calibration_steps: 200
    exclude_ops: ["layernorm", "softmax", "logits"]
  grad:
    scaling: "dynamic"   # dynamic | static
    clip_norm: 1.0
  kv_cache:
    dtype: "int8"        # int8 | fp8 | bf16


				
			

2) PyTorch: BF16 обучение (стабильная база)

				
					import torch
from torch import nn, optim

model = nn.TransformerEncoderLayer(d_model=1024, nhead=16, batch_first=True).cuda()
optimizer = optim.AdamW(model.parameters(), lr=2e-4)

scaler = torch.cuda.amp.GradScaler(enabled=False)  # BF16 не требует loss scaling
model.train()
for step, (x, y) in enumerate(loader):
    x, y = x.cuda(non_blocking=True), y.cuda(non_blocking=True)
    with torch.autocast(device_type="cuda", dtype=torch.bfloat16):
        logits = model(x)
        loss = nn.functional.cross_entropy(logits.view(-1, logits.size(-1)), y.view(-1))
    optimizer.zero_grad(set_to_none=True)
    loss.backward()
    torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
    optimizer.step()


				
			

3) PyTorch: включение FP8 там, где поддерживается

				
					import torch
from torch import nn

# Проверяем поддержку float8 dtypes
has_fp8 = hasattr(torch, "float8_e4m3fn") and hasattr(torch, "float8_e5m2")
FP8_W = getattr(torch, "float8_e4m3fn", None)  # веса/активации
ACCUM = torch.bfloat16

class MlpBlock(nn.Module):
    def __init__(self, d):
        super().__init__()
        self.fc1 = nn.Linear(d, 4*d, bias=False, dtype=ACCUM)
        self.fc2 = nn.Linear(4*d, d, bias=False, dtype=ACCUM)
        self.act = nn.GELU()

    def forward(self, x):
        if has_fp8:
            # Пример: хранение активаций в FP8, вычисления — с аккумулированием в BF16
            x_fp8 = x.to(FP8_W)                     # квантизация входа
            h = (self.fc1(x_fp8.to(ACCUM)))         # де-квантизация → GEMM (ACCUM)
        else:
            h = self.fc1(x)
        h = self.act(h)
        if has_fp8:
            h_fp8 = h.to(FP8_W)
            y = self.fc2(h_fp8.to(ACCUM))
        else:
            y = self.fc2(h)
        return y

				
			

Замечание: в проде используйте реализованные FP8‑слои вашего фреймворка/библиотек. Общий принцип сохраняется: хранение FP8, вычисление/аккумуляция — BF16/FP32, исключая чувствительные операции.

4) Инференс: гибрид FP8/BF16 и стриминг SSE

				
					import torch
from fastapi import FastAPI
from fastapi.responses import StreamingResponse

app = FastAPI()
model.eval()

def generate(prompt_ids, max_new_tokens=128):
    with torch.no_grad(), torch.autocast("cuda", dtype=torch.bfloat16):
        # Префилл в FP8 (если доступно)
        # ... подготовка KV-кэша (int8/fp8)
        for _ in range(max_new_tokens):
            logits = model(prompt_ids)  # внутри: FP8 GEMM + BF16 LN/Softmax
            next_id = torch.argmax(logits[:, -1], dim=-1, keepdim=True)
            yield int(next_id)
            prompt_ids = torch.cat([prompt_ids, next_id], dim=1)

@app.get("/events")
def sse(prompt: str):
    token_ids = tokenize(prompt).cuda()
    def stream():
        for tok in generate(token_ids):
            yield f"data: {tok}\n\n"
    return StreamingResponse(stream(), media_type="text/event-stream")


				
			

Наблюдаемость, метрики, алерты

См. https://cloudcompute.ru/solutions/monitoring-logging/ и https://cloudcompute.ru/solutions/llm-inference/observability/.

Обучение

  • train_step_time_ms (p50/p95), throughput_tokens_s, data_wait_ms
  • loss, grad_norm, nan_inf_count, overflow_steps
  • amax_histogram (по слоям FP8), activation_range_saturation_pct
  • GPU: gpu_util_pct, gpu_mem_used_gb (HBM), sm_efficiency_pct, pcie_tx_mb_s

Инференс

  • ttft_ms (p50/p95), tps_tok_s, latency_ms (p50/p95), queue_depth
  • kv_cache_bytes, kv_dtype, cache_hit_ratio
  • Качество: целевые метрики (перплексия/accuracy/PSNR и т.п.) на контрольном наборе

Алерты

  • nan_inf_count > 0 → немедленно выключить FP8 на соответствующих слоях, включить проверки диапазона.
  • activation_range_saturation_pct > 1% → увеличить динамику квантизации (ротация amax).
  • ttft_ms(p95) вне SLO → вернуть часть путей в BF16, уменьшить батч; см. https://cloudcompute.ru/solutions/throughput-vs-latency/.
  • gpu_mem_used_gb / vram > 0.9 → уменьшить длину контекста/батч или KV‑dtype.

Экономика и формулы

Обозначения: c_gpu — цена GPU/час; U — целевая загрузка; N_gpu — число GPU; TPS — токены/сек на GPU; t_h — часы; S — ускорение относительно FP16; M_mem — VRAM, R_mem — экономия памяти.

Инференс (цена за 1k/1M токенов)

EffCostPerHour = (c_gpu * N_gpu) / U

TokensPerHour = TPS * 3600 * N_gpu

Cost_per_1000_tok = EffCostPerHour / (TokensPerHour / 1000)

Cost_per_1M_tok   = EffCostPerHour / (TokensPerHour / 1_000_000)

Влияние FP8

TPS_fp8 ≈ TPS_fp16 * S

VRAM_fp8 ≈ M_mem * (1 — R_mem)

Обучение (цена эпохи)

Tokens_epoch = N_samples * seq_len

Train_tokens_per_hour = TPS_train * 3600 * N_gpu

Cost_per_epoch = EffCostPerHour * (Tokens_epoch / Train_tokens_per_hour)

KV‑кэш

KV_bytes ≈ N_layers * 2 * heads * head_dim * seq_len * dtype_bytes

→ При FP8/INT8 dtype_bytes снижаются, растёт вместимость контекста на ту же VRAM.

Планируйте параметры и профили на https://cloudcompute.ru/solutions/cost-planner/.

Безопасность/политики

  • Детерминизм и воспроизводимость: фиксируйте версии образов/драйверов/библиотек, seed; логируйте dtype‑решения в чекпоинтах.
  • Защита данных: контроль доступа к датасетам/валидационным сетам; разделение тренировочных/продовых секретов (см. https://cloudcompute.ru/solutions/security/).
  • PII: если обучаете на пользовательских данных — маскирование, ретеншн; отдельные среды для приватных наборов.
  • Политики прерывания: для Interruptible — чекпоинты ≤ 120 сек и идемпотентные задачи (см. https://cloudcompute.ru/solutions/interruptible-patterns/).

Траблшутинг

Симптом

Причина

Решение

NaN/Inf в лоссе на FP8

Пересатурация диапазона, плохая калибровка amax

Временно переведите слой в BF16, перезапустите калибровку на 100–200 шагов, включите range‑статистику.

Качество просело на валидации

FP8 в чувствительных узлах (LN/Softmax/Logits)

Исключите эти операции из FP8; оставьте BF16/FP32.

TTFT вырос, TPS упал

Микробатчинги/очереди перегружены

Уменьшите batch/beam, увеличьте параллелизм по запросам; проверьте PCIe/NVLink.

OOM при длинных контекстах

KV‑кэш в BF16/FP16

Переключите KV‑dtype на INT8/FP8, уменьшите seq_len, используйте «paged‑KV».

Тренировка флапает (нестабильна)

FP16 с недостаточным loss scaling

Перейдите на BF16; включите dynamic scaling или снизьте LR.

Перфоманc не растёт на FP8

Узкое место не в GEMM

Профилируйте: возможно, софтмакс/редукции/даталоадер — тюнинг I/O и редукций.

Разные результаты между нодами

Несовпадение dtype и seed

Зафиксируйте конфиг, проверьте автокаст и версии пакетов.

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

  1. Выберите шаблон (Docker/SSH/Jupyter) на https://cloudcompute.ru/solutions/templates/.
  2. Определите режим: On‑Demand (интерактивный инференс/демо) или Interruptible (массовая генерация/обучение чанками). См. https://cloudcompute.ru/solutions/interruptible-patterns/.
  3. Подберите профиль GPU: 24 ГБ (Compact), 48 ГБ (Balanced), 80 ГБ (HQ). См. таблицу профилей выше.
  4. В образ/конфиг добавьте dtype‑флаги (BF16 база; FP8 — точечно, с калибровкой).
  5. Настройте наблюдаемость: метрики качества/латентности/amax, GPU util/HBM — см. https://cloudcompute.ru/solutions/monitoring-logging/ и https://cloudcompute.ru/solutions/llm-inference/observability/.
  6. Для мульти‑обучения включите FSDP/ZeRO — см. https://cloudcompute.ru/solutions/multi-gpu/.
  7. Сбалансируйте throughput↔latency под вашу SLO — см. https://cloudcompute.ru/solutions/throughput-vs-latency/ и https://cloudcompute.ru/solutions/performance-tuning/.
  8. Проверьте секьюрити/ретеншн конфигов/датасетов — https://cloudcompute.ru/solutions/security/.

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

  • Обучение в BF16, исключения (LN/Softmax/Logits) — BF16/FP32, FP8 — только на матрицах после калибровки.
  • amax‑калибровка выполнена; activation_range_saturation_pct ≤ 1%.
  • На инференсе соблюдены SLO: ttft_ms(p95), tps_tok_s, latency_ms(p95).
  • KV‑кэш в INT8/FP8 при длинных контекстах; OOM не воспроизводится.
  • GPU util 60–85%, запас VRAM ≥ 20%; отсутствуют переполнения очередей I/O.
  • Метрики/алерты заведены; NaN/Inf ловятся и останавливают пайплайн.
  • Экономика подтверждена: Cost_per_1M_tokens/Cost_per_epoch через https://cloudcompute.ru/solutions/cost-planner/.
  • Конфиги dtype/версии библиотек зафиксированы в CI/CD (см. https://cloudcompute.ru/solutions/containers-ci-cd/).
  • Политики безопасности/ретеншна — применены (https://cloudcompute.ru/solutions/security/).

Навигация