Python 为什么在numpy中矩阵减法比点积慢得多?

Python 为什么在numpy中矩阵减法比点积慢得多?,python,numpy,Python,Numpy,假设我们有一个向量和一个矩阵: X = np.random.random((1, 384)).astype('float32') Y = np.random.random((500000, 384)).astype('float32') 为什么np.dot(X,Y.T)比X-Y快得多 In [8]: %timeit np.dot(X, Y.T) 10 loops, best of 3: 42.4 ms per loop In [9]: %timeit X - Y 1 loop, best o

假设我们有一个向量和一个矩阵:

X = np.random.random((1, 384)).astype('float32')
Y = np.random.random((500000, 384)).astype('float32')
为什么
np.dot(X,Y.T)
X-Y
快得多

In [8]: %timeit np.dot(X, Y.T)
10 loops, best of 3: 42.4 ms per loop

In [9]: %timeit X - Y
1 loop, best of 3: 501 ms per loop

我该怎么做才能使减法像点积法一样快?

使用np。减法(X,Y)几乎将执行时间减半。它比X-Y快,但速度仍然低于点积。可能有帮助

这只是一条评论,尽管您已经检查过了

我测试了广播是否是一个原因,但在本例中,它与性能完全无关

In [1]: import numpy as np

In [2]: X = np.random.random((1, 384)).astype('float32')
   ...: Y = np.random.random((500000, 384)).astype('float32')

In [3]: %timeit np.dot(X, Y.T)
   ...: %timeit X - Y
27.4 ms ± 910 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
324 ms ± 16.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [4]: import numpy.matlib
   ...: X = np.matlib.repmat(X, 500000, 1)
   ...: print(X.shape)
   ...: %timeit X - Y
(500000, 384)
351 ms ± 20.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

请原谅,我不确定如何提高性能。

输出的大小很重要,因为输出必须写入内存,写入大型数组需要时间。
点(X,Y.T)
的形状是(150000)。X-Y的形状是(50000384)

在我的测试中,X-Y花费的大部分时间是为输出分配一个数组。比较:

%timeit X - Y   
1 loop, best of 3: 449 ms per loop
对于预先分配的空间
Z=np.zero_,如(Y)

因此,如果您必须重复执行这种减法,那么预先分配一个具有适当形状和类型的数组将节省一半以上的执行时间

我认为你的减法运算不如乘法快。要做的算术数量大致相同:X的每个条目都会遇到Y的500000个条目。当您执行乘法(求和步骤)时,结果被合并的事实只会有所帮助,因为CPU使用它已经存在的数字快速地进行运算,因此它只有一个数字要发送回去。所以:工作量大致相同,但对于减法运算来说,内存写入量是384倍

这里有一个证明,当两个(方阵)的输出大小相同时,减法速度更快:


当维度不同时矩阵的减法?减法的numpy广播可能会导致更多time@lamandy是的,形状不同,这是计算曼哈顿距离的一个步骤。@skruber是的,你认为这是由于实现的原因吗?或者理论上不可能像点积那样快地进行减法运算吗?
np。如果输入数组是浮点数组,点
通常会调用BLAS例程进行矩阵乘法。这些通常是经过大量优化的,并且可能是多线程的,这取决于您的numpy版本链接到的BLAS库
np.subtract始终是单线程的。最好直接编写代码,而不是屏幕截图。我相信np.subtract与直接减法大致相同。不会快很多。
%timeit np.subtract(X, Y, out=Z)
10 loops, best of 3: 181 ms per loop
X = np.random.random((1000, 1000)).astype('float32')
Y = np.random.random((1000, 1000)).astype('float32')

%timeit np.dot(X, Y.T)
100 loops, best of 3: 28.7 ms per loop

%timeit X - Y
1000 loops, best of 3: 579 µs per loop