0

Pythonでマルチプロセッシングモジュールを使用して類似性行列を見つけるためにコードを並列化しようとしています。小さなnp.ndarrayを10 X 15要素で使用するとうまく動作します。しかし、私がnp.ndarrayを3613 X 7040の要素にスケールすると、システムのメモリが不足します。Pythonマルチプロセッシングプールが使用されているときにシステムのメモリが不足していますか?

以下は私のコードです。

import multiprocessing 
from multiprocessing import Pool 
## Importing Jacard_similarity_score 
from sklearn.metrics import jaccard_similarity_score 

# Function for finding the similarities between two np arrays 
def similarityMetric(a,b): 
    return (jaccard_similarity_score(a,b)) 

## Below functions are used for Parallelizing the scripts 
# auxiliary funciton to make it work 
def product_helper1(args): 
    return (similarityMetric(*args)) 

def parallel_product1(list_a, list_b): 
    # spark given number of processes 
    p = Pool(8) 
    # set each matching item into a tuple 
    job_args = getArguments(list_a,list_b)  
    # map to pool 
    results = p.map(product_helper1, job_args) 
    p.close() 
    p.join() 
    return (results) 

## getArguments function is used to get the combined list 
def getArguments(list_a,list_b): 
    arguments = [] 
    for i in list_a: 
     for j in list_b: 
      item = (i,j) 
      arguments.append(item) 
    return (arguments) 

次のコードを実行すると、システムのメモリが不足してハングアップします。私はPythonで、このモジュールを使用して、私が間違っているつもりかを理解しようとしているに新しいですサイズで2 numpy.ndarrays testMatrix1とtestMatrix2(3613、7040)

resultantMatrix = parallel_product1(testMatrix1,testMatrix2) 

を渡しています。どんな助けもありがとうございます。

+0

'getArguments'は、2つの行列の可能なすべての行のリストを作成します。つまり、' 3613 * 3613'の項目です。私のマシンでは、数GBのRAMが必要です。 'itertools.product(list_a、list_b)'を代わりに使うようにしてください。これは必要に応じてペアを生成し、一度にすべてをメモリに格納する必要はありません。 –

答えて

1

奇数は、コンビナトリアル爆発だけです。メインプロセスのすべてのペアをライブで生成するのではなく、前もって実現するようにしているので、膨大な量のメモリを格納しています。 ndarray sがPythonのfloatなるdouble値が含まれていると仮定すると、getArgumentsによって返さlistのメモリ使用量はおおよそペアごとtupleと2 float Sのコスト、または約です:私の64で

3613 * 7040 * (sys.getsizeof((0., 0.)) + sys.getsizeof(0.) * 2) 

これは、Py3では約2.65 GBのRAM、Py2では約2.85 GBのRAMを意味します。

あなたは発電機を使用してストリーミング方式でデータを処理できる場合は、引数はいい加減に生産され、不要になると、廃棄されているので、あなたはおそらく大幅にメモリ使用量を減らすことができる:

import itertools 

def parallel_product1(list_a, list_b): 
    # spark given number of processes 
    p = Pool(8) 
    # set each matching item into a tuple 
    # Returns a generator that lazily produces the tuples 
    job_args = itertools.product(list_a,list_b)  
    # map to pool 
    results = p.map(product_helper1, job_args) 
    p.close() 
    p.join() 
    return (results) 

をこれはまだすべてが必要です結果は記憶に収まる。 product_helperfloatを返す場合、64ビットマシン上のresultlistの予想されるメモリ使用量は依然として約0.75GB程度になります。結果がストリーミング形式で処理できる場合は、p.imapまたはそれ以上の結果を反復するp.imap_unordered(後者は、ジェネレータが引数を生成した順序ではなく、計算結果として結果を返します)をディスクに書き込むか、メモリにすぐに解放されると、たくさんのメモリが節約されます。次のように出力するだけですが、ファイルに書き換え可能な形式で書き込むことも妥当でしょう。

def parallel_product1(list_a, list_b): 
    # spark given number of processes 
    p = Pool(8) 
    # set each matching item into a tuple 
    # Returns a generator that lazily produces the tuples 
    job_args = itertools.product(list_a,list_b)  
    # map to pool 
    for result in p.imap_unordered(product_helper1, job_args): 
     print(result) 
    p.close() 
    p.join() 
+0

ありがとうございました。あなたが示唆したようにitertoolsを使ってみましたが、少なくともシステムのメモリが不足していません。プログラムの完了にどれくらいの時間がかかったか教えていただけますか?マルチプロセシングモジュールを使用せずにresultsMatrix(出力)を生成するには、55分かかります。私は並列化しようとすると、1時間以上が経過していて、まだ64ビット8コアマシンで動作しています。このモジュールを使用するための重要な前提条件が不足している場合は、教えてください。 – Jessa

+0

私は 'R'で同様の問題が発生しました。私はdoParとforeachパッケージを使用して、プログラムの実行時間を数時間から '5分'にしました。私はGoogleでいくつかのブログを見てきました。PythonのマルチプロセッシングモジュールはRのforeachと似ています。Pythonで同じものを使用している間に重要な情報が欠けているのでしょうか? – Jessa

0

map方法は、プロセス間通信を介して、作業者へのすべてのデータを送信します。現在行われているようあなたが

を送っているので、これは私がそれを組み合わせる必要がマトリックス中指標のタプルのリストを作成するgetArgumentsを変更することをお勧め何を、資源の膨大な量を消費します。これは、行列の2つの行ではなく、ワーカープロセスに送信する必要がある2つの数値です。各作業者は、使用するマトリックスの行を認識します。

の2つの行列をロードしての前にmapと呼び出す前にロードします。この方法ではすべてのワーカーがアクセスできます。また、ワーカーで変更されていない限り、OSの仮想メモリマネージャーは同じメモリページをコピーせず、メモリ使用量を抑えます。

関連する問題