让我们从的三个数组开始dtype=np.double
。使用numpy 1.7.1编译icc
并链接到intel的numpy 1.7.1在intel CPU上执行计时mkl
。一个AMD的CPU与编译numpy的1.6.1gcc
不mkl
也被用来验证的时序。请注意,计时几乎与系统大小成线性比例,并且不是由于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
Einsum似乎是至少两倍快np.inner
,np.outer
,np.kron
和,np.sum
不管axes
选择。主要的例外是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的ufuncs直到numpy 1.8才会使用(请参阅更改日志)。我相信这是正确的答案,但无法确认。通过更改输入数组的dtype并观察速度差异以及并非每个人都观察到相同的时序趋势这一事实,可以找到一些有限的证明。