Accelerate documentation
Solución de problemas
Solución de problemas
Esta guía ofrece soluciones a algunos problemas que podrías encontrar al usar Accelerate. No se cubren todos los errores, ya que Accelerate es una biblioteca activa que evoluciona continuamente y existen muchos casos de uso y configuraciones de entrenamiento distribuido diferentes. Si las soluciones descritas aquí no te ayudan con tu error específico, consulta la sección Solicitar ayuda para saber dónde y cómo obtener asistencia.
Registro
El registro de eventos puede ayudar a identificar de dónde proviene un error. En una configuración distribuida con múltiples procesos, el registro puede ser un desafío, pero Accelerate proporciona la utilidad logging() para garantizar que los registros estén sincronizados.
Para solucionar un problema, use logging() en lugar del módulo estándar de Python logging. Establezca el nivel de detalle (INFO, DEBUG, WARNING, ERROR, CRITICAL) con el parámetro log_level y luego puede:
- Exporta
log_levelcomo la variable de entornoACCELERATE_LOG_LEVEL. - Pase
log_leveldirectamente aget_logger.
Por ejemplo, para establecer log_level="INFO":
from accelerate.logging import get_logger
logger = get_logger(__name__, log_level="DEBUG")Por defecto, el registro se llama solo en los procesos principales. Para llamarlo en todos los procesos, pase main_process_only=False.
Si el registro debe llamarse en todos los procesos y en orden, pase también in_order=True.
from accelerate.logging import get_logger
logger = get_logger(__name__, log_level="DEBUG")
# log all processes
logger.debug("thing_to_log", main_process_only=False)
# log all processes in order
logger.debug("thing_to_log", main_process_only=False, in_order=True)Código colgado y errores de tiempo de espera
Puede haber muchas razones por las que tu código se queda colgado. Veamos cómo resolver algunos de los problemas más comunes que pueden causar que tu código se quede colgado.
Formas de tensor no coincidentes
Las formas de tensor no coincidentes son un problema común que puede hacer que tu código se quede colgado durante un tiempo significativo en una configuración distribuida.
Al ejecutar scripts en una configuración distribuida, funciones como Accelerator.gather() y Accelerator.reduce() son necesarias para obtener tensores entre dispositivos y realizar operaciones sobre ellos de forma colectiva. Estas (y otras) funciones dependen de torch.distributed para realizar una operación de gather, lo que requiere que los tensores tengan la misma forma exacta en todos los procesos. Si las formas de los tensores no coinciden, el código se bloquea y finalmente se producirá una excepción de tiempo de espera.
Puede usar el modo de depuración operativa de Accelerate para detectar este problema de inmediato. Recomendamos habilitar este modo durante la configuración de accelerate config, pero también puede activarlo desde la CLI, como variable de entorno o editando manualmente el archivo config.yaml.
accelerate launch --debug {my_script.py} --arg1 --arg2Si habilita el modo de depuración como variable de entorno, no necesita llamar a accelerate launch.
ACCELERATE_DEBUG_MODE="1" torchrun {my_script.py} --arg1 --arg2Agrega debug: true a tu archivo config.yaml.
compute_environment: LOCAL_MACHINE
debug: trueUna vez que habilites el modo de depuración, deberías obtener un seguimiento de errores que señale el problema de incompatibilidad de forma de tensor.
Traceback (most recent call last):
File "/home/zach_mueller_huggingface_co/test.py", line 18, in <module>
main()
File "/home/zach_mueller_huggingface_co/test.py", line 15, in main
broadcast_tensor = broadcast(tensor)
File "/home/zach_mueller_huggingface_co/accelerate/src/accelerate/utils/operations.py", line 303, in wrapper
accelerate.utils.operations.DistributedOperationException:
Cannot apply desired operation due to shape mismatches. All shapes across devices must be valid.
Operation: `accelerate.utils.operations.broadcast`
Input shapes:
- Process 0: [1, 5]
- Process 1: [1, 2, 5]Detención temprana
Para el early stopping en el entrenamiento distribuido, si cada proceso tiene una condición de parada específica (p. ej., la pérdida de validación), es posible que no esté sincronizada entre todos los procesos. Como resultado, puede producirse un break en el proceso 0 pero no en el proceso 1, lo que hará que tu código se quede colgado indefinidamente hasta que se produzca un timeout.
Si tiene condiciones de parada anticipada, use los métodos set_trigger y check_trigger para asegurarse de que todos los procesos terminen correctamente.
# Assume `should_do_breakpoint` is a custom-defined function that returns a conditional,
# and that conditional might be true only on process 1
if should_do_breakpoint(loss):
accelerator.set_trigger()
# Later in the training script when we need to check for the breakpoint
if accelerator.check_trigger():
breakVersiones de kernel bajas en Linux
En Linux con versión de kernel < 5.5, se han reportado procesos colgados. Para evitar este problema, actualice su sistema a una versión de kernel posterior.
MPI
Si tu trabajo de entrenamiento distribuido en CPU usando MPI se queda colgado, asegúrate de que tienes configurado SSH sin contraseña (usando claves) entre los nodos. Esto significa que, para todos los nodos de tu hostfile, debes poder iniciar sesión SSH desde un nodo a otro sin que se te pida una contraseña.
A continuación, intente ejecutar el comando mpirun como comprobación de sanidad. Por ejemplo, el comando siguiente debería imprimir los nombres de host de cada uno de los nodos.
mpirun -f hostfile -n {number of nodes} -ppn 1 hostnameMemoria insuficiente
Uno de los errores más frustrantes al ejecutar scripts de entrenamiento es encontrarse con “Out-of-Memory” en dispositivos como CUDA, XPU o CPU. Todo el script debe reiniciarse y se pierde todo el progreso.
Para abordar este problema, Accelerate ofrece la utilidad find_executable_batch_size(), que se basa en gran medida en toma. Esta utilidad reintenta el código que falla debido a condiciones de OOM (falta de memoria) y reduce automáticamente los tamaños de lote. Para cada condición de OOM, el algoritmo reduce el tamaño del lote a la mitad y reintenta el código hasta que tenga éxito.
Para usar find_executable_batch_size(), reestructura tu función de entrenamiento para incluir una función interna con find_executable_batch_size y crea tus dataloaders dentro de ella. Como mínimo, esto solo requiere 4 líneas de código nuevas.
La función interna debe recibir el tamaño del lote como primer parámetro, pero no le pasamos ninguno al llamarla. El envoltorio se encargará de esto por ti. Cualquier objeto (modelos, optimizadores) que consuma memoria de dispositivo y se pase al Accelerator también debe declararse dentro de la función interna.
def training_function(args):
accelerator = Accelerator()
+ @find_executable_batch_size(starting_batch_size=args.batch_size)
+ def inner_training_loop(batch_size):
+ nonlocal accelerator # Ensure they can be used in our context
+ accelerator.free_memory() # Free all lingering references
model = get_model()
model.to(accelerator.device)
optimizer = get_optimizer()
train_dataloader, eval_dataloader = get_dataloaders(accelerator, batch_size)
lr_scheduler = get_scheduler(
optimizer,
num_training_steps=len(train_dataloader)*num_epochs
)
model, optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare(
model, optimizer, train_dataloader, eval_dataloader, lr_scheduler
)
train(model, optimizer, train_dataloader, lr_scheduler)
validate(model, eval_dataloader)
+ inner_training_loop()Resultados no reproducibles entre configuraciones de dispositivos
Si modificaste la configuración de dispositivos y observas un rendimiento diferente del modelo, es probable que no hayas actualizado tu script al pasar de una configuración a otra. Incluso si usas el mismo script con el mismo tamaño de lote, los resultados seguirán siendo diferentes en un TPU, en una configuración multi-GPU y en una GPU única.
Por ejemplo, si estabas entrenando en una sola GPU con un tamaño de lote de 16 y pasas a una configuración de doble GPU, necesitas cambiar el tamaño de lote a 8 para mantener el mismo tamaño de lote efectivo. Esto se debe a que, al entrenar con Accelerate, el tamaño de lote que se pasa al dataloader es el tamaño de lote por GPU.
Para asegurarse de poder reproducir los resultados entre las configuraciones, utilice la misma semilla, ajuste el tamaño del lote en consecuencia y considere escalar la tasa de aprendizaje.
Para más detalles y una referencia rápida sobre los tamaños de lote, consulte la guía Comparación del rendimiento entre diferentes configuraciones de dispositivos.
Problemas de rendimiento en diferentes GPUs
Si su configuración de múltiples GPU consta de GPUs diferentes, es posible que se encuentre con algunos problemas de rendimiento:
- Es posible que exista un desequilibrio en la memoria de GPU entre las distintas GPUs. En este caso, la GPU con menor memoria limitará el tamaño del lote o el tamaño del modelo que se puede cargar en las GPUs.
- Si está utilizando GPUs con perfiles de rendimiento diferentes, el rendimiento estará determinado por la GPU más lenta que esté utilizando, ya que las demás GPUs tendrán que esperar a que complete su carga de trabajo.
Las GPU muy diferentes dentro de la misma configuración pueden provocar cuellos de botella de rendimiento.
Pide ayuda
Si ninguna de las soluciones y consejos de aquí te ayudó a resolver tu problema, siempre puedes contactar a la comunidad y al equipo de Accelerate para obtener ayuda.
Pide ayuda en los foros de Hugging Face publicando tu pregunta en la categoría de Accelerate. Asegúrate de escribir una publicación descriptiva con el contexto relevante sobre tu configuración y código reproducible para maximizar la probabilidad de que tu problema se resuelva.
Publica una pregunta en Discord y deja que el equipo y la comunidad te ayuden.
Crea un Issue en el repositorio de GitHub de Accelerate si crees que has encontrado un error relacionado con la biblioteca. Incluye contexto sobre el error y detalles sobre tu configuración distribuida para ayudarnos a identificar mejor qué está fallando y cómo podemos solucionarlo.