BFloat16 (BF16)
BFloat16 (BF16) es un formato de coma flotante de 16 bits con el exponente de 8 bits y la fracción de 7 bits de FP32, que conserva el rango de FP32 con la mitad de memoria. En qué se diferencia de FP16.
BFloat16 (coma flotante de cerebro, BF16) es un formato de coma flotante de 16 bits con 1 bit de signo, 8 bits de exponente y 7 bits de fracción. Mantiene la misma anchura de exponente que el formato de coma flotante estándar de 32 bits (FP32), por lo que cubre el mismo intervalo de valores, aproximadamente de 1,2 × 10⁻³⁸ a 3,4 × 10³⁸, y almacena cada número usando la mitad de memoria. El coste está en la precisión: 7 bits de fracción solo proporcionan dos o tres cifras decimales significativas. El aprendizaje profundo tolera bien ese redondeo, y el formato, concebido en Google Brain para las TPU de Google, se ha convertido en el formato de 16 bits predeterminado para entrenar modelos grandes en GPU modernas y aceleradores.
Cómo representa números BF16#
Un valor BF16 es exactamente la mitad superior de un valor FP32: el mismo signo y exponente, con la fracción reducida de 23 a 7 bits. Por tanto, convertir FP32 a BF16 solo redondea los 16 bits inferiores, y la conversión inversa añade ceros, lo que hace que el formato sea barato de implementar en hardware. El otro formato habitual de 16 bits, IEEE FP16 o precisión media, distribuye los bits de otra manera, con 5 bits de exponente y 10 de fracción; así gana precisión a costa de rango. La comparación de los tres formatos con los mismos valores muestra la diferencia:
import torch
# Largest value, smallest normal value, and spacing just above 1.0 for each format
for dtype in [torch.float32, torch.float16, torch.bfloat16]:
info = torch.finfo(dtype)
print(f"{dtype!s:15} max={info.max:.3g} tiny={info.tiny:.3g} eps={info.eps:.3g}")
# A large activation, a tiny gradient, and a value that needs fine precision
x = torch.tensor([70000.0, 1e-8, 1.001953125])
print("FP16:", x.half().tolist())
print("BF16:", x.bfloat16().tolist())BF16 alcanza un máximo de 3.39e38, frente a los 65.504 de FP16, y su valor normal mínimo, 1.18e-38, coincide con el de FP32. FP16 convierte 70.000 en infinito y 1e-8 en cero, mientras que BF16 conserva ambos como 70.144 y aproximadamente 1.0e-8. El intervalo más fino de FP16 (eps 0.000977 frente a 0.00781 de BF16) conserva exactamente 1.001953125, mientras que BF16 lo redondea a 1.0.
BF16 frente a FP16 en el entrenamiento#
Durante el entrenamiento, el rango importa más que la precisión. Los gradientes suelen caer por debajo de los valores mínimos de FP16 y desaparecer, así que el entrenamiento con precisión mixta FP16 multiplica la pérdida por un factor de escala antes de la retropropagación y reduce ese factor cada vez que los gradientes se desbordan; esta técnica se llama escalado de la pérdida. BF16 no necesita escalado de la pérdida, porque su rango iguala al de FP32, y el entrenamiento con BF16 iguala los resultados de FP32 en modelos de visión, voz, lenguaje y recomendación con el mismo número de iteraciones y sin cambiar los hiperparámetros. El entrenamiento con precisión mixta mantiene una copia maestra de los pesos en FP32 y realiza las multiplicaciones de matrices en BF16 con acumulación en FP32, ya que sumar muchos productos con fracciones de 7 bits en BF16 provocaría demasiada pérdida. La elección entre los dos formatos de 16 bits depende sobre todo del hardware:
PyTorch aplica BF16 mediante la precisión mixta automática con torch.autocast(device_type="cuda", dtype=torch.bfloat16). Ultralytics YOLO ofrece el mismo interruptor para el entrenamiento con amp="bf16", que ejecuta la pasada hacia delante con autocast BF16 y desactiva el escalador de gradientes que usa su modo FP16 predeterminado, en GPU CUDA con compatibilidad nativa con BF16.
Compatibilidad de hardware#
Las TPU de Cloud de segunda y tercera generación de Google multiplican en BF16 dentro de sus unidades matriciales y acumulan en FP32, y las generaciones posteriores de TPU mantuvieron este formato. Las GPU de NVIDIA ejecutan BF16 en Tensor Cores a partir de la generación Ampere, incluidas las GPU A100, H100 y Blackwell, y los procesadores Intel Xeon con extensiones matriciales avanzadas (AMX) aceleran este formato en la CPU. En una NVIDIA A100, las operaciones con Tensor Core en BF16 y FP16 alcanzan ambas un máximo de 312 teraFLOPS, 16 veces los 19,5 teraFLOPS de cálculo FP32 estándar de la GPU.
BF16 frente a formatos relacionados#
- Precisión media (FP16): El formato IEEE de 16 bits, con más precisión y mucho menos rango. Sigue siendo habitual para la inferencia, donde las activaciones se mantienen dentro de su rango y su precisión adicional resulta útil.
- TF32: Modo de cálculo de Tensor Core de NVIDIA con el exponente de 8 bits de BF16 y la fracción de 10 bits de FP16, que las bibliotecas pueden usar para multiplicaciones de matrices FP32 en GPU Ampere y posteriores, mientras los tensores se mantienen almacenados en 32 bits.
- FP8: Formatos de coma flotante de 8 bits, como E4M3 y E5M2, compatibles con GPU Hopper y Blackwell, que vuelven a reducir a la mitad el uso de memoria para el entrenamiento y la inferencia de los modelos más grandes.
- Cuantización de modelos: Convierte los pesos entrenados a formatos enteros como INT8 o INT4 para su implementación.
BF16 en modelos de lenguaje grandes#
La mayoría de los modelos de lenguaje grandes (LLM) de pesos abiertos se entrenan con precisión mixta BF16 y se publican con pesos BF16, que sirven de referencia para comparar las versiones cuantizadas FP8 e INT4. A 2 bytes por parámetro, los pesos de un modelo de 70.000 millones de parámetros ocupan 140 GB en BF16, más que los 80 GB de una NVIDIA H100, así que servir un modelo así en BF16 requiere repartirlo entre al menos dos GPU.










