はじめに
みなさんの現場は機械学習モデルを学習する時に
どのように行っているでしょうか?
大きなモデルになるほど学習が何日もかかるなんてことはざらだと思います。
「夜中に学習できるように設定していたけど、翌朝見たら止まってる、、、」
という惨事を経験したので、対処法を共有します。
Dockerのライフサイクル管理とプロセスの切り離しの2段構えで解決しましょう。
- シチュエーション
- VSCodeを使って開発サーバーにSSH接続している
- 学習環境が入っているコンテナを立ち上げて学習を実行する
なぜ学習が止まってしまうのか、、、
原因は主に3つのレイヤーで発生しています。
- SSH接続の切断
- VSCodeのRemote-SSHなどが切断されると、実行中のシェルに対して終了命令が送られ、プロセスが強制終了します
- VSCodeのクリーンアップ
- VSCodeを閉じるとVSCode Serverが管理している子プロセスを道連れにすることがあります
- Dockerのライフサイクル
-
--rmをつけてdocker run -itで起動している場合、操作しているシェル(メインプロセス)が終了した瞬間にコンテナ自体が削除されます
Dockerコンテナはホスト側のプロセス上で動いているので、
SSH接続が切れると、そのセッションで動いていたプロセス(Dockerを操作していたシェル)に終了信号が送られます。その結果、そのシェルに紐付いていたコンテナやプロセスが道連れになってしまうのです。
つまり、問題の本質は学習プロセスが、VSCodeのセッションと一蓮托生になっていることです。
このVSCodeとDockerの依存関係を断ち切ることで、VSCode Serverが死んでも(VSCodeを閉じても)、コンテナとPythonプロセスだけはサーバーの片隅で黙々計算させ続けるということをしたいわけです。
解決策:2段構えの切り離し運用
VSCodeのセッションが切れても学習を続行させるには、
「コンテナ」と「プロセス」のそれぞれを独立(デタッチ)させる必要があります。
ステップ1:コンテナを「デタッチモード-d」で常駐させる
まず、学習の「土台」となるコンテナを、
VSCodeの操作画面から切り離してバックグラウンドで起動します。
docker run -d \
--name my_container \
--gpus all \
-v $(pwd):/workspace \
--rm \
my_image tail -f /dev/null
-
-d: コンテナをバックグラウンドで実行します。これにより、ターミナルを閉じてもコンテナは走り続けます。動いているコンテナを確認したい時は、docker psでstatusがUPになってるかを見ます -
--rm: 学習が終わって手動でコンテナを止めた瞬間に、自動でゴミを残さず消去してくれます。 -
tail -f /dev/null: コンテナを起動し続けるためのダミーコマンドです。
デタッチモードをつけていないと、Dockerを動かしているプロセスがなくなると(VSCodeを閉じるなど)コンテナ自体なくなります。
ステップ2:docker execとnohupでプロセスを自立させる
次に、常駐しているコンテナの中に入り、学習を「投げっぱなし」にします。
# 1. 起動中のコンテナに「外」から入る
docker exec -it my_container bash
# 2. nohup を使って、セッションが切れても死なないように実行
# 標準出力とエラーを 'train.log' に書き出す
nohup python train.py > train.log 2>&1 &
-
docker exec:docker runで入るのと違い、すでに動いているコンテナにお邪魔するイメージです。もしVSCodeとの接続が切れても本体のコンテナには影響が及びません -
nohup + &:nohupは「HUPシグナル(切断通知)を無視しろ」という命令です。末尾の&でバックグラウンドに回すことで、シェルを閉じてもPythonプロセスが生き残り続けます。 -
2>&1: 「標準エラー出力も、標準出力と同じ場所(ログファイル)に書き込め」という設定です。これがないと、エラーが起きたときにログに残らず、原因不明のまま止まることになります。
この2つの設定で学習プロセスを実行することで、
SSH接続が切れても、VSCodeを閉じてしまっても問題なく学習が進んでいくことになります。
実行中の進捗確認と後片付け
プロセスをバックグラウンドに逃がした後は、進捗が気になって何度もコンテナに入りたくなりますが、その必要はありません。
状況確認するには?
tail -fを使うことでnohupで書き出したログファイルを
コンテナの外から覗き見ることができます。
# コンテナの外から、ログの末尾をリアルタイム表示
docker exec -it my_container tail -f train.log
-
tail -f: ファイルの末尾を監視し、新しい行が追加されるたびに表示を更新します。 - いつでも離脱OK:
Ctrl + Cでログの監視を止めても、学習プロセス自体は止まりません。 安心して接続を切り、ブラウザを閉じ、PCをスリープさせてください。
使い終わったコンテナはどうする?
学習が無事に終了し、ログで結果を確認したら、
最後はリソースを解放する必要があります。
今回の手順では、起動時に--rmをつけているため
以下のコマンドを打つだけで「プロセスの停止」と「コンテナの削除」が同時に完了します。
# コンテナを停止(同時に自動削除される)
docker stop my_container
※ なぜ
docker stopを使うのか?通常、
docker run -itで動かしている時はCtrl + Cやexitでコンテナを止めることが多いですが、
今回は-d(デタッチモード)で土台を固めているため、明示的に「止まれ」と命じる必要があります。
これにより、GPUメモリやシステムリソースが確実に解放され、次の実験にスムーズに移行できます。
まとめ
本記事では、機械学習モデルを学習させるときにVSCodeを閉じても、
学習を継続できる設定についてまとめました。
「数時間の計算が水の泡になる」という絶望は、
データサイエンティストの通過儀礼かもしれませんが、一度経験すれば十分です。
今回紹介した死なない土台と依存しないプロセスの運用Tipsを活用して、
心置きなくPCを閉じ、安心して朝を迎えられる環境を構築しましょう!