HorovodRunner: aprendizaje profundo distribuido con Horovod

Aprenda a realizar el entrenamiento distribuido de modelos de aprendizaje automático mediante HorovodRunner para iniciar trabajos de entrenamiento Horovod como trabajos de Spark en Azure Databricks.

¿Qué es HorovodRunner?

HorovodRunner es una API general para ejecutar cargas de trabajo distribuidas de aprendizaje profundo en Azure Databricks mediante el marco Horovod. Al integrar Horovod con el modo de barrera de Spark, Azure Databricks puede proporcionar una mayor estabilidad en los trabajos entrenamiento para el aprendizaje profundo de larga duración de Spark. HorovodRunner usa un método de Python que contiene código de entrenamiento de aprendizaje profundo con enlaces de Horovod. HorovodRunner selecciona el método en el controlador y lo distribuye a los trabajos de Spark. Un trabajo de MPI de Horovod se inserta como un trabajo de Spark mediante el modo de ejecución de barrera. El primer ejecutor recopila las direcciones IP de todos los ejecutores de tareas mediante BarrierTaskContext y desencadena un trabajo de Horovod mediante mpirun. Cada proceso MPI de Python carga el programa de usuario en pickled, lo deserializa y lo ejecuta.

HorovodRunner

Aprendizaje distribuido mediante HorovodRunner

HorovodRunner le permite iniciar trabajos de entrenamiento de Horovod como trabajos de Spark. La API HorovodRunner admite los métodos que se muestran en la tabla. Para obtener más información, consulte la documentación de la API HorovodRunner.

Método y firma Descripción
init(self, np) Cree una instancia de HorovodRunner.
run(self, main, **kwargs) Ejecute un trabajo de entrenamiento de Horovod invocando main(**kwargs). La función principal y los argumentos de palabras clave se serializan mediante cloudpickle y se distribuyen a los trabajadores del clúster.

El enfoque general para desarrollar un programa de entrenamiento distribuido mediante HorovodRunner es:

  1. Cree una instancia HorovodRunner inicializada con el número de nodos.
  2. Defina un método de entrenamiento de Horovod de acuerdo con los métodos descritos en Uso de Horovod y asegúrese de agregar cualquier instrucción de importación en el método.
  3. Pase el método de entrenamiento a la instancia HorovodRunner.

Por ejemplo:

hr = HorovodRunner(np=2)

def train():
  import tensorflow as tf
  hvd.init()

hr.run(train)

Para ejecutar HorovodRunner en el controlador solo con subprocesos n, use hr = HorovodRunner(np=-n). Por ejemplo, si hay 4 GPU en el nodo del controlador, puede elegir entre n y 4 como máximo. Para obtener más información sobre el parámetro np, consulte la documentación de la API HorovodRunner. Para obtener más información sobre cómo anclar una GPU por subproceso, consulte la guía de uso de Horovod.

Un error común es que los objetos TensorFlow no se pueden encontrar ni seleccionar. Esto sucede cuando las instrucciones de importación de la biblioteca no se distribuyen a otros ejecutores. Para evitar este problema, incluya todas las instrucciones de importación (por ejemplo, import tensorflow as tf) en la parte superior del método de entrenamiento de Horovod y dentro de cualquier otra función definida por el usuario que se haya llamado en el método de entrenamiento de Horovod.

Registro del entrenamiento de Horovod con Horovod Timeline

Horovod tiene la capacidad de registrar la escala de tiempo de su actividad, denominada Escala de tiempo de Horovod.

Importante

La escala de tiempo de Horovod tiene un impacto significativo en el rendimiento. El rendimiento de Inception3 puede disminuir en más o menos un 40 % cuando la escala de tiempo de Horovod está habilitada. Para acelerar los trabajos de HorovodRunner, no use la escala de tiempo de Horovod.

Recuerde que no puede ver la escala de tiempo de Horovod mientras el entrenamiento está en curso.

Para registrar una escala de tiempo de Horovod, establezca la variable de entorno HOROVOD_TIMELINE en la ubicación donde quiera guardar el archivo de escala de tiempo. Databricks recomienda usar una ubicación en el almacenamiento compartido para que el archivo de escala de tiempo se pueda recuperar fácilmente. Por ejemplo, puede usar las API de archivo local de DBFS, tal como se muestra:

timeline_dir = "/dbfs/ml/horovod-timeline/%s" % uuid.uuid4()
os.makedirs(timeline_dir)
os.environ['HOROVOD_TIMELINE'] = timeline_dir + "/horovod_timeline.json"
hr = HorovodRunner(np=4)
hr.run(run_training_horovod, params=params)

A continuación, agregue código específico de la escala de tiempo al principio y al final de la función de entrenamiento. El siguiente cuaderno de ejemplo incluye código de ejemplo que puede utilizar como solución para ver el progreso del entrenamiento.

Cuaderno de ejemplo de la escala de tiempo de Horovod

Obtener el cuaderno

Para descargar el archivo de escala de tiempo, use la CLI de Databricks o FileStore y, a continuación, use la instalación del explorador Chrome chrome://tracing para verla. Por ejemplo:

Horovod timeline

Flujo de trabajo de desarrollo

Estos son los pasos generales que debe dar para migrar código de aprendizaje profundo de nodo único al entrenamiento distribuido. Los Ejemplos: Migrar al aprendizaje profundo distribuido con HorovodRunner de esta sección ilustran estos pasos.

  1. Preparación del código de nodo único: Prepare y pruebe el código de nodo único con TensorFlow, Keras o PyTorch.
  2. Migración a Horovod: Siga las instrucciones de la guía de uso de Horovod para migrar el código con Horovod y probarlo en el controlador:
    1. Agregue hvd.init() para inicializar Horovod.
    2. Ancle una GPU de servidor para que la use este proceso mediante config.gpu_options.visible_device_list. Con la configuración típica de una GPU por proceso, esta opción se puede establecer en un rango local. En ese caso, al primer proceso del servidor se le asignará la primera GPU, al segundo proceso se le asignará la segunda GPU, y así sucesivamente.
    3. Incluya una partición del conjunto de datos. Este operador de conjunto de datos es muy útil al ejecutar el entrenamiento distribuido, ya que permite a cada trabajo leer un subconjunto único.
    4. Escale la tasa de aprendizaje por número de trabajos. El tamaño efectivo del lote en el entrenamiento distribuido sincrónico se escala según el número de trabajos. Así pues, aumentar la velocidad de aprendizaje compensa el aumento del tamaño del lote.
    5. Ajuste el optimizador en hvd.DistributedOptimizer. El optimizador distribuido delega el cálculo de degradado en el optimizador original, realiza el promedio de los degradados mediante allreduce o allgather y, a continuación, aplica los degradados según el promedio.
    6. Agregue hvd.BroadcastGlobalVariablesHook(0) a los estados iniciales de la variable de difusión a partir del rango 0 a todos los demás procesos. Esto es necesario para garantizar una inicialización coherente de todos los trabajos cuando el entrenamiento se inicia con pesos aleatorios o si se restaura desde un punto de control. Como alternativa, si no usa MonitoredTrainingSession, puede ejecutar la operación hvd.broadcast_global_variables una vez inicializadas las variables globales.
    7. Modifique el código para guardar los puntos de control solo en el trabajo 0 para evitar que otros trabajos provoquen errores.
  3. Migración a HorovodRunner: HorovodRunner ejecuta el trabajo de entrenamiento de Horovod invocando una función de Python. Asegúrese de encapsular el procedimiento de entrenamiento principal en una sola función de Python. A continuación, puede probar HorovodRunner en modo local y en modo distribuido.

Actualización de las bibliotecas de aprendizaje profundo

Nota:

Este artículo contiene referencias al término esclavo, un término que Azure Databricks no utiliza. Cuando se quite el término del software, se quitará también del artículo.

Si actualiza TensorFlow, Keras o PyTorch (o cambia a una versión anterior de estos), debe volver a instalar Horovod para que se compile en la biblioteca recién instalada. Por ejemplo, si quiere actualizar TensorFlow, Databricks es recomendable que use el script init de las instrucciones de instalación de TensorFlow y anexe al final el siguiente código de instalación específico de TensorFlow para Horovod. Consulte las instrucciones de instalación de Horovod para trabajar con diferentes combinaciones, como actualizar PyTorch y otras bibliotecas (o cambiar a una versión anterior).

add-apt-repository -y ppa:ubuntu-toolchain-r/test
apt update
# Using the same compiler that TensorFlow was built to compile Horovod
apt install g++-7 -y
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 60 --slave /usr/bin/g++ g++ /usr/bin/g++-7

HOROVOD_GPU_ALLREDUCE=NCCL HOROVOD_CUDA_HOME=/usr/local/cuda pip install horovod==0.18.1 --force-reinstall --no-deps --no-cache-dir

Ejemplos: Migrar al aprendizaje profundo distribuido con HorovodRunner

En los ejemplos siguientes, que están basados en el conjunto de datos MNIST, se muestra cómo migrar un programa de aprendizaje profundo de un solo nodo al aprendizaje profundo distribuido con HorovodRunner.

Limitaciones

  • Al trabajar con archivos de área de trabajo, HorovodRunner no funcionará si np está establecido en mayor que 1 y el cuaderno importa desde otros archivos relativos. Considere la posibilidad de usar horovod.spark en lugar de HorovodRunner.