在Python中加倍矩阵数组的最快方法(numpy)

时间:2011-09-07 19:22:19

标签: arrays performance matrix numpy multiplication

我有两个2乘2复数矩阵的数组,我想知道最快的乘法方法是什么。 (我想对矩阵数组的元素进行矩阵乘法。)目前,我有

numpy.array(map(lambda i: numpy.dot(m1[i], m2[i]), range(l)))

但是,一个人能比这更好吗?

谢谢,

v923z

5 个答案:

答案 0 :(得分:1)

我认为你要找的答案是here。不幸的是,这是一个涉及重塑的相当混乱的解决方案。

答案 1 :(得分:1)

numpy.einsum是这个问题的最佳解决方案,它提到了DaveP参考的底部。代码干净,易于理解,比循环遍历数组并逐个进行乘法快一个数量级。以下是一些示例代码:

import numpy
l = 100

m1 = rand(l,2,2)
m2 = rand(l,2,2)

m3 = numpy.array(map(lambda i: numpy.dot(m1[i], m2[i]), range(l)))
m3e = numpy.einsum('lij,ljk->lik', m1, m2)

%timeit numpy.array(map(lambda i: numpy.dot(m1[i], m2[i]), range(l)))
%timeit numpy.einsum('lij,ljk->lik', m1, m2)

print np.all(m3==m3e)

以下是在ipython笔记本中运行时的返回值:
1000次循环,最佳3:每循环479μs
10000次循环,最佳3次:每循环48.9μs

答案 2 :(得分:0)

如果m1m2是2x2复数矩阵的1维数组,则它们基本上具有形状(l,2,2)。因此,最后两个轴上的矩阵乘法相当于将m1的最后一个轴与m2的倒数第二个轴的乘积相加。这正是np.dot所做的:

np.dot(m1,m2)

或者,既然你有复杂的矩阵,也许你想首先采用m1的复共轭。在这种情况下,请使用np.vdot

PS。如果m1是2x2复杂矩阵的列表,那么可能会看看您是否可以从一开始就重新排列代码以使m1成为一个形状(l,2,2)的数组。

如果那是不可能的,列表理解

[np.dot(m1[i],m2[i]) for i in range(l)]

比使用map使用lambda更快,但执行l np.dot比在两个数组上执行一个np.dot要慢如上所述,形成(l,2,2)

答案 3 :(得分:0)

  

如果m1和m2是2x2复数矩阵的1维阵列,那么它们基本上具有形状(1,2,2)。因此,最后两个轴上的矩阵乘法相当于将m1的最后一个轴与m2的倒数第二个轴的乘积相加。这正是np.dot所做的:

但这不是np.dot的作用。

 a = numpy.array([numpy.diag([1, 2]), numpy.diag([2, 3]), numpy.diag([3, 4])])

生成一个2乘2矩阵的(3,2,2)数组。但是,numpy.dot(a,a)创建了6个矩阵,结果的形状为(3,2,3,2)。这不是我需要的。我需要的是一个包含numpy.dot(a [0],a [0]),numpy.dot(a [1],a [1]),numpy.dot(a [2],a [2] )...

[np.dot(m1[i],m2[i]) for i in range(l)]

应该可以工作,但我还没有检查过,lambda表达式的映射是否更快。

干杯,

v923z

编辑:for循环和地图以大约相同的速度运行。这是numpy.array的转换消耗了大量的时间,但是这两种方法都必须这样做,所以这里没有任何好处。

答案 4 :(得分:0)

可能是问题太老了,但我还在寻找答案。

我试过这段代码

a=np.asarray(range(1048576),dtype='complex');b=np.reshape(a//1024,(1024,1024));b=b+1J*b
%timeit c=np.dot(b,b)
%timeit d=np.einsum('ij, ki -> jk', b,b).T

结果是:'dot'

10 loops, best of 3: 174 ms per loop

代表'einsum'

1 loops, best of 3: 4.51 s per loop

我已经检查过c和d是否相同

(c==d).all()
True

仍然'点'是赢家,我仍在寻找更好的方法,但没有成功