Python并行矩阵向量乘法

Python并行矩阵向量乘法,python,matrix,multiprocessing,matrix-multiplication,Python,Matrix,Multiprocessing,Matrix Multiplication,我试图用向量元素乘以矩阵的每一列 我有一个正常工作的串行解决方案 for i in range(0,temp.shape[0]): for j in range(0,temp.shape[1]): temp[i,j] = temp[i,j] * h[i,0] 下面是一个并行解决方案,它适用于我正在尝试做的事情,但不会返回与上面代码相同的矩阵 def mv_mult(start_col,end_col,M,V): for i in range(0

我试图用向量元素乘以矩阵的每一列

我有一个正常工作的串行解决方案

    for i in range(0,temp.shape[0]):
        for j in range(0,temp.shape[1]):
             temp[i,j] = temp[i,j] * h[i,0]
下面是一个并行解决方案,它适用于我正在尝试做的事情,但不会返回与上面代码相同的矩阵

def mv_mult(start_col,end_col,M,V):
for i in range(0,M.shape[0]):
    for j in range(start_col,end_col):
        M[i,j] = M[i,j] * V[i,0]

num_threads = multiprocessing.cpu_count()
threads = []
extra = temp.shape[1] % num_threads
start_col = 0
jump = temp.shape[1] / num_threads
for i in range(0,num_threads):
    print 'starting thread ', i
    if (i <  extra)
        args = start_col, start_col+jump+1,temp,h
        p = multiprocessing.Process(target=mv_mult,args=args)
        p.start()
        threads.append(p)
        start_col += jump+1
    else:
        args = start_col, start_col+jump,temp,h
        p = multiprocessing.Process(target=mv_mult,args=args)
        p.start()
        threads.append(p)
        start_col += jump

for i in threads:
    i.join()
def mv_mult(起始列、结束列、M、V):
对于范围(0,M.shape[0])内的i:
对于范围内的j(开始列,结束列):
M[i,j]=M[i,j]*V[i,0]
num\u threads=多处理.cpu\u计数()
线程=[]
额外=临时形状[1]%螺纹数
起始值=0
跳转=临时形状[1]/num\u线程
对于范围内的i(0,num_线程):
打印“起始线程”,i
如果(i<额外)
args=开始列,开始列+跳转+1,温度,h
p=多处理。进程(目标=mv_mult,args=args)
p、 开始()
threads.append(p)
开始列+=跳转+1
其他:
args=启动列,启动列+跳转,温度,h
p=多处理。进程(目标=mv_mult,args=args)
p、 开始()
threads.append(p)
start_col+=跳转
对于线程中的i:
i、 加入
我对Python比较陌生,但据我所知,所有内容都是通过引用传递的,因此传递给每个新进程的临时矩阵都是同一个对象,因此它应该与串行解决方案的工作方式相同,减去它被列分割的事实


关于它为什么不工作有什么想法吗?

假设您有一个数组,首先尝试使用numpy的矢量化计算:

M[:,startcol:endcol] *= V[:,0]

您可能会发现这比任何并行化技巧都要快,如果不是,您最好使用类似的行,将矩阵块发送到每个进程,而不是单个元素。

这只是numpy
乘法操作:

import numpy

a = numpy.matrix(numpy.ones((5,5)))
b = numpy.arange(5).reshape(5,1)
print a
print b    
#[[ 1.  1.  1.  1.  1.]
# [ 1.  1.  1.  1.  1.]
# [ 1.  1.  1.  1.  1.]
# [ 1.  1.  1.  1.  1.]
# [ 1.  1.  1.  1.  1.]]
#[[0]
# [1]
# [2]
# [3]
# [4]]

c = numpy.multiply(a,b)
print c
#[[ 0.  0.  0.  0.  0.]
# [ 1.  1.  1.  1.  1.]
# [ 2.  2.  2.  2.  2.]
# [ 3.  3.  3.  3.  3.]
# [ 4.  4.  4.  4.  4.]]
(请注意,在串行版本中,您是在乘以行,而不是列)

将此时间与串行版本进行比较:

#!/usr/bin/env python

import numpy
import numpy.random
import numpy.linalg
import sys
import time

def init(n):
    a = numpy.matrix(numpy.random.rand(n,n))
    b = numpy.random.rand(n,1)
    b = b.reshape((n,1))
    return a,b

def np_mult(a, b):
    c = numpy.multiply(a,b)
    return c

def manual_mult(a,b):
    c = numpy.matrix(numpy.zeros_like(a))
    for i in range(0,a.shape[0]):
        for j in range(0,a.shape[1]):
             c[i,j] = a[i,j] * b[i]
    return c

def main(argv=None):
    if argv is None:
        argv = sys.argv

    n = int(argv[1])
    niters = int(argv[2])
    a,b = init(n)

    start = time.time()
    for i in xrange(niters):
        cnp = np_mult(a,b)
    end = time.time()

    nptime = (end-start)/niters
    print 'Numpy: ', nptime

    start = time.time()
    for i in xrange(niters):
        cm = manual_mult(a,b)
    end = time.time()

    manualtime = (end-start)/niters
    print 'Manual: ', manualtime
    print 'Speed difference = ', manualtime/nptime
    print 'Diff = ', numpy.linalg.norm(cm - cnp)/numpy.linalg.norm(cnp)

    return 0

if __name__ == "__main__":
    sys.exit(main())
使用一些小尺寸跑步可以提供:

$ ./mult.py 50 5
Numpy:  3.48091125488e-05
mManual:  0.021101808548
Speed difference =  606.215068493
Diff =  0.0

$ ./mult.py 100 5
Numpy:  6.59942626953e-05
Manual:  0.0830503940582
Speed difference =  1258.44869942
Diff =  0.0

$ ./mult.py 500 5
Numpy:  0.000931406021118
Manual:  2.08903641701
Speed difference =  2242.88481032
Diff =  0.0

由于速度差异使并行性所能弥补的一切相形见绌。

其他人提出了解决您问题的正确方法,我只想回应一下:

所以传递给每个新进程的临时矩阵是同一个对象,所以 它的工作原理应与串行解决方案相同

当您尝试进行多处理时,这种情况就会发生,并行进程不能有任何共享内存,因此它们不能同时访问同一个数组。我相信你正在让N_工人将你的阵列副本分发给工人。每个工人都在自己的副本上工作,然后在停止工作时将结果扔掉。我希望你在开始的时候能得到同样的矩阵


如果您想采用这种方法,您需要让它们在最后返回自己的副本,然后将它们合并在一起(这会降低您可能获得的任何效率收益)。

我最初尝试过使用这种方法,但它们是矩阵而不是数组,在按切片索引时出现错误。看起来python是通过赋值而不是引用传递的。刚吃过午饭回来,所以我开始研究这个问题。你也可以看看哪些可以加速元素级的大型计算?好主意,Mark m,numexpr非常适合加速大型计算的数组表达式,但是,当表达式包含许多可能会创建临时数组的术语时,它会非常出色。到目前为止,最好使用numpy实现这一点,并确保您的numpy链接到一个线程BLAS(Atlas,OpenBLAS)。您不想编写自己的线性代数例程。非常感谢。这看起来确实像我要做的。我正在把Matlab翻译成Python。谢谢你的时间安排。我最后用这个作为我的解决方案。我的矩阵大约是13000x13000。它是在循环中多次调用的函数的一部分。我的循环现在从12分钟减少到每次迭代3:30。