質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.32%
PyTorch

PyTorchは、オープンソースのPython向けの機械学習ライブラリ。Facebookの人工知能研究グループが開発を主導しています。強力なGPUサポートを備えたテンソル計算、テープベースの自動微分による柔軟なニューラルネットワークの記述が可能です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

1回答

573閲覧

Pythonで外部ライブラリを実行中にctrl+Cで正常終了したい

kkjiji

総合スコア42

PyTorch

PyTorchは、オープンソースのPython向けの機械学習ライブラリ。Facebookの人工知能研究グループが開発を主導しています。強力なGPUサポートを備えたテンソル計算、テープベースの自動微分による柔軟なニューラルネットワークの記述が可能です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

1グッド

2クリップ

投稿2025/03/04 12:20

編集2025/03/10 11:47

実現したいこと

Pythonでmain処理が書いているmain.pyファイルで外部ライブラリを実行中、Ctrl+Cでmain.pyのexceptで処理できるようにしたいです。
ただし、外部ライブラリは変更せずmain.pyのみで対処したいです。

発生している問題・分からないこと

pytorchを使ってAIモデルを学習している際に、pytorchの外部ライブラリを参照しに行きます。
その際にCtrl+Cを実行すると

(略) KeyboardInterrupt

となってしまい、Ctrl+Cの入力は認識していますがコマンドプロンプトが固まってしまいます。

この問題をtyr exceptで囲んでいるmain.pyファイルで正常に処理したいです。

エラーが確認されているソースコード
pytorch github
上記URLの131行目、class DataLoaderを使っているときにエラーが発生します。

(追記)
上記DataLoaderを読み込むとき、

python

1trainloader = torch.utils.data.DataLoader( 2 train_dataset, 3 batch_size=batch_size, 4 shuffle=config.TRAIN.SHUFFLE and train_sampler is None, 5 num_workers=config.WORKERS, 6 pin_memory=True, 7 drop_last=True, 8 sampler=train_sampler)

のように書きますが、num_workersが0のときは正常にexcept KeyboardInterruptできます。
num_workersを2より大きくすると、コマンドプロンプトが固まります。
num_workersの値分、バッチ処理が裏に走るようで複数バッチ処理が走っている場合にctrl+Cをするとすべてのバッチ処理を止めることができず、フリーズするようです。

該当のソースコード

特になし

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果
  • signalを使ってCtrl+Cの入力を拒否しようとしてもclass DataLoaderを参照中はCtrl+Cの入力を認識しており、コマンドプロンプトが固まる

→signal.signal(signal.SIGINT, signal.SIG_IGN)

◯自分の見解

  • 参照しているclass DataLoaderはmultiprocessingが走っておりmain.pyとは別のプロセスが走っていることが原因だと考えている。

pytorch github

signal.signal(signal.SIGINT, signal.SIG_IGN)した場合、メインとなるプロセスのCtrl+Cは無視することができてもmultiprocessingのサブプロセスは無視することができないと思っている。

ただ、外部ライブラリのファイルを変更せずにmain.pyからの処理だけで正常に処理する方法が分からず苦戦している。

補足

  • 業務PC

→Windows11/python 3.13.2/cmd.exe/PyTorch 2.5/CUDA version 11.8/num_workers 2~4で検証

  • 自宅PC

→Windows11/python 3.12.9/cmd.exe/PyTorch 2.5/CUDA version 12.6/num_workers 2~4で検証

teamikl👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hiroki-o

2025/03/04 13:44

タグにPythonを追加して、Pythonのバージョンと動かしているOSを「質問を編集して」追記すると、回答が得られる可能性が高まると思います。
kkjiji

2025/03/04 13:57 編集

タグの変更ってあとからも可能なのでしょうか? →タグの変更と内容の編集できました。。。 Python3.xを選んだつもりでしたが、Pythonistaになってますね。 前にも同じようになっていたのでバグなのでしょうか。。。
teamikl

2025/03/07 07:25 編集

幾つか問題点かなと思う候補はあるのですが、 問題を再現できる最小限の完全なコードの提示、もしくは Linux 環境での挙動の確認はできますか? DataLoader のサブプロセス ワーカーは 親プロセスを監視して、親プロセスが終了していれば サブプロセスも作業ループを抜けて終了する、という意図のコードが見られます XXXX: windows では、メインプロセスの生存チェックが機能してない可能性があります。 → 訂正: windows では別コードで対応されてました 他には、Ctrl-C 後に実行されるコードでのデッドロック等も、 質問の情報からは解りませんが可能性としては考えられます。(現状の質問の情報だけでは解りません)
kkjiji

2025/03/07 12:19

回答ありがとうございます。 Linuxで挙動確認してみました。 Windowsと固まるタイミング(学習が始まる直前)で、同じようにLinuxでもCtrl+Cを押してみると固まることなくコマンド使うことできました。 コマンド入力できるまで少しラグがあるので、裏でマルチプロセスを抜けているかもしれません。 上記検証からなにかわかることありますでしょうか??
teamikl

2025/03/07 14:57 編集

タイミングに関しては正確に把握してないので、該当するかどうかわからないけど DataLoader でのワーカー(サブプロセス)の稼働中であれば https://github.com/pytorch/pytorch/blob/main/torch/utils/data/dataloader.py DataLoader のデストラクタで呼ばれるメソッド _shutdown_workers の windows でのシグナル周りの挙動の違い コメントの FIXME: Unfortunately, for Windows, ~ 辺りが抵触しそうです。SIGCHLDがwindowsでは未サポートで、 シグナルハンドラでのワーカー側プロセスの終了を検知出来ない。 順当な解決策は、windows 用の代替処理を実装して github に PR だと思います (追記: 選択枝としては、wsl / docker 上に構築した posix 準拠の環境上で実行も) 一時的な回避策については検討の余地があるかも知れませんが、フリーズ状態だけ解消しても不十分で マルチプロセスでの正常終了(正しいリソース開放も含む)となると、 より詳細なデバッグ情報が必要です。→ エラーログの詳細、略されている部分。 問題の再現がこちらでも出来れば、他の案もあるかもしれません。 マルチプロセスでのフリーズしそうな個所・解消方法にはいくつか心当たり有りますが、 DataLoader のコードを読んでも候補が複数あるので、 実際に止まってる場所がどこか解らないことには、解消法の提案(回答)ができません。 問題を再現できる最小限の実行可能なコード・テスト用のデータの提示はできますか?
kkjiji

2025/03/08 02:42 編集

回答遅くなりすみません。 業務用のPCで開発を行っており、コードを展開することが難しかったです。 再現できるようなコードを作ろうとサンプルプログラムを作っていたのですが、自前のPCで実行するとCtrl+Cで正常に抜けることができ、再現することができませんでした。 現状Ctrl+Cでコマンドプロンプトが固まるタイミングの詳細を記載します。 なにか解決策の糸口がわかればご教授いただけると幸いです。 ===以下、考察=== 正常にループを抜けられないタイミングはDataLoaderにセットしたデータを取得するタイミングだと思っています。 https://github.com/chenjun2hao/DDRNet.pytorch/blob/main/tools/train.py 上記はgithubで展開されているコードです。 行137 trainloader = torch.utils.data.DataLoader でloaderをを読み込みますが、loaderにセットするdatasetは自作で作っています。 (Augmentationなど自作で実装するため) https://zenn.dev/a5chin/articles/original_data datasetを自作する場合、上記サイトにあるようにdef __getitem__とdef __len__の関数を必ず作る必要があります。(from torch.utils.data import Datasetを継承している) https://github.com/chenjun2hao/DDRNet.pytorch/blob/main/lib/core/function.py datasetからデータを取り出す際は上記サイトの行58 for i_iter, batch in enumerate(trainloader, 0): のタイミングに__getitem__が呼び出されて、画像を取得することになると思っています。 loaderのnum_workerを4とかにセットしてマルチプロセスを実行する際に、 上記のfor i_iter, batch in enumerate(trainloader, 0): でデータを取得する際にCtrl+Cを押すとコマンドプロンプトが固まります。 逆にそれ以外の場所でCtrl+Cを押しても現状コマンドプロンプトは固まることはありません。 上記のような現象から自作のdatasetが原因ではないかと思ってきました。 他に必要な関数や抜けるために必要な処理が必要になりそう感じなのでしょうか。。 (色々と考察していただいた上に、コード提出できず分かりづらい文章上での説明になってしまいすみません。) === 追記分 === 色々試してみたところ、ctrl+Cでコマンドプロンプトは固まるタイミングはimport torchなどライブラリをimportしているタイミングではないかと思いました。 ◯ファイル構成 ・メインの処理:main.py ・pytorchの学習関連:pipeline.py(pytorch_pipelineというクラスを作成) main.pyでpipeline.pyをpytorch_pipelineをimportして学習を行っています。 そのさい、loaderのnum_workerを4などに設定してマルチプロセスを実行すると、 新たにmain.py、pipeline.pyがnum_workerに設定した値分ロードされていました。 そのためimport torchなども4回呼ばれています。 私のPCのスペックが足りないのか、import torchを4回もしていると5,6秒時間がかかります。 このタイミングでctrl+Cでキャンセルとコマンドプロンプトが固まります。 おそらく原因はマルチプロセス中のライブラリimport中にプロセスをキャンセルされると正常にプロセスが抜けられないことではないかと思いました。 なにか解決の参考になりましたらと思い、追記させてもらいます。
teamikl

2025/03/08 05:33

確認です。 業務用のPCで検証したコードは業務用のコードで、問題が発生(フリーズ)あり 自前のPCで検証したのは、当たらに作成した別のサンプルコードで、問題は再現しなかった、という理解でよいですか? 後、以下の情報を質問へ追記という形で更新お願いします。(他の方へもわかりやすいように) 確認点2: 業務・自宅環境での pytorch の種類 cuda version の違い。 確認点3: シグナル周りの扱いだと、「コマンドプロンプト」の詳細 cmd, powershell, IDE 他 ---- 以下の考察について >DataLoaderにセットしたデータを取得するタイミングだと思っています。 >自作のdatasetが原因ではないかと思ってきました。 >ctrl+Cでコマンドプロンプトは固まるタイミングはimport torchなどライブラリをimportしているタイミングではないかと思いました。 第三者視点だと、他にも色々と実際のコードで確認しないと解らない点があって、 こちらの環境で問題を再現できない事には、問題個所の絞り込みは出来ません。 例えば、回答に挙げた例では signal.signal(signal.SIGINT, signal.SIG_IGN) の有無や書いた場所 >サブプロセスは無視することができないと思っている が、意図せずに 実はサブプロセス側にも設定されてたという事もあり得ます (サブプロセスでもモジュールの再読み込みが発生する為、グローバルのコードも実行される) import時Ctrl-Cはこれから見てみますが、前者(DataLoader)は回答に記載した通り、 SIGINT無視の設定を試して、Ctrl-C のタイミング次第ではエラーがでたりでなかったり、 自分でも何度か試しましたが、フリーズ状態の完全な再現は出来てません。 python 3.13/cmd.exe/PyTorch 2.6/CUDA version 12.6/num_workers 2~4で検証 よくある問題では部分的な抜粋で済む場合もありますが、 〇〇と思っていたが実は△△といったケースは、問題の絞り込みが出来ないので まずは、自身の環境で「問題を再現できる(必須)」「最小限のコード」を作ってみましょう。 クリーンな環境が用意できるなら(venvでも可) ライブラリのインストールするコマンドも含めて。 追記: pytorch の github issue で windows での Ctrl-C 問題を探してみましたが、 現行のバージョンでは見当たりませんでした。過去のバージョン(1.x)では DataLoader で同様の報告有。 → 業務環境の PyTorch の version も要確認
teamikl

2025/03/08 06:27

>そのためimport torchなども4回呼ばれています。 >私のPCのスペックが足りないのか、import torchを4回もしていると5,6秒時間がかかります。 main.pyが再評価されるのは、Windosでは正常な挙動です。(Linuxでは通常設定ではされません) Linux ではプロセスがコピーされる(fork) が、Windows では新しいインタプリタを起動し __name__ == '__mp_main__' で main.py を再実行 (spawn) 対策としては、グローバルで全てのモジュールの読み込みは行わず、 main関数内 (if __name__ == '__main__': から呼び出される場所) から 必要なモジュールのみを読み込むことで、不要なモジュールの読み込みを減らすことができます。
kkjiji

2025/03/08 11:03

毎度ご丁寧な回答ありがとうございます。 確認1:検証コードについて →ご質問の通り、業務用のコードとは別に新たにサンプルコードを作成しましたが問題を再現できなかったということであっています。 確認2,3については確認して追記しておきます。 月曜日までには確認します。 ご指摘の通り問題を再現できる最小限のサンプルコード作れるか再度試してみます。 また、マルチプロセスのWindowsでの挙動は正常とのことで理解しました。 色々と勉強不足ですみません。 まずは問題を再現できるようにコード作成してみます。
teamikl

2025/03/08 13:18

再現できなかったという事は、コードの問題なのか、環境の違いの問題なのか 先にそこの切り分けからですね。⇒ 新たに作成したサンプルコードを業務環境で実行して検証 コマンドプロンプト環境の違いでも SIGINT の扱いで違いがあるので注意。 > マルチプロセスのWindowsでの挙動 ドキュメントの該当箇所を示しておくと multiprocessing コンテキストと開始方式 https://docs.python.org/ja/3.13/library/multiprocessing.html#contexts-and-start-methods python の windows でのマルチプロセスは、起動方式の仕組みの違いを把握してないと コードが意図通りの挙動になってない場合があるので、この辺もコードの全容が必要な理由の一つです。
guest

回答1

0

signal.signal(signal.SIGINT, signal.SIG_IGN)した場合、メインとなるプロセスのCtrl+Cは無視することができてもmultiprocessingのサブプロセスは無視することができないと思っている。

DataLoader のworker_init_fn 引数でサブプロセス側の初期化時に関数を呼び出すことができて、
そのなかで signalハンドラの設定が可能です。

(条件・追記: Windows のように、サブプロセスが spawn 方式の起動であれば)
モジュールのトップレベルで呼び出すことでサブプロセス側のシグナルも設定できます。

マルチプロセスで稼働させる場合、マルチプロセスのガイドラインに沿ったコードでないと
意図しない挙動に見舞われる場合があります。
(現状掲載されてる質問の部分的なコードでは情報不足で、プログラム全容の情報が必要)

例えば、モジュールのトップレベルで signal.signal(signal.SIGINT, signal.SIG_IGN)とされていた場合、
サブプロセスのワーカーでも同様のシグナルハンドラが設定される為、
小プロセスでも KeyboardInterrupt が投げられない → ワーカーの作業ループが抜けられなくて
フリーズする等のケースも考えられます。

https://github.com/pytorch/pytorch/blob/main/torch/utils/data/_utils/worker.py

python

1# def _worker_loop(...): 2 3 try: 4 while watchdob.is_alive(): # 親プロセスが生存している間 5 ... 6 except KeyboardInterrupt: 7 # Main process will raise KeyboardInterrupt anyways. 8 pass 9 ...

SIGINT を無視してない場合は、ワーカーのループは Ctrl-C で正常に終了できるはずです。
上述したように、プログラムの全容が解らないと、メインプロセスのみ設定したつもりのハンドラが
サブプロセスにも設定されていたという事があるかもしれません。(第三者視点では確証出来ない情報→コードが必要)

https://github.com/pytorch/pytorch/blob/main/torch/utils/data/dataloader.py

python

1 2# class DataLoader(...): 3 4 def _shutdown_workers(self): 5 try: 6 ... 7 for w in self._workers: 8 w.join(timeout=...) # 子プロセスの完了を待つ、長引く場合はタイムアウト 9 ... 10 finally: 11 ... 12 for w in self._workers: 13 if w.is_alive(): 14 w.terminate() # 状況次第でデッドロックの可能性 15 16 17 def __del__(self): 18 self._shutdown_workers() 19

Process terminated
警告~~プロセスが終了してしまうと他のプロセスのデッドロックの原因になるでしょう。

https://docs.python.org/ja/3.13/library/multiprocessing.html#multiprocessing.Process.terminate

ライブラリ側のコードが except KeyboardInterrupt でワーカーのループを抜けることを期待しているので
ユーザ側のコードで expect KeyboardInterrupt と捕捉してしまうと、意図しない挙動になったり、

また、Ctrl-C が押されるタイミングによっても挙動が変わってくるため、
どんなコードでどのタイミングでCtrl-C を押したか等の正確な情報が必要です。

全ての可能性を列挙するのは現実的ではないし、問題箇所を絞り込むには情報不足ですが、
把握できる範囲で解決策もしくはフリーズ状態の回避に繋がりそうな対策


解決策・選択肢として提案できるのは、回答として期待するエラー自体の解決にならないかもしれないけど

  • wsl / docker 上の posix 準拠環境で実行する
  • windows 環境下では num_workers=0 で利用する

プリーズ状態を回避するだけであれば、SIGINT の無視はせずに、
シグナルハンドラ内で 終了 sys.exit するなど。


プログラミングガイドライン¶
multiprocessing を使用するときに守るべき一定のガイドラインとイディオム

https://docs.python.org/ja/3.13/library/multiprocessing.html#multiprocessing-programming

windows でマルチプロセスの場合は、挙動が異なる点が多いので特に注意。
※ URLの文書内の「フリーズ」は、exe化の意図で使われてます。今回の質問のフリーズとは関係なし。

投稿2025/03/07 18:05

編集2025/03/09 05:57
teamikl

総合スコア8811

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.32%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問