English translation is not available yet. Showing Russian content.

Почему BF16 лучше FP16 для training?

Краткий тезис

BF16 (bfloat16) превосходит FP16 (float16) для обучения нейросетей благодаря более широкому динамическому диапазону (8 бит экспоненты против 5), что предотвращает переполнение градиентов (overflow) и уменьшает риск исчезновения (underflow). Однако BF16 имеет меньшую точность мантиссы (7 бит против 10), что может приводить к потере информации для очень малых градиентов. На практике оптимальным является смешанное обучение (precision precision precision training|mixed precision) с использованием BF16 для прямого и обратного проходов и FP32 для хранения weights|master weights|master weights, а при использовании FP16 обязательно применяется масштабирование градиентов (gradient scaling).


1. Числовые форматы с плавающей точкой: FP32, FP16, BF16

Все три формата представляют числа в виде: знак (1 бит) + экспонента (E бит) + мантисса (M бит). Значение вычисляется как:

(-1)^знак * 2^(экспонента - bias) * 1.мантисса
ФорматВсего битЭкспонента (E)Мантисса (M)BiasДиапазон (приблизительно)Машинный эпсилон
FP3232823127±1.18e-38 … ±3.4e38~1.19e-7
FP161651015±6.1e-5 … ±65504~9.77e-4
BF161687127±1.18e-38 … ±3.4e38~7.81e-3

Ключевое наблюдение BF16 использует столько же бит на экспоненту, сколько FP32 (8 бит), поэтому его динамический диапазон совпадает с FP32. FP16 же имеет всего 5 бит экспоненты, что резко сужает диапазон.


2. Почему динамический диапазон критичен для обучения

При обучении нейросетей градиенты могут варьироваться на много порядков:

  • Большие градиенты (например, на начальных слоях или при нестабильной оптимизации) могут превысить максимальное представимое число формата → overflow (становится inf или NaN).
  • Маленькие градиенты (например, в глубоких сетях или при насыщении активаций) могут стать меньше минимального положительного числа → underflow (обнуляются).

FP16 имеет максимальное значение всего 65504. Любой градиент больше этой величины превращается в inf, что разрушает обучение. Минимальное нормализованное число FP16 — 6.1e-5, поэтому очень малые градиенты (например, при обучении с низкой точностью или в хвостах распределения) обнуляются.

BF16 благодаря 8-битной экспоненте может представлять числа от ~1.18e-38 до ~3.4e38 — точно как FP32. Таким образом, overflow практически исключён, а underflow встречается реже.


3. Проблемы FP16: overflow и underflow на практике

Рассмотрим типичный сценарий обучения большой языковой модели (LLM). Градиенты на ранних итерациях могут быть большими из-за случайной инициализации. Если использовать FP16, значения градиентов >65504 приведут к NaN, и обучение остановится.

Даже при использовании масштабирования градиентов (gradient scaling) — умножения потерь на коэффициент перед обратным проходом — FP16 остаётся уязвимым к переполнению при резких скачках градиентов. Кроме того, масштабирование требует подбора коэффициента и дополнительных проверок (например, пропуск шага при обнаружении inf).

Пример кода (PyTorch с AMP для FP16):

scaler = torch.cuda.amp.GradScaler()
for data, target in dataloader:
    optimizer.zero_grad()
    with torch.cuda.amp.autocast(dtype=torch.float16):
        output = model(data)
        loss = loss_fn(output, target)
    scaler.scale(loss).backward()
    scaler.step(optimizer)
    scaler.update()

Для BF16 масштабирование обычно не требуется, так как диапазон покрывает все разумные значения градиентов.


4. Преимущества BF16: широкий диапазон без масштабирования

BF16 наследует диапазон FP32, поэтому:

  • Нет overflow для типичных градиентов (даже при batch size 1 или при обучении с большим learning rate).
  • Underflow случается реже, хотя для очень малых градиентов (например, в конце обучения) точность может быть недостаточной.
  • Не нужен GradScaler — упрощается код и уменьшается риск пропуска шагов.
  • Аппаратная поддержка: современные GPU (NVIDIA A100, H100, AMD MI250) и TPU имеют нативные блоки для BF16, что даёт прирост производительности.

5. Когда BF16 проигрывает: потеря точности для малых градиентов

Мантисса BF16 содержит всего 7 бит (против 10 у FP16 и 23 у FP32). Это означает, что машинный эпсилон (разница между 1 и следующим представимым числом) для BF16 составляет ~7.8e-3, тогда как для FP16 — ~9.8e-4.

Следствие если градиенты становятся очень маленькими (например, при тонкой настройке с низким learning rate или в задачах с высокой точностью), BF16 может округлить их до нуля или внести значительную ошибку. В таких случаях FP16 с масштабированием может сохранить больше информации.

Экспериментальные данные для большинства задач (BERT, GPT, ResNet) BF16 показывает качество, близкое к FP32, и часто превосходит FP16 без масштабирования. Однако для задач с очень малыми градиентами (например, обучение с шумом или некоторые GAN) FP16 с правильным scaling может быть лучше.


6. Смешанное обучение (Mixed Precision Training)

На практике редко используют чистый BF16 или FP16 для всех параметров. Стандартный подход:

  • Master weights хранятся в FP32 (для точности накопления).
  • Прямой и обратный проходы выполняются в BF16/FP16 (для скорости и памяти).
  • Оптимизатор обновляет FP32-копии весов.

Этот метод называется Automatic Mixed Precision (AMP). В PyTorch для BF16 используется torch.cuda.amp.autocast(dtype=torch.bfloat16), для FP16dtype=torch.float16 с GradScaler.

Сравнение памяти

  • FP32: 4 байта на параметр.
  • FP16/BF16: 2 байта на параметр.
  • Смешанное обучение: 6 байт на параметр (2 для forward/backward + 4 для master copy), но можно экономить память, храня master weights в FP16 (риск потери точности).

7. Аппаратная поддержка и производительность

АрхитектураПоддержка BF16Поддержка FP16Примечание
NVIDIA V100нет (эмуляция)даFP16 через tensor cores
NVIDIA A100да (нативные tensor cores)даBF16 в 2x быстрее FP16 для некоторых операций
NVIDIA H100да (улучшенные tensor cores)даBF16/FP16 одинаково быстры
AMD MI250дада
Google TPU v2+дадаTPU предпочитает BF16

Вывод на современных ускорителях BF16 часто даёт ту же или лучшую производительность, чем FP16, при меньших проблемах с точностью.


8. Экспериментальные результаты: BF16 vs FP16

Исследования (например, от Google и NVIDIA) показывают:

  • Для BERT-Large обучение с BF16 даёт точность, идентичную FP32, в то время как FP16 без масштабирования расходится.
  • Для ResNet-50 на ImageNet BF16 и FP16 с масштабированием показывают одинаковую точность, но BF16 проще в настройке.
  • Для обучения LLM (GPT-3, LLaMA) BF16 стал стандартом де-факто благодаря стабильности.

Таблица сравнения (гипотетический эксперимент):

МетрикаFP32FP16 (без scaling)FP16 (со scaling)BF16
Top-1 accuracy76.3%NaN (overflow)76.2%76.3%
Время обучения100%60%65%62%
Потребление памяти100%55%60%55%

9. Рекомендации: когда выбирать BF16, а когда FP16

  • BF16 — выбор по умолчанию для обучения больших моделей (LLM, трансформеры), когда доступна аппаратная поддержка. Он проще в использовании (не нужен GradScaler) и стабильнее.
  • FP16 — может быть полезен, когда:
    • Нет поддержки BF16 (старые GPU).
    • Требуется максимальная точность для очень малых градиентов (мант

Навигация