繁体   English   中英

为什么一个代码(matmul)比另一个(Python)快

[英]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.reala.imag是就地访问,而np.vstack创建一个新副本。 @运算符 ( matmul() ) 处理a.reala.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

所以aC_CONTIGUOUSa.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM