1 つまたは複数の大きなNumpy
配列に対して、多くの中間操作を実行しなければならない場合があります。これにより、すぐにMemoryError
s が発生する可能性があります。これまでの調査で、Pickling (Pickle、CPickle、Pytables など) と がgc.collect()
この問題を軽減する方法であることがわかりました。経験豊富なプログラマーが大量のデータを扱うときに使用する他のテクニックがあるかどうか疑問に思っていました (もちろん、戦略/コード内の冗長性を削除する以外に)。
また、私が確信していることが 1 つあるとすれば、無料のものなどないということです。これらのテクニックのいくつかでは、どのようなトレードオフ (速度、堅牢性など) があるのでしょうか?
ベストアンサー1
あなたの苦しみはよくわかります... 配列のサイズの数倍の値を後で破棄する値に格納してしまうことがあります。配列内の 1 つの項目を一度に処理する場合、これは無関係ですが、ベクトル化する場合、致命的になる可能性があります。
説明のために仕事からの例を使います。私は最近、説明したアルゴリズムをコーディングしました。ここnumpy を使用します。これは、RGB 画像を取得して CMYK 画像に変換するカラー マップ アルゴリズムです。ピクセルごとに繰り返されるプロセスは次のとおりです。
- 各 RGB 値の上位 4 ビットを 3 次元ルックアップ テーブルのインデックスとして使用します。これにより、LUT 内の立方体の 8 つの頂点の CMYK 値が決定されます。
- 前のステップの頂点値に基づいて、各 RGB 値の下位 4 ビットを使用してその立方体内で補間します。これを最も効率的に行うには、処理する画像のサイズの uint8 の配列 16 個を計算する必要があります。24 ビットの RGB 画像の場合、処理するには画像の 6 倍のストレージが必要になります。
これに対処するには、次の 2 つの方法があります。
1. 分割して征服する
おそらく、1,000x1,000 配列を 1 回のパスで処理することはできないでしょう。しかし、100x1,000 の配列 10 個を Python の for ループで反復処理できれば、1,000,000 項目を処理する Python 反復子よりもはるかに高速になります。確かに遅くなりますが、それほどではありません。
2. 高価な計算をキャッシュする
これは、上記の補間例に直接関係しており、見つけるのが難しいですが、注意して探す価値はあります。各次元に 4 ビットの 3 次元立方体を補間しているため、可能な結果は 16x16x16 のみで、16x16x16 バイトの 16 個の配列に格納できます。したがって、それらを事前に計算して 64KB のメモリを使用して格納し、画像全体の値を 1 つずつ検索することができます。これにより、膨大なメモリ コストですべてのピクセルに対して同じ操作をやり直す必要がなくなります。これは、64x64 ピクセルほど小さい画像に対してすでに効果を発揮しており、基本的に配列を細分化することなく、ピクセル数の 6 倍の画像を処理することができます。
dtypes
3.賢く使う
中間値が 1 つの に収まる場合はuint8
、 の配列を使用しないでくださいint32
。これは、サイレント オーバーフローによる不可解なエラーの悪夢になる可能性がありますが、注意すれば、リソースを大幅に節約できます。