Code de sortie et signaux
- Code de sortie 0 : W&B considère que le run s’est terminé avec succès et ne le remet pas en file d’attente.
- Code de sortie non nul : W&B considère le run comme ayant échoué ou comme ayant été préempté. Lorsque vous utilisez
mark_preempting(), W&B remet le run en file d’attente afin qu’un autre agent (ou le même agent après redémarrage) puisse le reprendre.
sys.exit(). Il est important de comprendre ce contrat et de s’y fier dans des environnements préemptibles ou sur cluster.
Lorsque le processus se termine à cause d’un signal interceptable, votre gestionnaire peut s’exécuter, appeler wandb.run.mark_preempting() si vous souhaitez que le run soit remis en file d’attente, effectuer un nettoyage (par exemple, enregistrer un point de contrôle), puis quitter avec un code non nul. Une convention courante est sys.exit(128 + signum) pour une terminaison due à un signal. W&B enregistre ce code de sortie et les mêmes règles de remise en file d’attente s’appliquent. Lorsque le noyau du système d’exploitation tue le processus avec SIGKILL, le processus ne peut pas exécuter de hooks de sortie ; W&B n’écrit donc pas de synthèse finale, et le run peut apparaître comme planté ou tué. L’agent démarre néanmoins le run suivant.
Runs inactifs et délais d’expiration côté serveur
SIGKILL). Consignez des métriques à intervalles réguliers ou quittez avec un code de sortie explicite afin que l’état de l’exécution reflète bien ce qui s’est passé.
Signaux interceptables et préemption
- Enregistrez les gestionnaires le plus tôt possible (par exemple, avant d’entrer dans la boucle principale d’entraînement).
- Dans le gestionnaire, appelez
wandb.run.mark_preempting()si vous souhaitez que le run soit remis en file d’attente après une préemption, effectuez les opérations de nettoyage (par exemple, enregistrez un checkpoint), puis quittez avec un code non nul.
SIGUSR1 (un signal de préemption de cluster courant) et SIGTERM. Il laisse SIGINT libre pour une utilisation interactive (par exemple, une annulation manuelle depuis le terminal). Le gestionnaire appelle wandb.run.mark_preempting() et quitte avec 128 + signum :
SIGKILL (impossible à intercepter)
SIGKILL provient du noyau du système d’exploitation et ne peut être ni intercepté ni ignoré. Le processus se termine immédiatement, sans possibilité d’exécuter des gestionnaires de signal ou des rappels atexit. W&B ne peut pas écrire de résumé final pour le run. L’agent récupère malgré tout et poursuit le balayage, mais les données de ce run sont incomplètes. Utilisez SIGKILL uniquement en dernier recours. Privilégiez SIGTERM ou SIGINT lorsque vous avez besoin d’un arrêt propre.
Transmission des signaux de l’agent au processus enfant
wandb agent, l’agent exécute votre script d’entraînement en tant que processus enfant. Lorsque vous interrompez l’agent (par exemple avec Ctrl+C, ou lorsqu’un ordonnanceur envoie SIGTERM au job), le processus enfant (processus d’entraînement) ne reçoit pas le signal par défaut. Le script d’entraînement ne peut donc pas exécuter son gestionnaire ni appeler mark_preempting(). Pour plus d’informations, voir wandb GitHub issue #3667.
Pour permettre au processus enfant de s’arrêter proprement et d’appeler wandb.run.mark_preempting() dans un gestionnaire, exécutez l’agent CLI avec --forward-signals :
wandb.agent() dans l’API Python. Ce mode d’exécution lance votre fonction d’entraînement dans un thread, et non dans un processus enfant distinct, donc le même comportement de transmission ne s’applique pas.
Lorsque l’agent CLI reçoit SIGINT ou SIGTERM avec la transmission activée, il relaie le signal au processus enfant. Le gestionnaire de votre script d’entraînement peut alors s’exécuter, appeler wandb.run.mark_preempting() et wandb.finish() avec un code de sortie non nul si nécessaire, puis se terminer avec un code non nul. Si vous appuyez deux fois sur Ctrl+C sur le processus de l’agent, l’agent reçoit SIGTERM par défaut. Avec --forward-signals, l’agent peut transmettre SIGINT au processus enfant pour que votre gestionnaire s’exécute.
Pour plus d’informations, voir la référence CLI wandb agent.
Clusters préemptibles comme SLURM
- Lorsque l’ordonnanceur envoie le signal à l’agent : exécutez l’agent avec
wandb agent --forward-signalsafin que, lorsque l’ordonnanceur (ou l’utilisateur) envoie un signal à l’agent, l’agent le transmette au processus enfant. Le gestionnaire du processus enfant peut alors appelerwandb.run.mark_preempting(),wandb.finish(exit_code=...)avec un code non nul, puissys.exit(128 + signum)(ou un autre code de sortie non nul). - Lorsque l’ordonnanceur envoie le signal au script de lancement (et non directement à l’agent) : faites en sorte que le script de lancement envoie le signal de préemption directement au processus d’entraînement. Par exemple, le script d’entraînement écrit son ID de processus dans un fichier. Le script de lancement intercepte le signal du cluster (par exemple
SIGUSR1) et exécutekill -SIGUSR1 $(cat $PID_FILE)afin que le gestionnaire du processus d’entraînement s’exécute.
SIGTERM ou SIGUSR1). Dans le gestionnaire, appelez wandb.run.mark_preempting() si un run est actif, puis terminez le run avec un code de sortie non nul et sys.exit(128 + signum) (ou un autre code non nul) afin que W&B remette le run en file d’attente. Pour plus d’informations sur le moment où W&B remet les runs en file d’attente et sur l’interaction avec mark_preempting(), voir Resume preemptible balayage runs.
État du balayage : exécutez wandb sweep entity/project/sweep_ID --resume avant de démarrer l’agent afin que le balayage soit en mode reprise et attribue les runs remis en file d’attente.
Coordination multi-agent : lorsque plusieurs agents s’exécutent en même temps (comme dans des jobs de tableau SLURM), ils peuvent entrer en concurrence pour récupérer le même run préempté. Il s’agit d’une limitation connue. Pour contourner ce problème, décalez le démarrage des agents ou utilisez des mécanismes de coordination externes, comme des verrous.
Pour les jobs SLURM multi-GPU où un seul processus doit appeler wandb.agent(), voir How should I run sweeps on SLURM?.
wandb sweep --cancel
--cancel interagit avec les signaux et les processus enfants, car l’annulation se comporte différemment de l’envoi direct d’un signal du système d’exploitation. Vous annulez un balayage à l’aide de l’API W&B, et non avec un signal du système d’exploitation. Exécutez une commande comme wandb sweep --cancel entity/project/sweep_ID. Le serveur demande à l’agent de quitter, puis l’agent termine les processus enfants en cours d’exécution et s’arrête. Il peut s’écouler un court délai (de l’ordre de l’intervalle d’interrogation de l’API par l’agent) avant que l’annulation ne prenne effet.
L’annulation envoie SIGKILL aux runs. Les processus enfants n’ont aucune possibilité d’exécuter des gestionnaires de signaux définis par l’utilisateur. Il en va de même lorsque vous utilisez le contrôle Cancel dans l’UI de balayage. Utilisez --cancel lorsque vous voulez arrêter l’ensemble du balayage et le marquer comme annulé. Pour arrêter proprement le run en cours, envoyez un signal interceptable au run (ou utilisez --forward-signals avec l’agent CLI et envoyez le signal à l’agent). Pour terminer proprement un balayage, utilisez plutôt wandb sweep --stop que --cancel.
Pour plus d’informations sur les options de mise en pause, de reprise, d’arrêt et d’annulation, voir Gérer les balayages.
Signaux envoyés à l’agent ou au run
--forward-signals avec l’agent CLI, l’arrêt de l’agent ne garantit pas l’arrêt du processus enfant d’entraînement.
Pour vérifier que l’agent s’est arrêté, utilisez une commande du système d’exploitation comme ps -p [AGENT-PID] ou pgrep -f "wandb agent" au lieu de vous fier à l’apparition du prompt.
Référence : mark_preempting() et l’état final du run
mark_preempting() et de la façon dont le processus se termine. Il suppose que vous utilisez la CLI wandb agent avec votre programme d’entraînement comme sous-processus.
Si vous appelez
mark_preempting() uniquement dans un gestionnaire de signal, vous ne couvrez pas les cas où ce gestionnaire n’est jamais exécuté, comme avec SIGKILL.
Si vous appelez toujours mark_preempting() immédiatement après wandb.init(), W&B peut traiter tout échec comme une préemption et pourrait remettre le run en file d’attente de manière répétée, y compris en cas de bug ou de mauvaise configuration.
Pour les environnements avec un signal de préemption bien défini, l’approche habituelle consiste à utiliser un gestionnaire de signal qui appelle mark_preempting() et quitte avec un code non nul, plutôt qu’un appel inconditionnel après init().