【发布时间】:2013-08-24 06:38:00
【问题描述】:
让我们从三个dtype=np.double 数组开始。使用icc 编译并链接到英特尔mkl 的numpy 1.7.1 在英特尔CPU 上执行计时。使用gcc 而没有mkl 编译的带有numpy 1.6.1 的AMD cpu 也用于验证时序。请注意,时间与系统大小几乎呈线性关系,并不是由于 numpy 函数 if 语句中产生的小开销,这些差异将以微秒而不是毫秒显示:
arr_1D=np.arange(500,dtype=np.double)
large_arr_1D=np.arange(100000,dtype=np.double)
arr_2D=np.arange(500**2,dtype=np.double).reshape(500,500)
arr_3D=np.arange(500**3,dtype=np.double).reshape(500,500,500)
首先让我们看看np.sum函数:
np.all(np.sum(arr_3D)==np.einsum('ijk->',arr_3D))
True
%timeit np.sum(arr_3D)
10 loops, best of 3: 142 ms per loop
%timeit np.einsum('ijk->', arr_3D)
10 loops, best of 3: 70.2 ms per loop
权力:
np.allclose(arr_3D*arr_3D*arr_3D,np.einsum('ijk,ijk,ijk->ijk',arr_3D,arr_3D,arr_3D))
True
%timeit arr_3D*arr_3D*arr_3D
1 loops, best of 3: 1.32 s per loop
%timeit np.einsum('ijk,ijk,ijk->ijk', arr_3D, arr_3D, arr_3D)
1 loops, best of 3: 694 ms per loop
外品:
np.all(np.outer(arr_1D,arr_1D)==np.einsum('i,k->ik',arr_1D,arr_1D))
True
%timeit np.outer(arr_1D, arr_1D)
1000 loops, best of 3: 411 us per loop
%timeit np.einsum('i,k->ik', arr_1D, arr_1D)
1000 loops, best of 3: 245 us per loop
使用np.einsum 时,上述所有速度都快了一倍。这些应该是苹果对苹果的比较,因为一切都是dtype=np.double。我希望在这样的操作中加快速度:
np.allclose(np.sum(arr_2D*arr_3D),np.einsum('ij,oij->',arr_2D,arr_3D))
True
%timeit np.sum(arr_2D*arr_3D)
1 loops, best of 3: 813 ms per loop
%timeit np.einsum('ij,oij->', arr_2D, arr_3D)
10 loops, best of 3: 85.1 ms per loop
无论axes 选择如何,np.inner、np.outer、np.kron 和 np.sum 的 Einsum 似乎至少快一倍。主要例外是np.dot,因为它从 BLAS 库调用 DGEMM。那么为什么np.einsum 比其他等效的 numpy 函数更快呢?
完整的 DGEMM 案例:
np.allclose(np.dot(arr_2D,arr_2D),np.einsum('ij,jk',arr_2D,arr_2D))
True
%timeit np.einsum('ij,jk',arr_2D,arr_2D)
10 loops, best of 3: 56.1 ms per loop
%timeit np.dot(arr_2D,arr_2D)
100 loops, best of 3: 5.17 ms per loop
主要理论来自@sebergs 评论,np.einsum 可以使用SSE2,但 numpy 的 ufunc 直到 numpy 1.8 才会使用(参见 change log)。我相信这是正确的答案,但 无法确认。通过更改输入数组的 dtype 并观察速度差异以及并非每个人都观察到相同的时序趋势这一事实,可以找到一些有限的证据。
【问题讨论】:
-
numpy 链接的 BLAS 库是什么?是多线程的吗?
-
带 AVX 的多线程 MKL BLAS。
-
顺便提一下,好问题,好例子!这可能值得在邮件列表中询问。之前已经介绍过(尤其是关于
sum),但我很惊讶einsum始终比outer、inner、kron等快约2 倍。知道在哪里会很有趣差异来自于。 -
@JoeKington 如果其他人可以重现 ~2x 加速,我想我会将其发布在邮件列表中。奇怪的是,杰米的回答确实证明了这一点。
-
有点相关:stackoverflow.com/questions/17527340/… 但在这种情况下,速度差异的原因似乎是内存管理,(至少当你开始制作非常大的东西时)
标签: python arrays performance numpy multidimensional-array