Распараллелить метод расчета расстояния с многопроцессорной обработкой

Этот вопрос связан с другим, который я опубликовал несколько дней назад; Я прочитал этот вопрос о проблеме, связанной с multiprocessing травлением с помощью методов экземпляра. Проблема в том, что я не понял, как применить предоставленное решение к моему случаю:

def _pickle_method(method):
    # Author: Steven Bethard
    # http://bytes.com/topic/python/answers/552476-why-cant-you-pickle-instancemethods
    func_name = method.im_func.__name__
    obj = method.im_self
    cls = method.im_class
    cls_name = ''
    if func_name.startswith('__') and not func_name.endswith('__'):
        cls_name = cls.__name__.lstrip('_')
    if cls_name:
        func_name = '_' + cls_name + func_name
    return _unpickle_method, (func_name, obj, cls)

def _unpickle_method(func_name, obj, cls):
    # Author: Steven Bethard
    # http://bytes.com/topic/python/answers/552476-why-cant-you-pickle-instancemethods
    for cls in cls.mro():
        try:
            func = cls.__dict__[func_name]
        except KeyError:
            pass
        else:
            break
    return func.__get__(obj, cls)

copy_reg.pickle(types.MethodType, _pickle_method, _unpickle_method)

class Circle(Feature):
# Stuff...
    def __points_distance(self,points):
        xa = n.array([self.xc,self.yc]).reshape((1,2))
        d = n.abs(dist.cdist(points,xa) - self.radius)
        return d

def points_distance(self,points,pool=None):
    if pool:
        return pool.map(self.__points_distance,points)
    else:
        return self.__points_distance(points)

Это дает ValueError: XA must be a 2-dimensional array ошибку при запуске:

import tra.features as fts
import numpy as np
import multiprocessing as mp

points = np.random.random(size=(1000,2))
circle_points = np.random.random(size=(3,2))

feature = fts.Circle(circle_points)

pool = mp.Pool()
ds = feature.points_distance(points,pool=pool)

но это (очевидно) работает при выполнении:

pool = None
ds = feature.points_distance(points,pool=pool)

Любые подсказки?

Это отличается от этого (я проверил эта реализация), потому что этот метод используется внутри другого класса, который создает экземпляр класса Circle и вызывает его метод points_distance. В любом случае другое отличие заключается в том, что метод points_distance использует scipy.spatial.distance.cdist, который ожидает (n,2)-образное numpy.ndarray. Это работает при использовании последовательной версии, но вызывает исключение, о котором я упоминал, при параллельном использовании. Я полагаю, что есть оговорка о передаче аргументов с помощью cPickle.


person rdbisme    schedule 11.07.2015    source источник
comment
@Пользователь спасибо за помощь. Я уже проверил предоставленный вами ответ, но на данный момент он у меня не работает.   -  person rdbisme    schedule 11.07.2015


Ответы (3)


Массив points, который вы передаете pool.map, имеет вид (1000, 2). Когда pool.map разбивает его для передачи в качестве аргумента points в __points_distance, этот массив имеет только форму (2,).

Попробуйте добавить points.shape = (1, 2) в тело __points_distance перед вызовом cdist.

person codewarrior    schedule 15.07.2015
comment
Я немного новичок в многопроцессорной обработке, но похоже, что то, как он разбивает ваш (1000, 2) массив на тысячу (2,) массивов, не является хорошим использованием возможностей numpy. Может быть, есть способ, скажем, разбить массив (1000000, 2) на тысячу (1000, 2) массивов и отправить каждый из них рабочему. - person codewarrior; 15.07.2015
comment
Я предполагаю, что очевидный способ - изменить points на (10, 100, 2), а затем vstack результаты вместе.... - person codewarrior; 15.07.2015
comment
Это хороший момент. Я очень беспокоюсь, что это нужно делать вручную, используя multiprocessing.Queue и multiprocessing.Process. Я думаю, что я немного жду, возможно, других ответов. Спасибо за вашу помощь. - person rdbisme; 15.07.2015
comment
Вероятно, решением может быть предварительное разделение массива перед передачей его pool.map, а затем вставка фрагментов в список. Скажем, используя numpy.split. - person rdbisme; 15.07.2015
comment
Я думаю, что вы немного далеки от своего первоначального вопроса;) - person codewarrior; 15.07.2015

Я думаю, что здесь довольно много путаницы, поэтому я не уверен, что понимаю проблему.

Исключение NameError: global name 'pool' is not defined связано не с проблемой травления, а с проблемой области видимости.

Метод не может найти pool в своей области. Попробуйте исправить это, передав ссылку pool методу.

Другая вещь:

pool = mp.Pool(mp.cpu_count())

Вызов cpu_count() является избыточным, поскольку пул уже порождает столько рабочих процессов, сколько ЦП у вас есть по умолчанию.

person noxdafox    schedule 15.07.2015
comment
спасибо за Ваш ответ. Я решил проблему с областью действия, но получаю другое исключение, связанное с scipy.spatial.distance.cdist. Если вы хотите, вы можете отредактировать свой ответ, если знаете, что происходит. - person rdbisme; 15.07.2015
comment
Я бы предпочел, чтобы вы закрыли этот вопрос как решенный и открыли новый, где вы объясните новую проблему, с которой столкнулись. Поскольку другие люди могут прочитать этот вопрос, им будет проще иметь отдельный контекст. - person noxdafox; 15.07.2015

Переменная pool определена вне класса Circle, поэтому points_distance() will be unable to findpool` в своем пространстве имен:

Добавьте конструктор в Circle или Feature, который принимает pool, и передайте пул, который вы хотите использовать, в RansacFeature, который, как я предполагаю, создает для вас экземпляры Circle.

person knite    schedule 16.07.2015