🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python

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

Q&A

解決済

2回答

5657閲覧

pythonでPILを使って読み込んだ画像データをnumpyのデータに何度も変換するとメモリが足りなくなる

Amanokawa

総合スコア41

Python

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

1グッド

0クリップ

投稿2019/10/30 10:04

編集2019/11/02 00:37

1GB分の複数のjpg画像を使って繰り返し処理をするプログラムを作っています。
処理はnumpyで行うのですが、1GB分すべてをndarrayに変換すると20GB近く膨れるのでメモリに乗りません。
なので、PILを使って1GB分をImageデータとして読み込んでおき、そこから必要な分だけをnumpyデータに逐一変換する方法をとりました。
しかし、繰り返しその処理を行うとなぜかpythonがメモリを占領していきます。
使用したndarrayをdelしても変わりません。これはなぜなのでしょうか?

以下に行ったプログラムの簡単に記述しました。これを実行するとどんどん使用メモリが増えていきます。
ループを数えたところだいたい150順ぐらいで12GBを超えました。
画像はすべて10MBくらいで大きな差はありません。
hoge関数を消しても相変わらずメモリは増えるのでnumpyの変換が原因なのかと思います。

python

1# 1GB分の画像データをPILで読み込みリストに入れる 2pil_img_list = [Image.open(name) for name in img_name_list] 3 4# 繰り返し操作 5while True: 6 # ランダムに画像を選択してndarrayに変換する 7 random_index = np.random.randint(0, len(pil_img_list)) 8 numpy_data = np.array(pil_img_list[random_index]) 9 10 # 何かしらの操作 11 hoge(numpy_data) 12 13 # 一応試した変数削除 14  print("numpy_data" in globals()) # True 15 del numpy_data 16  gc.collect() 17 print("numpy_data" in globals()) # False

環境の容量の関係上あらかじめndarrayを用意することができません。
上記に似た方法で処理を行いたいと思っています、ぜひ解決策をご教示願います。

環境
・windows10, Pycharm:2019.2.3, python3.7, Pillow:6.1.0, numpy:1.16.4
・Colaboratory, Pillow:4.3.0, numpy:1.17.3

メモリに関しては知識不足で詳細にお答えすることができません。
windowsではタスクマネージャーのパフォーマンスでメモリの使用量が増えることを確認し、
Colaboratoryでは12GのRAMのすべてを使用したためクラッシュしました。

--- 解決 ---
PILオブジェクトを定期的に読み込むことで解決しました。

python

1# 繰り返し操作 2while True: 3 # 1GB分の画像データをPILで読み込みリストに入れる 4 pil_img_list = [Image.open(name) for name in img_name_list] 5 6 # あらかじめ確認したメモリリークしない100周を回す 7 for i in range(100): 8 # ランダムに画像を選択してndarrayに変換する 9 random_index = np.random.randint(0, len(pil_img_list)) 10 numpy_data = np.array(pil_img_list[random_index]) 11 12 # 何かしらの操作 13 hoge(numpy_data)
退会済みユーザー👍を押しています

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

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

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

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

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

meg_

2019/10/30 10:18

・「使用したndarrayをdelしても変わりません。」コードを掲載ください。 ・環境の情報を掲載ください。(OS、メモリ等)
退会済みユーザー

退会済みユーザー

2019/10/30 10:38

> hoge(numpy_data) これ抜きでも1GB分走査した際にメモリがいっぱいになるのでしょうか? Yesならnumpyの問題かもしれませんし、Noであればhoge(blah)の問題だと思います。 一度お確かめください。
Amanokawa

2019/10/30 11:15

hoge()抜きでもメモリは増えました。
退会済みユーザー

退会済みユーザー

2019/10/30 21:47

numpy_data = np.array(pil_img_list[np.random.randint(0, len(pil_img_list))]) のように変数の定義を減らしてはいかがでしょうか?
Amanokawa

2019/10/30 23:13

読みやすいように分けて書きましたが、定義せず実行した場合も同様に増えていきます。
guest

回答2

0

ベストアンサー

同じ問題に行き詰った方がその解決策を公開されています。

ryuoujisintaさん@Qiita

解決策:
リークする処理を回数制限付きの子プロセスに任せる。
一定回数でプロセスを閉じて次の子プロセスに任せる。

Pythonはこういうもの、かもしれません。

投稿2019/10/31 10:42

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

Amanokawa

2019/11/02 00:35 編集

回答ありがとうございます。 何がメモリを使っているのかを考えると、PILのオブジェクトなのではないかとたどり着きました。 この場合の子プロセスとはPILのオブジェクトになるので、一定期間で再読み込みさせるようコードを書き直したところ期待通りの動きをしてくれるようになりました。
guest

0

gcモジュールを使用してみてはどうでしょうか?

Python

1import gc 2 3#コード 4 5del numpy_data 6gc.collect()

明示的にガベージコレクションを行います。

投稿2019/10/30 11:35

meg_

総合スコア10736

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

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

Amanokawa

2019/10/30 11:56

試してみましたが効果がありませんでした。
meg_

2019/10/30 12:02

ループ内で生成している他の変数もGCしても未だメモリ不足でしょうか?
Amanokawa

2019/10/30 12:26

メモリ不足になります。 globals()でnumpy_dataを確認したところしっかり消えているようなので、いったいなににメモリを使っているのか不思議です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問