2015-07-13 2 views
3

Я использую разреженную обработку массива тензоров, которую я построил с использованием словарей и счетчиков в Python. Я хотел бы использовать параллельную манипуляцию массивом. Суть в том, что у меня закончилось наличие счетчиков на каждом узле, которые я бы хотел добавить вместе, используя MPI.Allreduce (или другое приятное решение). Например, с счетчиками можно сделатьСуммируя объекты Python с Allreduce MPI

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. Является ли мой лучший вариант «User-Defined Operation», или есть способ заставить Allreduce добавлять счетчики? Спасибо,

EDIT (7/14/15): Я попытался создать пользовательскую операцию для словарей, но были некоторые несоответствия. Я написал следующее

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__' так, по-видимому он хочет знать, что эти вещи словари? Как я могу сказать, что у них есть словарь типов?

+0

Вы можете превратить операцию в список понимания? – Matt

ответ

6

Ни MPI, ни MPI4py ничего не знают о счетчиках, поэтому вам нужно создать свою собственную операцию сокращения, чтобы это работало; это было бы то же самое для любого другого рода питона объекта:

#!/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 

Здесь мы сделали функцию, которая суммирует два счетчика объектов и создал оператор MPI из них с MPI.Op.Create; mpi4py будет разглаживать объекты, запустить эту функцию, чтобы объединить эти элементы в паре, затем рассортировать частичный результат и отправить его на следующую задачу.

Обратите внимание, что мы используем (нижний регистр) allreduce, который работает на произвольных объектах python, а не в верхнем регистре Allreduce, который работает на массивах numpy или их моральных эквивалентах (буферах, которые отображаются на Fortran/C массивы, для которых разработан API MPI).

Бег дает:

$ 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} 
+0

Я не вижу, как используется 'datatype '. –

+1

Это не так; он является частью API MPI, но его непросто использовать с помощью mpi4py для травления объектов Python. В принципе вы можете использовать его для выполнения различных операций с различными типами данных MPI. –

+0

Были новые разработки, см. Редактирование выше, пожалуйста, благодарю вас за помощь. –

 Смежные вопросы

  • Нет связанных вопросов^_^