Se usó la API de Cloud Translation para traducir esta página.
Switch to English

Usar bfloat16 con modelos de TensorFlow

La investigación sobre el aprendizaje automático (AA) demuestra que muchos modelos de aprendizaje automático pueden tolerar una aritmética de menor precisión sin que se degrade la exactitud convergente. Muchos modelos alcanzan resultados con la misma exactitud convergente con bfloat16 que cuando utilizan valores numéricos de punto flotante de 32 bits, y algunos modelos incluso muestran una mejora en la exactitud convergente con bfloat16.

Este documento trata sobre el entrenamiento de precisión mixta en el sentido de almacenar activaciones y gradientes en memoria mediante el formato bfloat16. (Para obtener más información sobre el entrenamiento de precisión mixto, consulta Entrenamiento de precisión mixto). En este documento, no se trata el uso de bfloat16 en el MXU en Cloud TPU.

Los siguientes temas se aplican a los modelos del AA que utilizan TensorFlow:

  • Descripción del punto flotante cerebral de 16 bits personalizado de Google, bfloat16.
  • Ventajas de rendimiento por usar bfloat16 en memoria para modelos del AA en hardware que lo admita, como Cloud TPU.
  • Cómo almacenar activaciones y gradientes en la memoria mediante bfloat16 para un modelo de TPU en TensorFlow.

De forma predeterminada, TensorFlow almacena todas las variables en un punto flotante de 32 bits (fp32). El uso de bfloat16 para las activaciones y los gradientes acelera el tiempo de los pasos del dispositivo y disminuye el uso de la memoria. Consulta Cambiar tu modelo a fin de determinar los beneficios de utilizar bfloat16 para activaciones y gradientes en tu modelo.

El formato de punto flotante bfloat16

El formato bfloat16 es [1:8:7], que tiene un bit de signo, ocho bits exponentes, siete bits mantisa más un bit mantisa implícito. En comparación, el formato estándar de punto flotante de 16 bits (fp16) es [1:5:10]. Ten en cuenta que el formato fp16 tiene solo 5 bits exponentes. Debido a estas características, bfloat16 tiene un rango dinámico mayor que fp16. El rango bfloat16 es útil, por ejemplo, para gradientes que pueden estar fuera del rango dinámico de fp16 y, por lo tanto, requieren escalamiento de pérdida; bfloat16 puede representar tales gradientes directamente. Además, puedes usar el formato bfloat16 para representar con precisión todos los números enteros [-256, 256], lo que significa que puedes codificar un int8 en bfloat16 sin pérdida de exactitud.

La siguiente figura ilustra tres formatos de puntos flotantes

  • fp32: Punto flotante de precisión simple IEEE
  • fp16: Punto flotante de precisión media IEEE
  • bfloat16: punto flotante cerebral de 16 bits

image

El rango dinámico de bfloat16 es mayor que el de fp16.

Ventajas de rendimiento y uso de la memoria

Cloud TPU es compatible con el almacenamiento de valores, como activaciones y gradientes en formato bfloat16. El uso de bfloat16 reduce el tamaño de los datos en la memoria y permite que los modelos más grandes quepan en la misma cantidad de memoria. Además, el uso de bfloat16 puede reducir la rematerialización, lo que mejora el tiempo de los pasos.

Algunas operaciones dependen del ancho de banda de la memoria, lo que significa que este determina el tiempo que se destina a esas operaciones. El almacenamiento de entradas y resultados de las operaciones que dependen del ancho de banda de la memoria en el formato bfloat16 reduce la cantidad de datos que deben transferirse, con lo que se mejora la velocidad de las operaciones.

En el siguiente gráfico, se muestran las mejoras percibidas en nuestros experimentos internos.

image

Cambia tu modelo para usar bfloat16

De forma predeterminada, las activaciones, los gradientes y los pesos se almacenan en fp32 en la memoria. Puedes utilizar bfloat16 para activaciones y gradientes, dejar los pesos en fp32 y, luego, comparar el rendimiento del modelo entre el uso de bfloat16 y fp32 a fin de determinar los beneficios.

  1. Ejecuta el modelo en fp32 mediante capture_tpu_profile.

  2. Para ver el tiempo de paso y la precisión convergente del modelo, usa el visualizador de perfiles en TensorBoard. (Consulta la sección Usar las herramientas de Cloud TPU en TensorBoard para conocer más detalles).

  3. Convierte la entrada a bfloat16 en tu canalización de entrada dentro del analizador de registros para que la conversión pueda realizarse en paralelo en lugar de al final del input_fn. Esto convierte todas las activaciones y los gradientes del modelo en bfloat16.

    Por ejemplo:

    image = tf.cast(image, tf.bfloat16)
    
  4. Crea tu red dentro del alcance de bfloat16 y, luego, convierte los resultados del modelo en float32.

Una vez que hayas configurado tu modelo a fin de utilizar tf.bfloat16 para las activaciones, verifica lo siguiente y consulta el impacto de bfloat16 en tu modelo:

  1. Ejecuta el modelo con bfloat16 mediante capture_tpu_profile.
  2. Para ver el tiempo de paso y la precisión convergente del modelo, usa el visualizador de perfiles en TensorBoard. (Consulta la sección Usar las herramientas de Cloud TPU en TensorBoard para conocer más detalles).
  3. Compara el tiempo del paso con bfloat16 y fp32. El tiempo del paso, normalmente, mejora para bfloat16.
  4. Compara la exactitud convergente de bfloat16 con la de fp32. Por lo general, son idénticas, pero los valores pueden ser mejores o peores de lo esperado.

Si aún no sabes qué rango de variación esperar de tu modelo, es posible que necesites varias ejecuciones para determinar cómo varía la exactitud convergente de ejecución en ejecución.

Si tu perfil muestra que el tiempo de procesamiento es más rápido, pero la canalización de entrada se convirtió en un cuello de botella, optimiza tu canalización de entrada a fin de obtener una ventaja de velocidad aún mayor. Consulta la documentación sobre el rendimiento de la canalización de entrada de datos para obtener lineamientos generales acerca de cómo mejorar el rendimiento de la canalización de TensorFlow.

Se recomienda utilizar la misma precisión para el entrenamiento y la inferencia. Se puede entrenar con fp32 para las activaciones y, luego, ejecutar inferencias con bfloat16 (o viceversa). Si eliges una precisión que no coincida, verifica la exactitud convergente con la precisión que se usó para la inferencia.