Accelerate documentation

Dépannage

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v1.15.0).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Dépannage

Ce guide propose des solutions à certains problèmes que vous pourriez rencontrer lors de l’utilisation d’Accelerate. Toutes les erreurs ne sont pas couvertes, car Accelerate est une bibliothèque active qui évolue en permanence et qui présente de nombreux cas d’usage et configurations d’entraînement distribué différentes. Si les solutions décrites ici ne résolvent pas votre erreur spécifique, veuillez consulter la section Demander de l’aide pour savoir où et comment obtenir de l’aide.

Journalisation

La journalisation peut vous aider à identifier l’origine d’une erreur. Dans une configuration distribuée avec plusieurs processus, la journalisation peut s’avérer complexe, mais Accelerate fournit l’utilitaire logging() pour garantir la synchronisation des journaux.

Pour dépanner un problème, utilisez logging() à la place du module standard Python logging. Définissez le niveau de verbosité (INFO, DEBUG, WARNING, ERROR, CRITICAL) avec le paramètre log_level, puis vous pouvez soit :

  1. Exportez log_level en tant que variable d'environnement ACCELERATE_LOG_LEVEL.
  2. Passez log_level directement à get_logger.

Par exemple, pour définir log_level="INFO" :

from accelerate.logging import get_logger

logger = get_logger(__name__, log_level="DEBUG")

Par défaut, le journal est appelé uniquement sur les processus principaux. Pour l'appeler sur tous les processus, passez main_process_only=False. Si le journal doit être appelé sur tous les processus et dans l'ordre, passez également 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)

Code en attente et erreurs de délai

Il peut y avoir de nombreuses raisons pour lesquelles votre code est bloqué. Examinons comment résoudre certains des problèmes les plus courants susceptibles de provoquer ce blocage.

Formes de tenseurs non correspondantes

Les formes de tenseurs non correspondantes sont un problème courant qui peut faire en sorte que votre code reste bloqué pendant une durée significative sur une configuration distribuée.

Lors de l’exécution de scripts dans un environnement distribué, des fonctions telles que Accelerator.gather() et Accelerator.reduce() sont nécessaires pour récupérer des tenseurs sur plusieurs appareils afin d’y effectuer collectivement des opérations. Ces fonctions (et d’autres) s’appuient sur torch.distributed pour effectuer une opération de gather, qui exige que les tenseurs aient exactement la même forme sur tous les processus. Si les formes des tenseurs ne correspondent pas, votre code se bloque et finira par déclencher une exception de dépassement de délai.

Vous pouvez utiliser le mode de débogage opérationnel d’Accelerate pour détecter immédiatement ce problème. Nous recommandons d’activer ce mode lors de la configuration accelerate config, mais vous pouvez également l’activer depuis l’interface en ligne de commande, en tant que variable d’environnement, ou en modifiant manuellement le fichier config.yaml.

CLI
variable d'environnement
config.yaml
accelerate launch --debug {my_script.py} --arg1 --arg2

Une fois le mode de débogage activé, vous devriez obtenir une trace d’erreur qui pointe vers le problème d’incompatibilité des formes de tenseurs.

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]

Arrêt anticipé

Pour l’arrêt anticipé dans l’entraînement distribué, si chaque processus possède une condition d’arrêt spécifique (par exemple, la perte de validation), celle-ci peut ne pas être synchronisée entre tous les processus. En conséquence, une interruption peut se produire sur le processus 0 mais pas sur le processus 1, ce qui entraînera un blocage indéfini de votre code jusqu’à l’expiration du délai.

Si vous avez des conditions d’arrêt anticipé, utilisez les méthodes set_trigger et check_trigger pour vous assurer que tous les processus sont terminés correctement.

# 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():
    break

Versions de noyau Linux anciennes

Sur Linux avec une version du noyau < 5.5, des processus bloqués ont été signalés. Pour éviter ce problème, mettez à jour votre système vers une version de noyau plus récente.

MPI

Si votre tâche d’entraînement distribué sur CPU utilisant MPI est bloquée, assurez-vous que la configuration SSH sans mot de passe (à l’aide de clés) est en place entre les nœuds. Cela signifie que, pour tous les nœuds de votre fichier d’hôtes, vous devez pouvoir vous connecter en SSH d’un nœud à un autre sans être invité à saisir un mot de passe.

Ensuite, essayez d'exécuter la commande mpirun comme vérification de bon sens. Par exemple, la commande ci-dessous doit afficher les noms d'hôtes de chacun des nœuds.

mpirun -f hostfile -n {number of nodes} -ppn 1 hostname

Dépassement de mémoire

L’une des erreurs les plus frustrantes lors de l’exécution de scripts d’entraînement est de rencontrer une erreur « Out-of-Memory » sur des dispositifs tels que CUDA, XPU ou CPU. L’ensemble du script doit être relancé et tout le travail effectué est perdu.

Pour résoudre ce problème, Accelerate fournit l'utilitaire find_executable_batch_size(), qui s'appuie fortement sur toma. Cet utilitaire relance le code qui échoue en raison de conditions OOM (out-of-memory) et réduit automatiquement les tailles de lot. Pour chaque condition OOM, l'algorithme divise la taille de lot par deux et relance le code jusqu'à ce qu'il réussisse.

Pour utiliser find_executable_batch_size(), restructurez votre fonction d’entraînement afin d’y inclure une fonction interne avec find_executable_batch_size et construisez vos dataloaders à l’intérieur de celle-ci. À minima, cela ne nécessite que 4 nouvelles lignes de code.

La fonction interne doit prendre la taille du lot comme premier paramètre, mais nous ne lui en passons pas lors de l’appel. L’emballage s’en chargera pour vous. Tout objet (modèles, optimiseurs) qui consomme de la mémoire sur l’appareil et qui est passé à Accelerator doit également être déclaré à l’intérieur de la fonction interne.

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()

Résultats non reproductibles entre les configurations de matériel

Si vous avez modifié la configuration des appareils et que vous observez des différences de performance du modèle, il est probable que vous n’ayez pas mis à jour votre script lors du passage d’une configuration à l’autre. Même si vous utilisez le même script avec la même taille de lot, les résultats resteront différents sur un TPU, en multi-GPU et en GPU unique.

Par exemple, si vous entraînez sur un seul GPU avec une taille de lot de 16 et que vous passez à une configuration à double GPU, vous devez modifier la taille de lot à 8 pour conserver la même taille de lot effective. En effet, lors de l'entraînement avec Accelerate, la taille de lot transmise au dataloader correspond à la taille de lot par GPU.

Pour vous assurer de pouvoir reproduire les résultats entre les configurations, utilisez la même graine, ajustez la taille du lot en conséquence et envisagez d’adapter le taux d’apprentissage.

Pour plus de détails et une référence rapide sur les tailles de lot, consultez le guide Comparaison des performances entre différentes configurations d’appareils.

Problèmes de performance sur différents GPU

Si votre configuration multi-GPU est composée de GPU différents, vous pouvez rencontrer certains problèmes de performances :

  • Un déséquilibre de la mémoire GPU peut exister entre les GPU. Dans ce cas, le GPU doté de la plus petite mémoire limitera la taille du lot ou la taille du modèle qui peut être chargé sur les GPU.
  • Si vous utilisez des GPU avec des profils de performances différents, les performances seront déterminées par le GPU le plus lent que vous utilisez, car les autres GPU devront attendre qu’il ait terminé sa charge de travail.

Des GPU très différents au sein d'une même configuration peuvent entraîner des goulets d'étranglement de performance.

Demander de l'aide

Si aucune des solutions et des conseils présentés ici n'a permis de résoudre votre problème, vous pouvez toujours solliciter l'aide de la communauté et de l'équipe Accelerate.

  • Demandez de l’aide sur les forums Hugging Face en publiant votre question dans la catégorie Accelerate. Veillez à rédiger un message descriptif, avec le contexte pertinent de votre configuration et un code reproductible, afin de maximiser les chances que votre problème soit résolu !

  • Posez une question sur Discord et laissez l'équipe et la communauté vous aider.

  • Créez un Issue sur le dépôt GitHub d’Accelerate si vous pensez avoir trouvé un bug lié à la bibliothèque. Incluez un contexte sur le bug ainsi que des détails sur votre configuration distribuée pour nous aider à mieux comprendre le problème et à trouver une solution.

Update on GitHub