该问题涉及基本矩阵运算。在下面的代码中,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))
Run Code Online (Sandbox Code Playgroud)
一个示例结果是
t1=0.037965. t2=4.375873.
Run Code Online (Sandbox Code Playgroud)
a.real并在创建新副本a.imag时就地访问。运算符( )处理的np.vstack方式需要较长的时间。为了使其更快,您可以创建每个的副本,然后将其传递给或使用and (我不确定 BLAS 中的每个实现)。 @matmul()a.reala.imag@np.dot(a.real.T, a.real)np.dot(a.imag.T, a.imag)
对于大型矩阵,以下代码中的第一个方法应该仍然稍微快一些:
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))
Run Code Online (Sandbox Code Playgroud)
输出:
t1=0.031620. t2=0.021769.
Run Code Online (Sandbox Code Playgroud)
编辑:深入研究:
让我们快速浏览一下各种内存布局:
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
Run Code Online (Sandbox Code Playgroud)
a是也是如此C_CONTIGUOUS,不是a.real也是如此。我不确定如何@实现计算,但我的猜测是它与缓存技巧、步幅和展开循环不同。我将把这个问题留给专家来解释。现在,array.copy()默认情况下是C_CONTIGUOUS(请注意:默认情况下np.copy()不是C_CONTIGUOUS。 ),这就是为什么上面的第二种方法与第一种方法一样快(其中b也是C_CONTIGUOUS)。
@George C:我认为第一个方法稍微快一些,因为np.vstack创建了一个可以在一个地方利用缓存技巧的新对象,而在第二种方法中, 和 的C_CONTIGUOUS输出位于内存的不同位置,需要额外的计算工作。这是更多解释的链接。
免责声明:欢迎任何了解 NumPy 实现细节的专家编辑这篇文章。a.real.T @ a.reala.imag.T@a.imag
| 归档时间: |
|
| 查看次数: |
136 次 |
| 最近记录: |