【问题标题】:MPI - sending and receiving columns of matrixMPI - 矩阵的发送和接收列
【发布时间】:2017-11-20 20:01:38
【问题描述】:

我正在尝试使用Scatter 将矩阵列发送到其他进程。下面的代码非常适用于行,因此为了以最少的修改发送列,我使用 Numpy 转置函数。但是,这似乎没有任何效果,除非我制作一个完整的新矩阵副本(您可以想象,这违背了目的)。

以下 3 个最小示例来说明问题(必须运行 3 个进程!)。

  1. 分散行(按预期工作):

    comm = MPI.COMM_WORLD
    rank = comm.Get_rank()
    size = comm.Get_size()
    
    A = np.zeros((3,3))
    if rank==0:
        A = np.matrix([[1.,2.,3.],[4.,5.,6.],[7.,8.,9.]])
    
    local_a = np.zeros(3)
    
    comm.Scatter(A, local_a, root=0)
    print "process", rank, "has", local_a
    

    给出输出:

    process 0 has [ 1.  2.  3.]
    process 1 has [ 4.  5.  6.]
    process 2 has [ 7.  8.  9.]
    
  2. 分散列(不起作用,仍然分散行...):

    comm = MPI.COMM_WORLD
    rank = comm.Get_rank()
    size = comm.Get_size()
    
    A = np.zeros((3,3))
    if rank==0:
        A = np.matrix([[1.,2.,3.],[4.,5.,6.],[7.,8.,9.]]).T
    
    local_a = np.zeros(3)
    
    comm.Scatter(A, local_a, root=0)
    print "process", rank, "has", local_a
    

    给出输出:

    process 0 has [ 1.  2.  3.]
    process 1 has [ 4.  5.  6.]
    process 2 has [ 7.  8.  9.]
    
  3. 分散列(有效,但似乎毫无意义):

    comm = MPI.COMM_WORLD
    rank = comm.Get_rank()
    size = comm.Get_size()
    
    A = np.zeros((3,3))
    if rank==0:
        A = np.matrix([[1.,2.,3.],[4.,5.,6.],[7.,8.,9.]]).T.copy()
    
    local_a = np.zeros(3)
    
    comm.Scatter(A, local_a, root=0)
    print "process", rank, "has", local_a
    

    最终给出想要的输出:

    process 0 has [ 1.  4.  7.]
    process 2 has [ 3.  6.  9.]
    process 1 has [ 2.  5.  8.]
    

有没有一种简单的方法来发送列而不必复制整个矩阵?


对于上下文,我正在mpi4py tutorial 中进行练习 5。如果您想知道,我的完整解决方案(如上面第 3 点所示浪费内存)是这样的:

comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()

A = np.zeros((3,3))
v = np.zeros(3)
result = np.zeros(3)
if rank==0:
    A = np.array([[1.,2.,3.],[4.,5.,6.],[7.,8.,9.]]).T.copy()
    v = np.array([0.1,0.01,0.001])

# Scatter the columns of the matrix
local_a = np.zeros(3)
comm.Scatter(A, local_a, root=0)

# Scatter the elements of the vector
local_v = np.array([0.])
comm.Scatter(v, local_v, root=0)

print "process", rank, "has A_ij =", local_a, "and v_i", local_v

# Multiplication
local_result = local_a * local_v

# Add together
comm.Reduce(local_result, result, op=MPI.SUM)
print "process", rank, "finds", result, "(", local_result, ")"

if (rank==0):
    print "The resulting vector is"
    print "   ", result, "computed in parallel"
    print "and", np.dot(A.T,v), "computed serially."

这是@Sajid 要求的内存分析测试:

我的解决方案 3(给出正确答案): 0.027 MiB A = np.array([[1.,2.,3.],[4.,5.,6.],[7.,8.,9.]]).T.copy() 0.066 MiB comm.Scatter(A, local_a, root=0) 总计 = 0.093 MiB

另一个类似的解决方案(给出正确答案): 0.004 MiB A = np.array([[1.,2.,3.],[4.,5.,6.],[7.,8.,9.]]) 0.090 MiB comm.Scatter(A.T.copy(), local_a, root=0) 总计 = 0.094 MiB

@Sajid 的解决方案(给出正确答案): 0.039 MiB A[:,:] = np.transpose(np.array([[1.,2.,3.],[4.,5.,6.],[7.,8.,9.]])) 0.062 MiB comm.Scatter(A, local_a, root=0) 总计 = 0.101 MiB

我的解决方案 2(给出错误答案): 0.004 MiB A = np.array([[1.,2.,3.],[4.,5.,6.],[7.,8.,9.]]) 0.066 MiB comm.Scatter(A, local_a, root=0) 总计 = 0.070 MiB

(我只是从行中复制了内存增量,其中内存增量在代码版本之间有所不同。显然,这都是来自根节点。)

似乎很清楚,所有正确的解决方案都必须将数组复制到内存中。这是次优的,因为我只想分散列而不是行。


【问题讨论】:

    标签: python numpy matrix mpi4py


    【解决方案1】:

    可能是数据未正确复制到 A 的问题,请尝试以下操作:

    import numpy as np
    from mpi4py import MPI
    
    comm = MPI.COMM_WORLD
    rank = comm.Get_rank()
    size = comm.Get_size()
    
    A = np.zeros((3,3))
    if rank==0:
        A[:,:] = np.transpose(np.matrix([[1.,2.,3.],[4.,5.,6.],[7.,8.,9.]]))
    
    local_a = (np.zeros(3))
    
    comm.Scatter(A, local_a, root=0)
    print("process", rank, "has", local_a)
    

    当然,如果您使用的是 python2,请更改打印语句。

    【讨论】:

    • 谢谢!这给了我想要的结果,但它不是也复制内存中的矩阵吗?
    • 乍一看,我认为问题在于正确复制数据,但如果您可以通过实际分析代码的两个版本来确认,那就很清楚了。
    • 我在原帖中添加了内存分析测试,因为太长了无法作为评论发表。
    猜你喜欢
    • 1970-01-01
    • 2021-06-13
    • 2018-10-02
    • 2013-04-15
    • 2015-03-19
    • 2018-03-12
    • 2013-12-20
    • 2016-06-15
    • 2012-03-13
    相关资源
    最近更新 更多