終了ステータスとシグナル
- 終了コード 0: run は正常に完了したと見なされ、キューに入れ直されません。
- 0 以外の終了コード: run は失敗またはプリエンプトされたものとして扱われます。
mark_preempting()を使用すると、W&B は run をキューに入れ直し、別の agent (または再起動後の同じ agent) が再開できるようにします。
sys.exit() 呼び出しによって終了した場合のいずれにも当てはまります。プリエンプト可能な環境やクラスター 環境では、この取り決めを理解し、それに基づいて動作することが極めて重要です。
プロセスが 捕捉可能な シグナル によって終了する場合、ハンドラ内で必要な処理を実行できます。run をキューに入れ直したい場合は wandb.run.mark_preempting() を呼び出し、クリーンアップ (たとえば checkpoint の保存) を行ったうえで、0 以外のコードで終了します。一般的な慣例は、シグナルによる終了時に sys.exit(128 + signum) を使用することです。W&B はその終了コードを記録し、同じ キューに入れ直しのルール が適用されます。プロセスが SIGKILL によってオペレーティングシステムのカーネルに kill された場合、プロセスは終了フックを実行できないため、最終的な summary は書き込まれず、run は crashed または killed として表示されることがあります。それでも、agent は次の run を開始します。
応答のない run とサーバー側のタイムアウト
SIGKILL の後) によく発生します。一定の間隔でメトリクスをログするか、明示的な終了コードで終了すると、実際に起きたことと run の状態を一致させやすくなります。
捕捉可能なシグナルとプリエンプション
- ハンドラーは早い段階で登録してください (たとえば、メインのトレーニングループに入る前) 。
- ハンドラー内では、プリエンプション後に run をキューに入れ直す場合は
wandb.run.mark_preempting()を呼び出し、クリーンアップ (たとえば checkpoint の保存) を行ってから、非ゼロのコードで終了してください。
SIGUSR1 (クラスター で一般的なプリエンプションシグナル) と SIGTERM のハンドラーを登録します。SIGINT は対話的な用途 (たとえば、ターミナルからの手動キャンセル) のために使えるよう残しています。ハンドラーは wandb.run.mark_preempting() を呼び出し、128 + signum を使って終了します:
SIGKILL (捕捉不可)
SIGKILL は捕捉も無視もできません。プロセスは即座に終了するため、ハンドラーや atexit コールバックを実行する余地はありません。W&B はその run の最終 summary を書き込めません。agent は復旧して引き続き sweep を継続しますが、その run のデータは不完全になります。SIGKILL の使用は最後の手段にとどめ、正常にシャットダウンする必要がある場合は SIGTERM または SIGINT を優先してください。
agent から子プロセスへのシグナル転送
wandb agent CLI を使用すると、agent はトレーニングスクリプトを子プロセスとして実行します。agent を中断しても (たとえば Ctrl+C を押した場合や、スケジューラがジョブに SIGTERM を送信した場合) 、既定では 子プロセス (トレーニングプロセス) にそのシグナルは渡されません。そのため、トレーニングスクリプトはハンドラを実行したり、mark_preempting() を呼び出したりできません。これは GitHub #3667 で説明されています。
子プロセスが正常にシャットダウンし、ハンドラ内で wandb.run.mark_preempting() を呼び出せるようにするには、CLI agent を --forward-signals 付きで実行します。
wandb.agent() では、シグナル転送はサポートされていません。この経路ではトレーニング関数は独立した子プロセスではなくスレッド内で実行されるため、同じ転送動作は適用されません。
転送を有効にした CLI agent が SIGINT または SIGTERM を受信すると、そのシグナルを子プロセスに中継します。これによりトレーニングスクリプトのハンドラーが実行され、必要に応じて wandb.run.mark_preempting() と、非ゼロの終了コードを指定した wandb.finish() を呼び出し、非ゼロコードで終了できます。agent プロセスで Ctrl+C を 2 回押すと、デフォルトでは agent は SIGTERM を受信します。--forward-signals を使用すると、SIGINT を子プロセスに転送してハンドラーを実行できます。
詳しくは、wandb agent CLI リファレンスを参照してください。
SLURM のようなプリエンプト可能なクラスター
- スケジューラがagentにシグナルを送る場合:
wandb agent --forward-signalsを指定してagentを実行してください。これにより、スケジューラ (またはユーザー) がagentにシグナルを送信したとき、そのシグナルが子プロセスに転送されます。すると子プロセスのハンドラでwandb.run.mark_preempting()、非ゼロコードを指定したwandb.finish(exit_code=...)、およびsys.exit(128 + signum)(または別の非ゼロ終了コード) を呼び出せます。 - スケジューラが起動スクリプトにシグナルを送る場合 (agentに直接送らない場合) : 起動スクリプトからプリエンプトシグナルをトレーニングプロセスに直接送るようにしてください。たとえば、トレーニングスクリプトが自分のプロセス ID をファイルに書き込み、起動スクリプトがクラスターのシグナル (たとえば
SIGUSR1) を捕捉してkill -SIGUSR1 $(cat $PID_FILE)を実行すれば、トレーニングプロセスのハンドラが実行されます。
SIGTERM または SIGUSR1) のハンドラを登録してください。ハンドラ内では、run がアクティブなら wandb.run.mark_preempting() を呼び出し、その後、run がキューに入れ直されるよう非ゼロの終了コードで run を終了し、sys.exit(128 + signum) (または別の非ゼロコード) を実行してください。run がいつキューに入れ直されるか、およびそれが mark_preempting() とどう関係するかについては、プリエンプト可能な Sweeps の run を再開するを参照してください。
Sweep の状態: agentを起動する前に wandb sweep entity/project/sweep_ID --resume を実行し、sweep を再開モードにして、キューに入れ直された run が割り当てられるようにしてください。
複数agentの協調: 多数のagentが同時に実行される場合 (SLURM の array job など) 、同じプリエンプト済み run の取得を競合することがあります。これは既知の制限事項です。この問題を回避しやすくするため、agentの起動タイミングをずらすか、lock などの外部協調メカニズムを使用してください。
wandb sweep --cancel
wandb sweep --cancel entity/project/sweep_ID のようなコマンドを実行してください。サーバーが agent に終了を指示し、その後 agent は実行中の子プロセスを終了して停止します。キャンセルが有効になるまで、短い遅延 (agent の API ポーリング間隔と同程度) が生じることがあります。
キャンセルでは、run に SIGKILL が送られます。子プロセスは、ユーザー定義のシグナルハンドラーを実行する機会がありません。これは、Sweeps UI の Cancel コントロールを使用した場合も同様です。sweep 全体を停止してキャンセル済みとしてマークしたい場合は、--cancel を使用してください。現在の run を正常終了させるには、run に捕捉可能なシグナルを送ります (または、CLI agent で --forward-signals を使用し、agent にシグナルを送ります) 。sweep を正常に完了させるには、--cancel ではなく wandb sweep --stop を使用してください。
一時停止、再開、停止、キャンセルのオプションについては、Manage sweeps を参照してください。
agent の終了と run の終了
--forward-signals を使用しない限り、agent を停止しても子のトレーニングプロセスが停止するとは限りません。
agent が終了したことを確認するには、プロンプトが表示されるかどうかで判断するのではなく、ps -p <agent_pid> や pgrep -f "wandb agent" のような OS コマンドを使用してください。
参照: mark_preempting() と最終的な run の状態
mark_preempting() をいつ呼び出すかと、プロセスがどのように終了するかに応じて、run の状態がどうなるかをまとめたものです。これは、トレーニングプログラムをサブプロセスとして wandb agent CLI を使用することを前提としています。
| シナリオ | mark_preempting() なし | シグナルハンドラが mark_preempting() を呼び出して非ゼロで終了 | init() の直後に常に mark_preempting() を呼び出す |
|---|---|---|---|
| run が終了コード 0 で正常に完了する | FINISHED | FINISHED | FINISHED |
| run が非ゼロの終了コードで失敗する | FAILED | FAILED | PREEMPTED |
run が SIGKILL を受信する | 約 5 分後に CRASHED | 約 5 分後に CRASHED (捕捉不可) | 約 5 分後に PREEMPTED |
run が SIGINT を受信する | KILLED | PREEMPTED (SIGINT ハンドラがある場合) | PREEMPTED |
run が別のシグナル (たとえば SIGTERM や SIGUSR1) を受信する | 約 5 分後に CRASHED | PREEMPTED (対応するハンドラがある場合) | 約 5 分後に PREEMPTED |
mark_preempting() をシグナルハンドラ内でしか呼び出さない場合は、SIGKILL のようにハンドラがまったく実行されないケースをカバーできません。
wandb.init() の直後に常に mark_preempting() を呼び出すと、あらゆる失敗がプリエンプションとして扱われる可能性があり、bug や不適切な設定が原因の場合でも、run が繰り返しキューに入れ直されることがあります。
プリエンプションシグナルが明確に定義されている環境では、一般的には mark_preempting() を呼び出して非ゼロで終了するシグナルハンドラを使用し、init() の直後に無条件で呼び出すことはしません。