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。