矩阵乘法的累积结果

时间:2020-04-29 22:34:11

标签: python numpy optimization matrix-multiplication array-broadcasting

给定 nxn 个矩阵的列表,我想计算这些矩阵乘法的累加乘积,即给定矩阵M0,M1,...,Mm,我想要一个结果R,其中 R [0] = M1,R [1] = M0 x M1,R [2] = M0 x M1 x M2 ,依此类推。

很明显,您可以通过for循环或尾部递归来完成此操作,但是我正在以python的速度进行编码。

在代码中:

def matrix_mul_cum_sum(M):
   #M[1..m] is an m x n x n  matrix

   if len(M) == 0:
       return []

   result = [M[1]]
   for A in M[1:]:
       result.append(np.mat_mul(result[-1],A))
   return result

对于特定应用,n = 4,并且m约为1000(如果重要)。我希望为此构造一个numpy公式,但是运气不佳。 PyTorch也可以接受,但是我不太了解。基本上,任何比基本for循环版本都要快的东西都会受到赞赏。

谢谢。

编辑:添加一些基准(@hpaulj提到np.linalg.multidot在这里非常慢,他是正确的。)

import numpy as np
np.set_printoptions(suppress=True)
import time
from functools import reduce
n=1000
M = np.random.uniform(0,1,(n,4,4))
attempts = 1000

start = time.time()
for i in range(attempts):
    x1=reduce(np.dot,M)
trd = time.time()-start
trd = np.round(trd/attempts,8)
print('reduce with np.dot: ',trd)


start = time.time()
for i in range(attempts):
    x2=reduce(np.matmul,M)
trm = time.time()-start
trm = np.round(trm/attempts,8)
print('reduce with np.matmul: ',trm)

start = time.time()
for i in range(attempts):
    x3 = M[0]
    for m in M[1:]:
        x3=np.dot(x3,m)
tfd = time.time()-start
tfd = np.round(tfd/attempts,8)
print('for-loop with np.dot:',tfd)

start = time.time()
for i in range(attempts):
    x4 = M[0]
    for m in M[1:]:
        x4=np.matmul(x4,m)
tfm = time.time()-start
tfm = np.round(tfm/attempts,8)
print('for-loop with np.matmul:',tfm)

def tail_rec(x):
    r = x[0]
    helper(x,1,r)
    return r

def helper(x,i,r):
    if i == len(x):
        return
    helper(x,i+1,np.matmul(x[i],r))

start = time.time()
for i in range(attempts):
    x5 = tail_rec(M)
tt = time.time()-start
tt = np.round(tt/attempts,8)
print('tail rec with matmul:',tt)

assert np.allclose(x1,x2,x3,x4,x5)

a = np.array([trd,trm,tfd,tfm,tt])
a = np.round(a/a[:,None],3)
print(a)

输出:

reduce with np.dot:  0.00118456
reduce with np.matmul:  0.00126214
for-loop with np.dot: 0.00122364
for-loop with np.matmul: 0.00142755
tail rec with matmul: 0.00194438
[[1.    1.065 1.033 1.205 1.641]
 [0.939 1.    0.969 1.131 1.541]
 [0.968 1.031 1.    1.167 1.589]
 [0.83  0.884 0.857 1.    1.362]
 [0.609 0.649 0.629 0.734 1.   ]]

矩阵给出方法的相对性能。输入项i,j是方法i的平均时间除以方法j的平均时间...列中的数字越小越好。

似乎前三种方法都差不多。

0 个答案:

没有答案