5

Python で辞書とカウンターを使用して作成したスパース テンソル配列操作を使用しています。この配列操作を並行して使えるようにしたいです。肝心なのは、MPI.Allreduce (または別の優れたソリューション) を使用して一緒に追加したい各ノードにカウンターを配置することになったことです。たとえば、カウンターを使用すると、これを行うことができます

A = Counter({a:1, b:2, c:3})
B = Counter({b:1, c:2, d:3})

そのような

C = A+B = Counter({a:1, b:3, c:5, d:3}).

これと同じ操作を行いたいのですが、関連するすべてのノードを使用して、

MPI.Allreduce(send_counter, recv_counter, MPI.SUM)

ただし、MPI は辞書/カウンターでこの操作を認識していないようで、エラーがスローされますexpecting a buffer or a list/tuple。私の最善の選択肢は「ユーザー定義操作」ですか、それとも Allreduce にカウンターを追加させる方法はありますか? ありがとう、

編集 (2015 年 7 月 14 日): 辞書のユーザー操作を作成しようとしましたが、いくつかの矛盾がありました。私は次のように書いた

def dict_sum(dict1, dict2, datatype):
    for key in dict2:
        try:
            dict1[key] += dict2[key]
        except KeyError:
            dict1[key] = dict2[key]

そして、関数についてMPIに話したとき、私はこれをしました:

dictSumOp = MPI.Op.Create(dict_sum, commute=True)

そして、コードではそれを次のように使用しました

the_result = comm.allreduce(mydict, dictSumOp)

しかし、それは投げunsupported operand '+' for type dictました。だから私は書いた

the_result = comm.allreduce(mydict, op=dictSumOp)

そして今、それはdict1[key] += dict2[key] TypeError: 'NoneType' object has no attribute '__getitem__' どうやらそれらが辞書であることを知りたがっているようです。型辞書があることをどのように伝えますか?

4

1 に答える 1

7

MPI も MPI4py も特にカウンターについて何も知らないため、これを機能させるには独自のリダクション操作を作成する必要があります。これは、他の種類の python オブジェクトでも同じです。

#!/usr/bin/env python
from mpi4py import MPI
import collections

def addCounter(counter1, counter2, datatype):
    for item in counter2:
        counter1[item] += counter2[item]
    return counter1

if __name__=="__main__":

    comm = MPI.COMM_WORLD

    if comm.rank == 0:
        myCounter = collections.Counter({'a':1, 'b':2, 'c':3})
    else:
        myCounter = collections.Counter({'b':1, 'c':2, 'd':3})


    counterSumOp = MPI.Op.Create(addCounter, commute=True)

    totcounter = comm.allreduce(myCounter, op=counterSumOp)
    print comm.rank, totcounter

ここでは、2 つのカウンター オブジェクトを合計する関数を取得し、それらから MPI.Op.Create を使用して MPI オペレーターを作成しました。mpi4py はオブジェクトを unpickle し、この関数を実行してこれらのアイテムをペアごとに結合し、部分的な結果を pickle して次のタスクに送ります。

また、numpy 配列またはそれらと同等のもの (バッファー、MPI APIに設計されています)。

実行すると次のようになります。

$ mpirun -np 2 python ./counter_reduce.py 
0 Counter({'c': 5, 'b': 3, 'd': 3, 'a': 1})
1 Counter({'c': 5, 'b': 3, 'd': 3, 'a': 1})

$ mpirun -np 4 python ./counter_reduce.py 
0 Counter({'c': 9, 'd': 9, 'b': 5, 'a': 1})
2 Counter({'c': 9, 'd': 9, 'b': 5, 'a': 1})
1 Counter({'c': 9, 'd': 9, 'b': 5, 'a': 1})
3 Counter({'c': 9, 'd': 9, 'b': 5, 'a': 1})

そして、わずかな変更だけで、一般的な辞書で機能します。

#!/usr/bin/env python
from mpi4py import MPI

def addCounter(counter1, counter2, datatype):
    for item in counter2:
        if item in counter1:
            counter1[item] += counter2[item]
        else:
            counter1[item] = counter2[item]
    return counter1

if __name__=="__main__":

    comm = MPI.COMM_WORLD

    if comm.rank == 0:
        myDict = {'a':1, 'c':"Hello "}
    else:
        myDict = {'c':"World!", 'd':3}

    counterSumOp = MPI.Op.Create(addCounter, commute=True)

    totDict = comm.allreduce(myDict, op=counterSumOp)
    print comm.rank, totDict

ランニングギビング

$ mpirun -np 2 python dict_reduce.py 
0 {'a': 1, 'c': 'Hello World!', 'd': 3}
1 {'a': 1, 'c': 'Hello World!', 'd': 3}
于 2015-07-13T16:54:22.103 に答える