简体   繁体   English

使用多处理嵌套循环

[英]Nested for loops using multiprocessing

I have a quick question regarding multiprocessing in python. 我有一个关于python中多处理的快速问题。

I am conducting a rather large grid search over three parameters and the computation is taking ~14 hours to complete. 我正在对三个参数进行相当大的网格搜索,计算需要大约14个小时才能完成。 I would like to shrink this run time down by using multiprocessing. 我想通过使用多处理来减少运行时间。

A very simplified example of my code is here: 我的代码的一个非常简化的示例在这里:

import numpy as np
import pickle
import time

a_range = np.arange(14, 18, 0.2)
b_range = np.arange(1000, 5000, 200)
c_range = np.arange(12, 21, .5)

a_position = range(len(a_range))
b_position = range(len(b_range))
c_position = range(len(c_range))

data_grid = np.zeros([len(a_range), len(b_range), len(c_range)])
record_data = []

start_time = time.time()

for (a,apos) in zip(a_range, a_position):
    for (b, bpos) in zip(b_range, b_position):
        for (c, cpos) in zip(c_range, c_position):
            example = a+b+c  #The math in my model is much more complex and takes
            #about 7-8 seconds to process
            data_grid[apos, bpos, cpos] = example
            record_data.append([a, b, c, example])

with open('Test_File', 'wb') as f: 
    pickle.dump(record_data, f) 

np.save('example_values', data_grid) 

print 'Code ran for ', round(time.time()-start_time,2), ' seconds'

Now, I have absolutely zero experience in multiprocessing so my first attempt at this was changing the for loops into a function and then calling the multiprocessing function like this: 现在,我在多处理方面的经验绝对为零,因此我的第一个尝试是将for循环更改为一个函数,然后像这样调用多处理函数:

def run_model(a, b, c, apos, bpos, cpos):
    example=a+b+c  
    data_grid[apos, bpos, cpos]=example
    record_data.append([a, b, c, example])

from multiprocessing import Pool

if __name__=='__main__':
    pool=Pool(processes=4)
    pool.map(run_model, [a_range, b_range, c_range, a_position, b_positon, c_positon])
    pool.close()
    pool.join()

This failed however at the pool.map call. 但是,这在pool.map调用中失败了。 I understand this function only takes a single iterable argument but I don't know how to fix the problem. 我知道此函数仅接受一个可迭代的参数,但不知道如何解决该问题。 I am also skeptical that the data_grid variable is going to be filled correctly. 我也对data_grid变量是否正确填充表示怀疑。 The result I want from this function is two files saved, one as an array of values whose indexes correspond to a, b, and c values and the last a list of lists containing the a, b, c values and the resulting value (example in the code above) 我要从此函数获得的结果是保存了两个文件,一个保存为值数组,其索引对应于a,b和c值,最后一个包含a,b,c值和结果值的列表列表(示例在上面的代码中)

Thanks for any help! 谢谢你的帮助!

-Will -将

This doesn't solve your multiprocessing problem but it might make your process faster. 这不能解决您的多处理问题,但是可以使您的处理更快。

Your pattern of using nested loops to construct nd coordinates and then operating on them can be vectorize d using ```numpy.meshgrid```` . 您使用嵌套的循环来构建第二坐标,然后对他们的经营模式可以使用矢量化 d ```numpy.meshgrid```` Without knowing your actual calcs this approach can't be tested. 在不知道您的实际计算的情况下,这种方法无法进行测试。

import numpy as np
a = np.array([0,1,2])
b = np.array([10,11,12])
c = np.array([20,21,22])

x, y, z = np.meshgrid(a,b,c)

>>> x
array([[[0, 0, 0],
        [1, 1, 1],
        [2, 2, 2]],

       [[0, 0, 0],
        [1, 1, 1],
        [2, 2, 2]],

       [[0, 0, 0],
        [1, 1, 1],
        [2, 2, 2]]])
>>> y
array([[[10, 10, 10],
        [10, 10, 10],
        [10, 10, 10]],

       [[11, 11, 11],
        [11, 11, 11],
        [11, 11, 11]],

       [[12, 12, 12],
        [12, 12, 12],
        [12, 12, 12]]])
>>> z
array([[[20, 21, 22],
        [20, 21, 22],
        [20, 21, 22]],

       [[20, 21, 22],
        [20, 21, 22],
        [20, 21, 22]],

       [[20, 21, 22],
        [20, 21, 22],
        [20, 21, 22]]])
>>> 



f = x + y + z

>>> f
array([[[30, 31, 32],
        [31, 32, 33],
        [32, 33, 34]],

       [[31, 32, 33],
        [32, 33, 34],
        [33, 34, 35]],

       [[32, 33, 34],
        [33, 34, 35],
        [34, 35, 36]]])
>>> 

There is also the option of using meshgrid to create the actual points then use a single loop to iterate over the points - you lose the spatial info with this approach unless you can figure out how to reshape the result. 也可以选择使用meshgrid创建实际点,然后使用一个循环遍历这些点-除非您能弄清楚如何重塑结果,否则使用这种方法会丢失空间信息。 I found this in SO answer https://stackoverflow.com/a/18253506/2823755 我在答案中找到了这个https://stackoverflow.com/a/18253506/2823755

points = np.vstack([x,y,z]).reshape(3, -1).T

>>> points
array([[ 0, 10, 20],
       [ 0, 10, 21],
       [ 0, 10, 22],
       [ 1, 10, 20],
       [ 1, 10, 21],
       [ 1, 10, 22],
       [ 2, 10, 20],
       [ 2, 10, 21],
       [ 2, 10, 22],
       [ 0, 11, 20],
       [ 0, 11, 21],
       [ 0, 11, 22],
       [ 1, 11, 20],
       [ 1, 11, 21],
       [ 1, 11, 22],
       [ 2, 11, 20],
       [ 2, 11, 21],
       [ 2, 11, 22],
       [ 0, 12, 20],
       [ 0, 12, 21],
       [ 0, 12, 22],
       [ 1, 12, 20],
       [ 1, 12, 21],
       [ 1, 12, 22],
       [ 2, 12, 20],
       [ 2, 12, 21],
       [ 2, 12, 22]])
>>>

You can create a function and apply it to points 您可以创建一个函数并将其应用于points

def g(point):
    x, y, z = point
    return x + y + z

result = np.apply_along_axis(g, 1, points)

>>> result
array([30, 31, 32, 31, 32, 33, 32, 33, 34, 31, 32, 33, 32, 33, 34, 33, 34, 35, 32, 33, 34, 33, 34, 35, 34, 35, 36])
>>>

Reshaping this example is straightforward: 重塑此示例非常简单:

>>> result.reshape(3,3,3)
array([[[30, 31, 32],
        [31, 32, 33],
        [32, 33, 34]],

       [[31, 32, 33],
        [32, 33, 34],
        [33, 34, 35]],

       [[32, 33, 34],
        [33, 34, 35],
        [34, 35, 36]]])
>>> 

Test to make sure they both the same 测试以确保它们都相同

>>> np.all(result.reshape(3,3,3) == f)
True
>>> 

For more complicated maths, just iterate over points: 对于更复杂的数学,只需遍历点即可:

result = []
for point in points:
    example = some_maths
    result.append(example)

result = np.array(result).reshape(shape_of_the_3d_data)

As per user wwii's suggestions, I have rewrote the example above by using numpy's meshgrid and getting rid of the nested for loops for just a single loop. 根据每个用户wwii的建议,我通过使用numpy的meshgrid重写了上面的示例,并摆脱了仅用于单个循环的嵌套for循环。 Here is an example of the working code. 这是工作代码的示例。

import numpy as np
import time

a_range = np.arange(14, 18, 1)
b_range = np.arange(1000, 2200, 200)
c_range = np.arange(12, 21, 1)

a_position = range(len(a_range))
b_position = range(len(b_range))
c_position = range(len(c_range))

mesha, meshb, meshc = np.meshgrid(a_range, b_range, c_range)
mesh_vals = np.vstack([mesha, meshb, meshc]).reshape(3, -1).T

mesha_pos, meshb_pos, meshc_pos = np.meshgrid(a_position, b_position, c_position)
mesh_positions = np.vstack([mesha_pos, meshb_pos, meshc_pos]).reshape(3,-1).T

data_grid = np.zeros([len(a_range), len(b_range), len(c_range)])
record_data = []

start_time = time.time()

for pol in range(len(mesh_positions)):
    example = mesh_vals[pol][0]+ mesh_vals[pol][1]+ mesh_vals[pol][2]
    data_grid[mesh_positions[pol][0], mesh_positions[pol][1], mesh_positions[pol][2]] = example
    record_data.append([mesh_vals[pol][0], mesh_vals[pol][1], mesh_vals[pol][2], example])

print 'Code ran for ', round(time.time()-start_time,2), ' seconds'

This actually, after further investigation caused the run time to increase rather significantly. 实际上,在进一步调查之后,这导致运行时间显着增加。 The difference between the for loops and this method was 20 seconds when subjected to a large range for a, b, and c. 对于a,b和c而言,for循环与该方法之间的差异为20秒。 I have no idea why, but I do know this construction of the problem should make multiprocessing easier since there is only a single for loop to deal with. 我不知道为什么,但是我确实知道问题的这种构造应该使多处理更容易,因为只有一个for循环可以处理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM