[英]Why one code (matmul) is faster than the other (Python)
该问题涉及基本的矩阵运算。 在下面的代码中,c1 本质上等于 c2。 但是,第一种计算方式比第二种计算方式快得多。 事实上,起初我认为第一种方式需要分配比 a 矩阵大两倍的 ab 矩阵,因此可能会更慢。 结果恰恰相反。 为什么?
import time
import numpy as np
a = np.random.rand(20000,100)+np.random.rand(20000,100)*1j
tic = time.time()
b = np.vstack((a.real,a.imag))
c1 = b.T @ b
t1 = time.time()-tic
tic = time.time()
c2 = a.real.T @ a.real+a.imag.T@a.imag
t2 = time.time()-tic
print('t1=%f. t2=%f.'%(t1,t2))
一个示例结果是
t1=0.037965. t2=4.375873.
a.real
和a.imag
是就地访问,而np.vstack
创建一个新副本。 @
运算符 ( matmul()
) 处理a.real
和a.imag
的方式需要更长的时间。 为了使其更快,您可以创建每个副本,然后将其传递给@
或使用np.dot(a.real.T, a.real)
和np.dot(a.imag.T, a.imag)
(我不确定 BLAS 中的每个实现)。
对于大型矩阵,下面代码中的第一个方法应该还是稍微快一点:
a = np.random.rand(20000,100)+np.random.rand(20000,100)*1j
tic = time.time()
b = np.vstack((a.real,a.imag))
c1 = b.T @ b
t1 = time.time()-tic
tic = time.time()
b = a.real.copy()
c = a.imag.copy()
c2 = b.T @ b + c.T @ c
t2 = time.time()-tic
print('t1=%f. t2=%f.'%(t1,t2))
Output:
t1=0.031620. t2=0.021769.
编辑:深入研究:
让我们快速浏览一下各种 memory 布局:
a = np.random.rand(20000,100)+np.random.rand(20000,100)*1j
print('a.flags\n', a.flags)
print('a.real flags\n', a.real.flags)
a.flags
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
...
a.real flags
C_CONTIGUOUS : False
F_CONTIGUOUS : False
OWNDATA : False
所以a
是C_CONTIGUOUS
而a.real
不是。 我不确定@
是如何实现计算的,但我的猜测是它与缓存技巧和跨步以及展开循环不同。 我将把它留给专家来解释。 现在, array.copy()
默认为C_CONTIGUOUS
(请注意: np.copy()
默认不是C_CONTIGUOUS
。 )这就是为什么上面的第二种方法与第一种方法一样快(其中b
也是C_CONTIGUOUS
)。
@George C: I think the first one is slightly faster because np.vstack
creates a new C_CONTIGUOUS
object that can leverage cache tricks in one place, while in the second approach the output of a.real.T @ a.real
and a.imag.T@a.imag
位于 memory 的不同位置,需要额外计算。 这是更多解释的链接。
免责声明:欢迎任何了解 NumPy 实现细节的专家编辑这篇文章。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.