El entrenamiento y el razonamiento de grandes modelos suelen implicar el concepto de precisión, y existen muchos tipos, y también se dividen en diferentes formatos con el mismo nivel de precisión. Además, también existen los conceptos de multiprecisión y precisión mixta en escenarios de uso práctico.
Precisión común
Precisión en punto flotante: doble precisión (FP64), precisión simple (FP32, TF32), media precisión (FP16, BF16), precisión de 8 bits (FP8), precisión de 4 bits (FP4, NF4) Precisión de cuantificación: INT8, INT4 (también INT3/INT5/INT6)
Un número de coma flotante consta de tres partes: bits de signo, exponenciales y mantisas. Cuanto mayor es el bit exponencial, mayor es el rango de números que se pueden representar. Cuanto mayor es el dígito de la mantisa, mayor es la precisión del número.
La tabla lo resume de la siguiente manera
| formato | bit de símbolo | Bit exponencial | Decimal | Cifras totales | | FP64 | 1 | 11 | 52 | 64 | | FP32 | 1 | 8 | 23 | 32 | | TF32 | 1 | 8 | 10 | 19 | | BF16 | 1 | 8 | 7 | 16 | | FP16 | 1 | 5 | 10 | 16 | | FP8 E4M3 | 1 | 4 | 3 | 8 | | FP8 E5M2 | 1 | 5 | 2 | 8 | | FP4 | 1 | 2 | 1 | 4 |
FP32: Número de coma flotante de 32 bits, 4 bytes por dato TF32: número de coma flotante de 19 bits, cada dato es de 2 bytes FP16: número de coma flotante de 16 bits, 2 bytes por dato BF16: número de coma flotante de 16 bits, cada dato es de 2 bytes Int8: entero de 8 bits, cada dato representa 1 byte Int4: enteros de 4 bits, cada dato es de 0,5 bytes
¿Por qué tanta precisión
Por el coste y la precisión. Todos sabemos que una alta precisión es definitivamente más precisa, pero también conllevará mayores costes de computación y almacenamiento. Menor precisión reduce la precisión del cálculo, pero puede mejorar la eficiencia y el rendimiento computacional. Así que una variedad de precisiones diferentes te permite elegir la más adecuada en distintas situaciones. La doble precisión es más precisa que la expresión de precisión simple, pero ocupa el doble de almacenamiento y tarda más en calcular.
¿Por qué es necesario cuantificar los modelos grandes?
1. Reducir el uso de memoria Los modelos grandes suelen usar números de coma flotante de 32 bits (FP32) o números de coma flotante de 16 bits (FP16) para representar pesos y valores de activación. Mediante cuantización, estos valores de alta precisión pueden convertirse en representaciones de menor precisión (por ejemplo, enteros de 8 bits, INT8), reduciendo significativamente el espacio de almacenamiento del modelo. Esto es importante para el despliegue en dispositivos con recursos limitados como dispositivos móviles, sistemas embebidos, etc.
2. Acelerar la velocidad de razonamiento Los modelos cuantizados pueden funcionar de forma más eficiente en hardware. Muchos equipos modernos (como GPU, TPU, NPU, etc.) cuentan con soporte especializado de optimización para computación de baja precisión, lo que permite operaciones de cuantización más rápidas. Además, los cálculos de baja precisión suelen implicar menos operaciones en bits, reduciendo la complejidad computacional y, por tanto, acelerando la inferencia.
3. Reducir el consumo de energía El modelo cuantizado no solo reduce la necesidad de recursos informáticos, sino que también reduce el consumo de energía. Esto es especialmente importante para dispositivos alimentados por batería como smartphones, dispositivos IoT, etc., donde un bajo consumo de energía implica una mayor duración de la batería.
4. Dispositivos de borde fáciles de desplegar Muchos modelos grandes fueron entrenados y desplegados inicialmente en la nube, pero con el desarrollo de la computación en el borde, cada vez más escenarios de aplicación requieren que los modelos se desplieguen en dispositivos de borde. Con la potencia de cálculo y los recursos de almacenamiento limitados en dispositivos edge, la cuantización puede ayudar a que estos modelos funcionen de forma más eficiente en dispositivos edge.
5. Reducir los requisitos de ancho de banda En el proceso de inferencia distribuida o actualizaciones de modelos, la cuantización puede reducir el ancho de banda necesario para la transferencia del modelo. Esto es útil para entornos con ancho de banda de red limitado, como dispositivos IoT en zonas remotas.
6. Mantener el rendimiento del modelo Aunque la cuantización introduce cierta pérdida de precisión, el rendimiento original del modelo puede preservarse en gran medida mediante métodos de cuantización apropiados (como la cuantización de precisión mixta, cuantización post-entrenamiento, entrenamiento de percepción cuantitativa, etc.). Por lo tanto, en aplicaciones prácticas, la cuantificación puede encontrar un buen equilibrio entre rendimiento y eficiencia.
Referencia de memoria
| tipo | Cada mil millones de parámetros debe ocupar memoria | | float32 | 4G | | FP16/BF16 | 2G | | int8 | 1G | | INT4 | 0,5G |
FP64 (Doble Precisión)
El punto flotante de 64 bits, típicamente un formato binario de punto flotante de doble precisión definido por IEEE 754, tiene:
Símbolo de 1 dígito Índice de 11 dígitos 52 decimales
Alcance: ~2,23e-308... ~1,80e308 con precisión decimal completa 15-17.
Uso:
Este formato se utiliza para cálculos científicos que requieren alta precisión. No se utiliza habitualmente para cálculos de aprendizaje profundo. Soporte de software: Representa el tipo doble en la mayoría de los sistemas C/C++. Soportado en TensorFlow (por ejemplo, tf.float64) / PyTorch (por ejemplo, torch.float64 o torch.double). Soporte de hardware: Normalmente soportado en CPUs x86. La mayoría de las GPUs, especialmente las de gaming, incluida la serie RTX, están muy limitadas en rendimiento FP64 (normalmente 1/32 del rendimiento FP32 en lugar de 1/2). Las GPUs recientes sin restricciones compatibles con FP64 incluyen GP100/100/102/104 en Tesla P40/P4 y Quadro GP100, GV100 en Tesla V100/Quadro GV100/Titan V, y la recientemente anunciada GA100 en A100 (curiosamente, la nueva arquitectura Ampere tiene una tercera generación) en comparación con los núcleos Tensor habilitados para FP64 Ahora se incluye el nuevo procesamiento FP64 compatible con IEEE, que ofrece un rendimiento 2,5 veces superior al FP64 de V100.
FP32 (Precisión total)
Este formato ha sido durante mucho tiempo un punto de batalla para el aprendizaje profundo. Otro formato IEEE 754, de punto flotante de precisión simple, tiene:
Símbolo de 1 dígito Índice de 8 dígitos 23 decimales Idealmente, tanto el entrenamiento como la inferencia deberían hacerse en FP32, pero FP32 es el doble de lento que FP16/BF16, por lo que en la práctica se usan a menudo métodos de precisión mixta, donde los pesos FP32 se usan como el "peso maestro" exacto, los pesos FP16/BF16 se emplean para cálculos de propagación hacia adelante y hacia atrás para mejorar la velocidad de entrenamiento, y finalmente los pesos soberanos FP32 se actualizan con gradientes FP16/BF16 en la fase de actualización del gradiente.
Durante el entrenamiento, el peso soberano es siempre FP32. En la práctica, los pesos de media precisión suelen proporcionar una precisión similar a la FP32 en la inferencia, porque los pesos exactos FP32 solo se necesitan cuando se actualiza el gradiente del modelo. Esto significa que podemos usar pesos de media precisión al inferir, así que podemos obtener el mismo resultado con solo la mitad de la memoria GPU.
Alcance: ~1,18e-38... ~3,40e38 con una precisión de 6-9 decimales significativos.
Uso:
El tipo estándar de computación de redes neuronales durante mucho tiempo. Los pesos, activaciones y otros valores en las redes neuronales llevan mucho tiempo predeterminados en FP32. Para muchos cálculos científicos, especialmente los iterativos, la precisión no es suficiente, lo que conduce a la acumulación de errores. Soporte de software: Representa el tipo float en la mayoría de los sistemas C/C++. Soportado en TensorFlow (por ejemplo, tf.float32) / PyTorch (por ejemplo, torch.float32 o torch.float). Soporte de hardware: Normalmente soportado en CPUs x86. Normalmente soportada por GPU NVIDIA/AMD.
FP16 (Media Precisión)
De manera similar, el formato estándar IEEE 754, el formato de punto flotante de media precisión tiene:
Símbolo de 1 dígito Índice de 5 dígitos 10 decimales El número FP16 tiene un rango numérico mucho menor que FP32. Por lo tanto, FP16 corre el riesgo de desbordamiento (cuando se usa para representar números muy grandes) y de desbordamiento (cuando se usa para representar números muy pequeños). Por ejemplo, cuando haces 10k * 10k, el resultado final debería ser 100M, que FP16 no puede representar porque el número máximo que FP16 puede representar es 64k. Así que acabas con NaN (No un Número) en los cálculos de redes neuronales, porque los cálculos se hacen en estratificaciones y en orden de lotes, así que una vez que aparece NaN, todos los cálculos previos se destruyen. En general, esto puede mitigarse mediante la escalada de pérdidas, pero este enfoque no siempre funciona.
Alcance: ~5,96e−8 (6,10e−5) ... 65504, con una precisión de 4 dígitos decimales significativos.
Uso:
El aprendizaje profundo suele usar FP16 en lugar de FP32, ya que los cálculos de menor precisión no parecen importar para redes neuronales. La precisión extra no sirve de nada, y al mismo tiempo es más lenta, requiere más memoria y ralentiza la comunicación. Puede usarse para entrenamiento, normalmente con entrenamiento de precisión mixta (TensorFlow/PyTorch). Puede usarse para cuantización posterior al entrenamiento para acelerar la inferencia (TensorFlow Lite). Otros formatos utilizados para la cuantización posterior al entrenamiento incluyen enteros INT8 (enteros de 8 bits), INT4 (4 bits) e incluso INT1 (valores binarios). Soporte de software: Actualmente no está en el estándar C/C++ (pero hay una propuesta de flotación breve). Algunos sistemas C/C++ admiten __fp16 tipos. De lo contrario, puede usarse con bibliotecas especiales. Soportado en TensorFlow (por ejemplo, tf.float16) / PyTorch (por ejemplo, torch.float16 o torch.half). Soporte de hardware: No se admiten CPUs x86 (como tipo único). El soporte en GPUs gaming antiguas es pobre (rendimiento 32/1 para FP64, consulta la publicación sobre GPUs para más detalles). Actualmente está bien soportado en GPUs modernas, como la serie NVIDIA RTX.
BFLOAT16 (Semi-Precisión)
Otro formato de 16 bits desarrollado originalmente por Google se llama "Brain Floating Point Format", o simplemente "bfloat16". El nombre proviene de Google Brain.
El IEEE FP16 original fue diseñado sin tener en cuenta aplicaciones de aprendizaje profundo, y su rango dinámico era demasiado limitado. BFLOAT16 resuelve este problema, proporcionando el mismo rango dinámico que el FP32.
Por lo tanto, BFLOAT16 tenemos:
Símbolo de 1 dígito Índice de 8 dígitos 7 decimales
El formato bfloat16 está truncado a IEEE 754 FP32, lo que permite una conversión rápida hacia y desde IEEE 754 FP32. Al convertir al formato bfloat16, se conservan bits exponenciales, mientras que los campos mantissa pueden reducirse por truncamiento.
Alcance: ~1,18e-38... ~3,40e38 con 3 decimales significativos. Uso:
Ahora parece que está reemplazando a FP16. A diferencia de FP16, que a menudo requiere un procesamiento especial mediante técnicas como la escalada de pérdidas, BF16 es casi un reemplazo directo de FP32 al entrenar y ejecutar redes neuronales profundas. Soporte de software: No en el estándar C/C++. Puede usarse con bibliotecas especiales. Soportado en TensorFlow (por ejemplo, tf.bfloat16) / PyTorch (por ejemplo, torch.bfloat16).
TF32
TensorFloat-32 o TF32 es el nuevo modo matemático en las GPUs NVIDIA A100.
Utilizando las mismas mantis de 10 bits que las matemáticas de media precisión (FP16), el TF32 demuestra tener suficiente margen para cumplir con los requisitos de precisión de las cargas de trabajo de IA. Y TF32 utiliza el mismo índice de 8 bits que FP32, por lo que puede soportar el mismo rango numérico.
Técnicamente, es un formato de 19 bits. Piénsalo como una BFLOAT16 de precisión extendida, como "BFLOAT19" o una precisión disminuida como FP32.
Así que, TF32 tiene:
Símbolo de 1 dígito Índice de 8 dígitos 10 decimales La ventaja de TF32 es que tiene el mismo formato que FP32. Al calcular el producto interno con TF32, la mantissa del operando de entrada se redondea de 23 a 10 bits. Los operandos de redondeo se multiplican exactamente y se acumulan en FP32 normal.
El núcleo tensor TF32 funciona con entradas FP32 y genera resultados en FP32 sin cambios de código. Las operaciones no matriciales continúan usando FP32. Esto proporciona una forma sencilla de acelerar los datos de entrada/salida FP32 en frameworks de deep learning y HPC.
Alcance: ~1.18e-38... ~3.40e38 con una precisión de 4 decimales significativos. Uso:
Una de las grandes ventajas de TF32 es que solo necesita soporte de compiladores al nivel más profundo, es decir, dentro del compilador CUDA. El resto del código simplemente ve FP32 con menos precisión, pero con el mismo rango dinámico. Usar TF32 es principalmente para hacer llamadas a la biblioteca y ver si funciona correctamente. La presencia del TF32 permite plug-ins rápidos, aprovechando la velocidad de los Núcleos Tensor sin mucho trabajo. Formatos como FP16 y BFLOAT16 requieren más ajustes porque implican diferentes disposiciones de bits. Pero el uso de estos formatos reduce el ancho de banda de la memoria, permitiendo una ejecución más rápida. Para comparar, el rendimiento máximo del A100 es:
FP32 sin núcleos tensoriales: 19,5 TFLOPS Núcleos tensoriales TF32: 156 TFLOPS (así que usar TF32 en lugar de FP32 facilita aumentar la velocidad). Núcleos tensoriales FP16/BF16: 312 TFLOPS (por lo tanto, un cambio razonable a FP16/BF16 puede aportar más ganancias de velocidad, pero a un coste mayor). Soporte de software: No en el estándar C/C++. CUDA 11 soportada. Soporte de hardware: GPU: NVIDIA A100 es el primer modelo soportado
FP8
Introducido por la GPU H100, permite una mayor multiplicación y convolución de matrices, pero con menor precisión.
Los tipos de datos FP100 soportados por H8 son en realidad 2 tipos de datos diferentes que pueden usarse para distintas partes del entrenamiento de redes neuronales:
E4M3 - consta de 1 bit simbólico, 4 bits exponenciales y 3 decimales. Puede almacenar hasta +/-448 y nan. E5M2 - consta de 1 bit de signo, 5 bits exponenciales y 2 decimales. Puede almacenar valores de hasta +/-57344, +/-inf y nan. El compromiso de aumentar el rango dinámico es que los valores almacenados son menos precisos.
Estructura de los tipos de datos en coma flotante. Todos los valores mostrados (en FP16, BF16, FP8 E4M3 y FP8 E5M2) son la representación más cercana al valor 0,3952.
Ambos tipos pueden usarse durante el entrenamiento de una red neuronal. En general, la activación y los pesos hacia adelante requieren mayor precisión, por lo que es mejor usar el tipo de datos E4M3 durante el paso hacia adelante. Sin embargo, en la retropropagación, el gradiente que fluye a través de la red suele ser menos susceptible a la pérdida de precisión, pero requiere un rango dinámico mayor. Por lo tanto, es mejor almacenarlos usando el formato de datos E5M2. El H100 TensorCore soporta cualquier combinación de estos tipos como entrada, permitiéndonos almacenar cada tensor con la precisión que prefiero.
Referencia:
El inicio de sesión del hipervínculo es visible.
El inicio de sesión del hipervínculo es visible. |