我需要一些帮助,因为我试了两天,我不知道怎么做到这一点。我有函数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
答案 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)]