具有多个参数

时间:2017-10-22 19:25:30

标签: python parallel-processing multiprocessing

我需要一些帮助,因为我试了两天,我不知道怎么做到这一点。我有函数compute_desc,它接受​​多个参数(确切地说是5),我希望并行运行它。 我现在有这个:

def compute_desc(coord, radius, coords, feat, verbose):
    # Compute here my descriptors
    return my_desc # numpy array (1x10 dimensions)

def main():
    points = np.rand.random((1000000, 4))
    coords = points[:, 0:3]
    feat = points[:, 3]
    all_features = np.empty((1000000, 10))
    all_features[:] = np.NAN
    scales = [0.5, 1, 2]
    for radius in scales:
        for index, coord in enumerate(coords):
            all_features[index, :] = compute_desc(coord,
                                                  radius,
                                                  coords,
                                                  feat,
                                                  False)

我想将此并行化。我看到了几个带有Pool的解决方案,但我不明白它是如何工作的。

我尝试使用pool.map(),但我只能向函数发送一个参数。

这是我的解决方案(它不起作用):

all_features = [pool.map(compute_desc, zip(point, repeat([radius, 
                                                          coords,
                                                          feat, 
                                                          False]
                                                         ) 
                                           ) 
                         )]

但我怀疑它可以使用numpy数组。

修改

这是我用池的最小代码(现在可以使用):

import numpy as np
from multiprocessing import Pool
from itertools import repeat

def compute_desc(coord, radius, coords, feat, verbose):
    # Compute here my descriptors
    my_desc = np.rand.random((1, 10))
    return my_desc

def compute_desc_pool(args):
    coord, radius, coords, feat, verbose = args
    compute_desc(coord, radius, coords, feat, verbose)

def main():
    points = np.random.rand(1000000, 4)
    coords = points[:, 0:3]
    feat = points[:, 3]
    scales = [0.5, 1, 2]
    for radius in scales:
        with Pool() as pool:
            args = zip(points, repeat(radius),
                       repeat(coords),
                       repeat(feat),
                       repeat(kdtree),
                       repeat(False))
            feat_one_scale = pool.map(compute_desc_pool, args)

        feat_one_scale = np.array(feat_one_scale)
        if radius == scales[0]:
            all_features = feat_one_scale
        else: 
            all_features = np.hstack([all_features, feat_one_scale])

    # Others stuffs

2 个答案:

答案 0 :(得分:1)

通用解决方案是传递给Pool.map 序列的元组,每个元组为您的工作函数保存一组参数,然后解压缩工人职能中的元组。

因此,只需将您的函数更改为仅接受一个参数您的参数元组,您已使用zip准备并传递给Pool.map。然后只需将args解压缩到变量:

def compute_desc(args):
    coord, radius, coords, feat, verbose = args
    # Compute here my descriptors

此外,Pool.map也应该与numpy类型一起使用,因为它们毕竟是有效的Python类型。

确保正确zip 5个序列,因此您的函数会收到5元组。您无需在point中对coords进行迭代,zip会为您执行此操作:

args = zip(coords, repeat(radius), repeat(coords), repeat(feat), repeat(False))
# args is a list of [(coords[0], radius, coords, feat, False), (coords[1], ... )]

(如果你这样做,并将point作为zip的第一个序列,zip将迭代该点,在这种情况下是一个3元素数组。

您的Pool.map行应如下所示:

for radius in scales:
    args = zip(coords, repeat(radius), repeat(coords), repeat(feat), repeat(False))
    feat_one_scale = [pool.map(compute_desc_pool, args)]
    # other stuff

针对您的案例的特定解决方案,其中除了一个以外的所有参数都可以使用functools.partial(如另一个答案所示)。此外,您甚至不需要在第一个参数中解包coords,只需传递[0..n]中的索引coords,因为您的工作函数的每次调用都已经收到完整的{{1}数组。

答案 1 :(得分:1)

我假设从你的例子中,这五个参数中的四个对于compute_desc_pool的所有调用都是不变的。如果是这样,那么您可以使用partial来执行此操作。

from functools import partial
....

def compute_desc_pool(coord, radius, coords, feat, verbose):    
    compute_desc(coord, radius, coords, feat, verbose)

def main():
    points = np.random.rand(1000000, 4)
    coords = points[:, 0:3]
    feat = points[:, 3]
    feat_one_scale = np.empty((1000000, 10))
    feat_one_scale[:] = np.NAN
    scales = [0.5, 1, 2]
    pool = Pool()
    for radius in scales:
        feat_one_scale = [pool.map(partial(compute_desc_pool, radius, coords, 
                                           feat, False), coords)]