Solucione de manera efectiva los problemas de convergencia del entrenamiento distribuido con la Sintonización Automática de Modelos Hyperband de Amazon SageMaker
Solucione problemas de convergencia en entrenamiento distribuido con Sintonización Automática de Modelos Hyperband de Amazon SageMaker
Los últimos años han mostrado un crecimiento asombroso en las redes neuronales de aprendizaje profundo (DNN, por sus siglas en inglés). Este crecimiento se puede observar en modelos más precisos e incluso en nuevas posibilidades con la IA generativa: grandes modelos de lenguaje (LLM, por sus siglas en inglés) que sintetizan lenguaje natural, generadores de texto a imagen, y más. Estas capacidades mejoradas de las DNN vienen con el costo de tener modelos masivos que requieren recursos computacionales significativos para ser entrenados. El entrenamiento distribuido aborda este problema con dos técnicas: paralelismo de datos y paralelismo de modelos. El paralelismo de datos se utiliza para escalar el proceso de entrenamiento en múltiples nodos y trabajadores, y el paralelismo de modelos divide un modelo y los ajusta en la infraestructura designada. Los trabajos de entrenamiento distribuido de Amazon SageMaker te permiten, con un solo clic (o una sola llamada a la API), configurar un clúster de cómputo distribuido, entrenar un modelo, guardar el resultado en Amazon Simple Storage Service (Amazon S3) y apagar el clúster cuando esté completo. Además, SageMaker ha innovado continuamente en el espacio de entrenamiento distribuido lanzando características como clústeres heterogéneos y bibliotecas de entrenamiento distribuido para paralelismo de datos y paralelismo de modelos.
El entrenamiento eficiente en un entorno distribuido requiere ajustar hiperparámetros. Un ejemplo común de buena práctica al entrenar en varias GPUs es multiplicar el tamaño del lote (o mini-lote) por el número de GPUs para mantener el mismo tamaño de lote por GPU. Sin embargo, ajustar los hiperparámetros a menudo afecta la convergencia del modelo. Por lo tanto, el entrenamiento distribuido necesita equilibrar tres factores: distribución, hiperparámetros y precisión del modelo.
En esta publicación, exploramos el efecto del entrenamiento distribuido en la convergencia y cómo utilizar el ajuste automático de modelos de Amazon SageMaker para afinar los hiperparámetros del modelo para el entrenamiento distribuido utilizando el paralelismo de datos.
El código fuente mencionado en esta publicación se puede encontrar en el repositorio de GitHub (se recomienda una instancia m5.xlarge).
Escalado del entrenamiento de un entorno individual a un entorno distribuido
El paralelismo de datos es una forma de escalar el proceso de entrenamiento a múltiples recursos informáticos y lograr un tiempo de entrenamiento más rápido. Con el paralelismo de datos, los datos se dividen entre los nodos de cómputo, y cada nodo calcula los gradientes en función de su partición y actualiza el modelo. Estas actualizaciones se pueden realizar utilizando uno o varios servidores de parámetros de manera asíncrona, uno a muchos o todo a todo. Otra forma puede ser utilizar un algoritmo AllReduce. Por ejemplo, en el algoritmo de anillo AllReduce, cada nodo se comunica solo con dos de sus nodos vecinos, lo que reduce las transferencias de datos en general. Para obtener más información sobre servidores de parámetros y ring-allreduce, consulta “Cómo lanzar un entrenamiento distribuido de TensorFlow fácilmente con Horovod” o “Servidores de parámetros en Amazon SageMaker”. En cuanto a la partición de datos, si hay n nodos de cómputo, cada nodo debería obtener un subconjunto de los datos, aproximadamente 1/n del tamaño.
- Entendiendo todo sobre los datos
- Un gimnasio de código abierto para el diseño asistido por aprendiza...
- Juego a gran escala ‘Dragon’s Dogma Dark Arisen’ ...
Para demostrar el efecto del escalado del entrenamiento en la convergencia del modelo, realizamos dos experimentos simples:
- Entrenar un modelo de clasificación de imágenes utilizando una DNN de capa completamente conectada con funciones de activación ReLU utilizando los frameworks MXNet y Gluon. Para los datos de entrenamiento, utilizamos el conjunto de datos MNIST de dígitos escritos a mano. Utilizamos el código fuente proporcionado en el repositorio de ejemplos de SageMaker.
- Entrenar un modelo de clasificación binaria utilizando el algoritmo XGBoost incorporado de SageMaker. Utilizamos el conjunto de datos de marketing directo para predecir clientes bancarios que probablemente responderán a una oferta específica. El código fuente y los pasos para reproducir el experimento se pueden encontrar en el repositorio de GitHub.
Cada entrenamiento de modelo se ejecutó dos veces: en una sola instancia y distribuido en varias instancias. Para el entrenamiento distribuido de DNN, para utilizar completamente los procesadores distribuidos, multiplicamos el tamaño del mini-lote por el número de instancias (cuatro). La siguiente tabla resume la configuración y los resultados.
Tipo de problema | Clasificación de imágenes | Clasificación binaria | ||
Modelo | DNN | XGBoost | ||
|
ml.c4.xlarge | ml.m5.2xlarge | ||
Conjunto de datos |
MNIST (Imágenes etiquetadas) |
Marketing Directo (tabular, categorías numéricas y vectorizadas) | ||
|
Precisión | AUC | ||
Épocas/Rondas | 20 | 150 | ||
Número de instancias | 1 | 4 | 1 | 3 |
Tipo de distribución | N/A | Servidor de parámetros | N/A | AllReduce |
Tiempo de entrenamiento (minutos) | 8 | 3 | 3 | 1 |
Puntuación de validación final | 0.97 | 0.11 | 0.78 | 0.63 |
Para ambos modelos, el tiempo de entrenamiento se redujo casi de forma lineal por el factor de distribución. Sin embargo, la convergencia del modelo sufrió una caída significativa. Este comportamiento es consistente para los dos modelos diferentes, las diferentes instancias de cómputo, los diferentes métodos de distribución y los diferentes tipos de datos. Entonces, ¿por qué la distribución del proceso de entrenamiento afectó la precisión del modelo?
Existen varias teorías que intentan explicar este efecto:
- Cuando las actualizaciones de tensores son grandes en tamaño, el tráfico entre los trabajadores y el servidor de parámetros puede congestionarse. Por lo tanto, los servidores de parámetros asíncronos sufrirán una convergencia significativamente peor debido a retrasos en las actualizaciones de pesos [1].
- Aumentar el tamaño del lote puede llevar a un sobreajuste y una mala generalización, reduciendo así la precisión de validación [2].
- Cuando se actualizan de forma asíncrona los parámetros del modelo, algunas DNN pueden no estar utilizando los pesos del modelo más recientemente actualizados; por lo tanto, calcularán gradientes basados en pesos que están unas pocas iteraciones atrás. Esto conduce a la obsolescencia de los pesos [3] y puede ser causado por varias razones.
- Algunos hiperparámetros son específicos del modelo u optimizador. Por ejemplo, la documentación oficial de XGBoost dice que el valor “exact” para el hiperparámetro “tree_mode” no es compatible con el entrenamiento distribuido porque XGBoost utiliza la distribución de datos divididos por filas, mientras que el método de árbol “exact” funciona en un formato de columnas ordenadas.
- Algunos investigadores han propuesto que configurar un mini-lote más grande puede llevar a gradientes con menos estocasticidad. Esto puede ocurrir cuando la función de pérdida contiene mínimos locales y puntos de silla y no se realiza ningún cambio en el tamaño del paso, lo que provoca que la optimización quede atrapada en dichos mínimos locales o puntos de silla [4].
Optimizar para entrenamiento distribuido
La optimización de hiperparámetros (HPO) es el proceso de buscar y seleccionar un conjunto de hiperparámetros que sean óptimos para un algoritmo de aprendizaje. SageMaker Automatic Model Tuning (AMT) proporciona HPO como un servicio gestionado ejecutando múltiples trabajos de entrenamiento en el conjunto de datos proporcionado. SageMaker AMT busca en los rangos de hiperparámetros que especifiques y devuelve los mejores valores, medidos por una métrica que elijas. Puedes utilizar SageMaker AMT con los algoritmos integrados o utilizar tus propios algoritmos y contenedores personalizados.
Sin embargo, la optimización para entrenamiento distribuido difiere del HPO común porque en lugar de lanzar una única instancia por trabajo de entrenamiento, cada trabajo realmente lanza un clúster de instancias. Esto significa un mayor impacto en el costo (especialmente si consideras instancias aceleradas por GPU, que son típicas para DNN). Además de los límites de AMT, es posible que puedas alcanzar los límites de cuenta de SageMaker para el número concurrente de instancias de entrenamiento. Por último, lanzar clústeres puede introducir una sobrecarga operativa debido a un tiempo de inicio más largo. SageMaker AMT tiene características específicas para abordar estos problemas. Hyperband con detención temprana asegura que las configuraciones de hiperparámetros con buen rendimiento se ajusten y las que tengan un mal rendimiento se detengan automáticamente. Esto permite un uso eficiente del tiempo de entrenamiento y reduce los costos innecesarios. Además, SageMaker AMT admite completamente el uso de instancias de Amazon EC2 Spot, que pueden optimizar el costo de entrenamiento hasta en un 90% en comparación con las instancias bajo demanda. En cuanto a los tiempos de inicio prolongados, SageMaker AMT reutiliza automáticamente las instancias de entrenamiento dentro de cada trabajo de ajuste, reduciendo así el tiempo de inicio promedio de cada trabajo de entrenamiento en 20 veces. Además, debes seguir las mejores prácticas de AMT, como elegir los hiperparámetros relevantes, sus rangos y escalas adecuados, el mejor número de trabajos de entrenamiento concurrentes y establecer una semilla aleatoria para reproducir los resultados.
En la siguiente sección, veremos estas características en acción mientras configuramos, ejecutamos y analizamos un trabajo de AMT utilizando el ejemplo de XGBoost que discutimos anteriormente.
Configurar, ejecutar y analizar un trabajo de ajuste
Como mencionamos antes, el código fuente se puede encontrar en el repositorio de GitHub. En los pasos 1-5, descargamos y preparamos los datos, creamos el estimador xgb3
(el estimador distribuido de XGBoost se configura para utilizar tres instancias), ejecutamos los trabajos de entrenamiento y observamos los resultados. En esta sección, describiremos cómo configurar el trabajo de ajuste para ese estimador, asumiendo que ya has pasado por los pasos 1-5.
Un trabajo de ajuste calcula los hiperparámetros óptimos para los trabajos de entrenamiento que lanza utilizando una métrica para evaluar el rendimiento. Puedes configurar tu propia métrica, que SageMaker analizará según la expresión regular que configures y emitirá a stdout
, o utilizar las métricas de los algoritmos integrados de SageMaker. En este ejemplo, utilizamos la métrica objetivo integrada de XGBoost, por lo que no necesitamos configurar una expresión regular. Para optimizar la convergencia del modelo, optimizamos en función de la métrica de AUC de validación:
objective_metric_name="validación:auc"
Ajustamos siete hiperparámetros:
- num_round – Número de rondas para el impulso durante el entrenamiento.
- eta – Tasa de encogimiento del paso utilizada en las actualizaciones para prevenir el sobreajuste.
- alpha – Término de regularización L1 en los pesos.
- min_child_weight – Suma mínima del peso de la instancia (hessiano) necesaria en una hija. Si el paso de partición del árbol resulta en un nodo hoja con la suma del peso de la instancia menor que
min_child_weight
, el proceso de construcción se detiene. - max_depth – Profundidad máxima de un árbol.
- colsample_bylevel – Proporción de submuestreo de columnas para cada división, en cada nivel. Este submuestreo se realiza una vez por cada nuevo nivel de profundidad alcanzado en un árbol.
- colsample_bytree – Proporción de submuestreo de columnas al construir cada árbol. Para cada árbol construido, el submuestreo ocurre una vez.
Para obtener más información sobre los hiperparámetros de XGBoost, consulta los Hiperparámetros de XGBoost. El siguiente código muestra los siete hiperparámetros y sus rangos:
hyperparameter_ranges = {
"num_round": IntegerParameter(100, 200),
"eta": ContinuousParameter(0, 1),
"min_child_weight": ContinuousParameter(1, 10),
"alpha": ContinuousParameter(0, 2),
"max_depth": IntegerParameter(1, 10),
"colsample_bylevel": ContinuousParameter(0, 1),
"colsample_bytree": ContinuousParameter(0, 1),
}
A continuación, proporcionamos la configuración para la estrategia Hyperband y la configuración del objeto tuner utilizando el SDK de SageMaker. HyperbandStrategyConfig
puede utilizar dos parámetros: max_resource
(opcional) para el número máximo de iteraciones a utilizar en un trabajo de entrenamiento para alcanzar el objetivo, y min_resource
– el número mínimo de iteraciones a utilizar por un trabajo de entrenamiento antes de detener el entrenamiento. Usamos HyperbandStrategyConfig
para configurar StrategyConfig
, que luego se utiliza en la definición del trabajo de ajuste. Consulta el siguiente código:
hsc = HyperbandStrategyConfig(max_resource=30, min_resource=1)
sc = StrategyConfig(hyperband_strategy_config=hsc)
Ahora creamos un objeto HyperparameterTuner
, al cual le pasamos la siguiente información:
- El estimador XGBoost, configurado para ejecutarse con tres instancias
- El nombre y definición de la métrica objetivo
- Nuestros rangos de hiperparámetros
- Configuraciones de recursos para el ajuste, como el número total de trabajos de entrenamiento a ejecutar y cuántos trabajos de entrenamiento se pueden ejecutar en paralelo
- Configuraciones de Hyperband (la estrategia y configuración que configuramos en el paso anterior)
- Detención temprana (
early_stopping_type
) configurada comoOff
¿Por qué configuramos la detención temprana como Off? Los trabajos de entrenamiento pueden detenerse temprano cuando es poco probable que mejoren la métrica objetivo del trabajo de ajuste de hiperparámetros. Esto puede ayudar a reducir el tiempo de cálculo y evitar el sobreajuste del modelo. Sin embargo, Hyperband utiliza un mecanismo avanzado incorporado para aplicar la detención temprana. Por lo tanto, el parámetro early_stopping_type
debe configurarse como Off
al utilizar la función interna de detención temprana de Hyperband. Consulta el siguiente código:
tuner = HyperparameterTuner(
xgb3,
objective_metric_name,
hyperparameter_ranges,
max_jobs=30,
max_parallel_jobs=4,
strategy="Hyperband",
early_stopping_type="Off",
strategy_config=sc
)
Finalmente, iniciamos el trabajo de ajuste automático del modelo llamando al método fit. Si deseas lanzar el trabajo de forma asincrónica, configura wait
en False
. Consulta el siguiente código:
tuner.fit(
{"train": s3_input_train, "validation": s3_input_validation},
include_cls_metadata=False,
wait=True,
)
Puedes seguir el progreso del trabajo y obtener un resumen en la consola de SageMaker. En el panel de navegación, selecciona Entrenamiento, elige Trabajos de ajuste de hiperparámetros y luego selecciona el trabajo de ajuste relevante. La siguiente captura de pantalla muestra el trabajo de ajuste con detalles sobre el estado y el rendimiento de los trabajos de entrenamiento.
Cuando el trabajo de ajuste esté completo, podemos revisar los resultados. En el ejemplo del cuaderno, mostramos cómo extraer los resultados usando el SDK de SageMaker. Primero, examinamos cómo el trabajo de ajuste aumentó la convergencia del modelo. Puede adjuntar el objeto HyperparameterTuner
utilizando el nombre del trabajo y llamar al método describe. El método devuelve un diccionario que contiene metadatos y resultados del trabajo de ajuste.
En el siguiente código, recuperamos el valor del trabajo de entrenamiento con mejor rendimiento, medido por nuestra métrica objetivo (AUC de validación):
tuner = HyperparameterTuner.attach(tuning_job_name=tuning_job_name)
tuner.describe()["BestTrainingJob"]["FinalHyperParameterTuningJobObjectiveMetric"]["Value"]
El resultado es 0.78 en AUC en el conjunto de validación. ¡Eso es una mejora significativa sobre el 0.63 inicial!
A continuación, veamos qué tan rápido se ejecutó nuestro trabajo de entrenamiento. Para eso, usamos el método HyperparameterTuningJobAnalytics en el SDK para obtener resultados sobre el trabajo de ajuste y los leemos en un marco de datos de Pandas para su análisis y visualización:
tuner_analytics = sagemaker.HyperparameterTuningJobAnalytics(tuning_job_name)
full_df = tuner_analytics.dataframe()
full_df.sort_values(by=["FinalObjectiveValue"], ascending=False).head()
Veamos el tiempo promedio que tomó un trabajo de entrenamiento con la estrategia Hyperband:
full_df["TrainingElapsedTimeSeconds"].mean()
El tiempo promedio tomó aproximadamente 1 minuto. Esto es consistente con el mecanismo de la estrategia Hyperband que detiene los trabajos de entrenamiento que tienen un rendimiento deficiente. En términos de costos, el trabajo de ajuste nos cobró un total de 30 minutos de tiempo de entrenamiento. Sin la detención temprana de Hyperband, se esperaba que la duración total facturable del entrenamiento fuera de 90 minutos (30 trabajos * 1 minuto por trabajo * 3 instancias por trabajo). ¡Eso es tres veces mejor en ahorro de costos! Finalmente, vemos que el trabajo de ajuste se ejecutó con 30 trabajos de entrenamiento y tomó un total de 12 minutos. Eso es casi un 50% menos del tiempo esperado (30 trabajos / 4 trabajos en paralelo * 3 minutos por trabajo).
Conclusión
En esta publicación, describimos algunos problemas de convergencia observados al entrenar modelos con entornos distribuidos. Vimos que SageMaker AMT utilizando Hyperband abordó las principales preocupaciones que introdujo la optimización del entrenamiento distribuido en paralelo de datos: convergencia (que mejoró en más del 10%), eficiencia operativa (el trabajo de ajuste tomó un 50% menos de tiempo que un trabajo secuencial no optimizado habría tomado) y eficiencia de costos (30 vs. los 90 minutos facturables del tiempo de trabajo de entrenamiento). La siguiente tabla resume nuestros resultados:
Métrica de Mejora | Sin Ajuste/Implementación de Modelo de Ajuste Ingenuo | Ajuste Automático del Modelo con Hyperband de SageMaker | Mejora Medida |
Calidad del Modelo (Medido por AUC de validación) | 0.63 | 0.78 | 15% |
Costo (Medido por minutos facturables de entrenamiento) | 90 | 30 | 66% |
Eficiencia operativa (Medida por tiempo total de ejecución) | 24 | 12 | 50% |
Para ajustar con respecto a la escala (tamaño del clúster), puedes repetir el trabajo de ajuste con múltiples configuraciones de clúster y comparar los resultados para encontrar los hiperparámetros óptimos que satisfagan la velocidad y la precisión del modelo.
Incluimos los pasos para lograr esto en la última sección del cuaderno.
Referencias
[1] Lian, Xiangru, et al. “Descenso de gradiente estocástico paralelo asincrónico descentralizado”. Conferencia Internacional sobre Aprendizaje Automático. PMLR, 2018.
[2] Keskar, Nitish Shirish, et al. “Sobre el entrenamiento con lotes grandes para el aprendizaje profundo: brecha de generalización y mínimos afilados”. Preimpresión de arXiv arXiv:1609.04836 (2016).
[3] Dai, Wei, et al. “Hacia la comprensión del impacto de la obsolescencia en el aprendizaje automático distribuido”. Preimpresión de arXiv arXiv:1810.03264 (2018).
[4] Dauphin, Yann N., et al. “Identificación y ataque del problema del punto silla en la optimización no convexa de alta dimensión”. Avances en sistemas de información neural 27 (2014).