Решения
Смешанная точность в обучении LLM: BF16/FP16/FP8
Цель. Помочь выбрать формат вычислений под вашу задачу и железо, правильно включить AMP/автокаст, избежать числовых проблем и получить прирост скорости/экономию VRAM без потери качества.
TL;DR:
- На Ampere/Hopper берите BF16 как дефолт — стабильно, без loss scaling, быстрая математика на Tensor Cores.
- FP16 всё ещё уместен на старых картах и в узких местах памяти (с GradScaler).
- FP8 — новый формат Hopper: даёт максимум пропускной способности через Transformer Engine, но требует аккуратной калибрации/валидации; рекомендован продвинутым пользователям.
- Плюс к этому включайте TF32 (Ampere+) для операций, где оно помогает «бесплатно».
Что такое смешанная точность и зачем она LLM
Смешанная точность (mixed precision) исполняет часть операций в «лёгком» формате (FP16/BF16/FP8), а критичные суммирования/редукции — в FP32. Это снижает затраты на память и ускоряет обучение, при этом сохранность качества обеспечивается автоматическим выбором «где какой формат». В PyTorch это делается через torch.autocast и (для FP16) torch.amp.GradScaler.
Короткий выбор формата
- BF16 (bfloat16). Такой же диапазон значений, как у FP32, но укороченная мантисса — поэтому как правило не нужен GradScaler; даёт стабильность в обучении трансформеров. На Ampere/Hopper ускоряется Tensor Cores.
- FP16. Меньше памяти, выше риск «под/переполнения» градиентов — используется вместе с GradScaler (динамический loss scaling).
- FP8. Введён на H100 (Hopper): ещё больше пропускной способности/экономии памяти, включается через NVIDIA Transformer Engine (TE) и соответствующие бэкенды внимания (cuDNN/FlashAttention‑3). Требует более тщательной валидации качества.
- TF32. Режим Ampere‑Tensor Cores для FP32‑операций; даёт ускорение «без правок кода» и может быть включён через флаг в PyTorch/HF‑Trainer.

Аппаратная матрица (на что опираться)

- Ampere (A100/RTX 30/L40): Tensor Cores для FP16, BF16, TF32. BF16/FP16 работают на схожей скорости на Tensor Cores.
- Hopper (H100): всё вышеперечисленное + FP8 (через Transformer Engine).
Мини‑рецепты: как включить в вашем тренинге
A) BF16 в PyTorch (без GradScaler)
model.train()
for batch in loader:
with torch.autocast(device_type="cuda", dtype=torch.bfloat16):
loss = model(**batch).loss
loss.backward()
optimizer.step(); optimizer.zero_grad(set_to_none=True)
autocast выбирает формат операций автоматически; BF16 обычно не требует масштабирования градиента.
B) FP16 + GradScaler
scaler = torch.amp.GradScaler(enabled=True)
for batch in loader:
with torch.autocast(device_type="cuda", dtype=torch.float16):
loss = model(**batch).loss
scaler.scale(loss).backward()
scaler.step(optimizer); scaler.update()
optimizer.zero_grad(set_to_none=True)
GradScaler предотвращает «занижение» градиентов в FP16 и повышает устойчивость.
C) Включить TF32 (ускорение «поверх»)
torch.backends.cuda.matmul.allow_tf32 = True
Либо через аргументы Trainer в HF: TrainingArguments(tf32=True).
D) FP8 через Transformer Engine (H100)
Высокоуровневый путь — заменить стандартные слои на модули TE или активировать автосмешивание TE, чтобы матмульты/внимание шли в FP8 c нужными калибровками. Смотрите «FP8 primer» и примеры TE.
Производительность и экономия памяти
- BF16/FP16 ускоряют математику на Tensor Cores и уменьшают объём активаций, что часто напрямую увеличивает пропускную способность шагов. На Ampere это «базовый» путь ускорения DL‑тренинга.
- FP8 (H100) повышает throughput внимания/матмультов ещё заметнее; например, в FlashAttention‑3 на Hopper заявлено ~1.5–2.0× ускорение против предыдущего поколения (и вплоть до ~PFLOPs/s в FP8).


Числовая стабильность и типичные настройки
- FP16: включайте GradScaler, grad_clip, проверяйте падение лосса без «ступенек» — признак корректной шкалы.
- BF16: обычно «ставится и работает», но всё равно держите grad_clip и мониторинг NaN/Inf.
- FP8: используйте рекомендуемые бэкенды внимания (cuDNN attention с FP8 или FlashAttention‑3 на H100) и следуйте гайдам TE по диапазонам/калибровке. Не переходите на FP8 без сравнения качества на вашем вал‑корпусе.
LLM‑специфика: где прячется выигрыш
- Attention‑ядра. Современные реализации (cuDNN attention / FlashAttention‑2/3) дают основной прирост; они работают в BF16/FP16, а на H100 — и в FP8.
- KV‑кэш и длина контекста. Память и время растут с контекстом; смешанная точность снижает объём активаций и требования к HBM, но контролируйте стабильность при длинных L (наблюдайте перплексию/регрессии).
- Комбинации с FSDP/ZeRO. Смешанная точность хорошо сочетается с шардированием параметров/стейтов; выбирайте BF16 как «базу», добавляйте grad‑checkpointing. См. страницу по FSDP/DeepSpeed.
Траблшутинг
- NaN/Inf в градиентах (FP16). Понизить lr, включить/усилить GradScaler, добавить grad_clip, проверить датасет на экстремальные значения.
- Граф «зубцами» / неравномерная скорость. Убедитесь, что «тяжёлые» операции действительно попадают под autocast; проверьте, что каст не выключен в кастомных слоях.
- Деградация качества (FP8). Перекалибровать/сузить области FP8, откатиться на BF16 для чувствительных слоёв внимания/MLP; сравнить валидацию до/после.
Навигация по смежным страницам
Оптимизаторы и память: /solutions/llm-training/optimizers/, /solutions/llm-training/memory-opt/
Масштабирование: /solutions/llm-training/fsdp-deepspeed/, /solutions/multi-gpu/
Данные/I‑O/чекпоинтинг: /solutions/llm-training/distributed-io/, /solutions/llm-training/checkpointing/