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

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

詳細はこちら
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

3回答

15926閲覧

メモリエラーの回避方法

dream-20xx

総合スコア17

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

1グッド

0クリップ

投稿2019/09/27 08:08

編集2019/09/27 09:11

質問内容

2つの2次元配列の演算においてメモリエラーが発生いたしました。
配列の要素数が多すぎてメモリ不足になることが原因だと思いますが、
PCのメモリを増やす以外で解決方法はありますでしょうか?

以下にサンプルコードを示します。
aの配列が1以上のときはbの配列の値にし、aの配列が0のときは0にするという処理です。
np.whereのところでメモリエラーが発生いたします。

大変お手数ですが、ご回答頂けると助かります。

試したこと

OpenCVに変更して試してみましたが、同じくメモリエラーとなりました。

サンプルコード

Python

1import numpy as np 2 3np.random.seed(0) 4a = np.round(np.random.rand(50000, 50000) * 10) 5b = np.round(np.random.rand(50000, 50000) * 10) 6 7b = np.where(a >= 1, b, 0) # ここで「MemoryError」

サンプルコード(OpenCV)

Python

1import numpy as np 2import cv2 3 4np.random.seed(0) 5a = np.round(np.random.rand(50000, 50000) * 10) 6b = np.round(np.random.rand(50000, 50000) * 10) 7 8ret, a = cv2.threshold(a, 1, 1, cv2.THRESH_BINARY) # ここで「cv::OutOfMemoryError」 9b = a * b
退会済みユーザー👍を押しています

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

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

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

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

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

guest

回答3

0

20000 * 20000 * 32 / 8 = 1.6GBの配列を複数同時に確保しようとしています。
np.uint8を使えば1/4に抑えられますが。。
メモリは何GBのPCを使っていますか?

基本的にはそれだけの大きさの配列は同時に確保せず、分割して計算したほうがいい気がします。
どういった用途でのコードでしょうか?

投稿2019/09/27 09:00

fukatani

総合スコア626

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

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

dream-20xx

2019/09/27 09:08

ご回答ありがとうございます! メモリは16Gです。あと、すみません、配列数を間違っていました。修正いたしました(20000→50000)。申し訳ございません。 用途は、衛星画像データの処理になりますが、詳細は話せませんが、サンプルコードのように、aの配列が1以上のときはbの配列の値にし、aの配列が0のときは0にするという処理が必要です。 そうですね、分割した方がよい気がしています。ループ処理になるかと思いますが、速度が極端に遅くなる懸念があり、今のところ試していません。
fukatani

2019/09/27 09:16

メモリをそれだけ使うと、キャッシュミスが起きたり確保に時間がかかったりして、むしろループを書くより遅いかもしれないです。10とか100ずつ分割してみてはどうでしょう? あとは画像を圧縮して小さくするという方向性もあるとは思います。 あるいは、ゼロの成分が非常に多いならスパース行列を使うのも手です。ただ、提示していただいたコードだと非ゼロ成分がかなり多そうなので無理そうです。
dream-20xx

2019/09/29 15:18

ありがとうございます!スパース行列も念のため試してみます。
guest

0

round で整数に丸めているので、int32 型にキャストしてはどうでしょうか。
そうすれば、a, b に必要なメモリ使用量は半分になります。

python

1np.random.seed(0) 2a = np.round(np.random.rand(20000, 20000) * 10).astype(np.int32) 3b = np.round(np.random.rand(20000, 20000) * 10).astype(np.int32) 4 5b = np.where(a >= 1, b, 0)

投稿2019/09/27 08:16

tiitoi

総合スコア21956

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

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

dream-20xx

2019/09/27 08:32

早速のご回答ありがとうございます! 試してみましたが、私の環境ではまだメモリエラーとなります。。
tiitoi

2019/09/27 08:34

np.int32 のところを np.int16 にすれば、さらに使用量を半分に減らせます。 メモリは何GBあるのでしょうか? またPython の実行環境はどのようになっているのでしょうか?
dream-20xx

2019/09/27 08:47

はい、np.int16もすでに試していましたがメモリエラーでした。np.int8は実データの範囲に収まらないので意味はないですが、一応やってみたところnp.int8もメモリエラーでした。 PCのメモリは16Gあります。 あと、すみません、サンプルコードの要素数を実ソースに比べてかなり少なく書いていました。修正(20000→50000)しました。申し訳ございません。
tiitoi

2019/09/27 08:52

50000*50000 の2次元配列は密行列でしょうか? もしそうだとすると、一般的なPCで扱うには規模が大きすぎるように思えます。 int16 でも1つの配列5G、int32なら10Gとなり、メモリ16Gではとても足りません。 扱う配列が疎行列 (配列のほとんどの値は0) などの性質はないのでしょうか?
dream-20xx

2019/09/27 09:03

地球観測衛星画像データを扱っており、密行列か疎行列かは場合によります。海が多いときは疎行列になりますが、そうでない場合は密行列になります。密行列と考えてもらって差し支えありません。そうですよね、とても足りないですよね。。
tiitoi

2019/09/27 09:08 編集

メモリ増設が選択肢にないならば、以下のように、一度に計算するのではなく、部分的に計算していくしかないと思います。 50000x50000 の配列を縦横10分割して、100個の5000x5000の配列にして、HDD に一旦保存する。 分割した配列に対して、演算して結果をまたHDDに保存する。
tiitoi

2019/09/27 09:11 編集

8Gのメモリボードをあと2枚挿せば足りそうな気もしますが、増設しないのであれば、データすべてを一度に扱うことがメモリ不足の原因なので、HDDを利用して、配列全体がメモリ上に展開されないようにする以外解決方法はないように思います。
dream-20xx

2019/09/27 09:13

ありがとうございます。今から所用があり、月曜日に実装してみます。処理速度が実用に耐えうるかどうかが懸念事項です。
guest

0

自己解決

遅くなり申し訳ございません。
以下のように分割して処理することで解決しました。
お二人とも正しい回答を頂いたので、お二人ともにプラス評価をいたしました。
本当ははじめの方にベストアンサーにしようと思ったのですが、ここに書いたらできないのですね。。
初心者で申し訳ございません。。

python

1import numpy as np 2 3np.random.seed(0) 4a = np.round(np.random.rand(50000, 50000) * 10).astype(np.uint16) 5b = np.round(np.random.rand(50000, 50000) * 10).astype(np.uint16) 6 7tmp = [] 8num = 10 # 配列を10分割 9a_split = np.split(a, num) 10b_split = np.split(b, num) 11 12for i in range(num): 13 tmp.append(np.where(a_split[i] >= 1, b_split[i], 0)) 14 15b = np.array(tmp, dtype='uint16').reshape(50000, 50000)

投稿2019/10/07 07:09

編集2019/10/07 07:12
dream-20xx

総合スコア17

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問