【问题标题】:Simplifying double einsum简化双 einsum
【发布时间】:2016-01-28 18:05:11
【问题描述】:

我正在尝试使用 numpy.einsum 来简化代码中的循环。

目前,我的代码如下所示:

k = 100 
m = 50
n = 10
A = np.arange(k*m*n).reshape(k, m, n)
B = np.arange(m*m).reshape(m, m)

T = np.zeros((n, n)) 
for ind in xrange(k):
    T += np.dot(A[ind,:,:].T, np.dot(B, A[ind,:,:]))

我正在尝试使用numpy.einsum 作为此循环的替代方案:

Tp = np.einsum('nij,njk->ik', np.einsum('nij,jk->nik', A.transpose(0,2,1), B), A)
print np.allclose(T, Tp)

是否可以使用单个numpy.einsum 而不是两个?

【问题讨论】:

  • 在我的电脑上,print (np.allclose(T, Tp)) 是假的??。

标签: python arrays numpy vectorization numpy-einsum


【解决方案1】:

在我的电脑上,你的时间是:

np.einsum('nij,njk->ik', np.einsum('nij,jk->nik', A.transpose(0,2,1), B), A)
# 100 loops, best of 3: 4.55 ms per loop

您可以通过以下方式实现:

T2 = np.einsum('nij, il, kln ->jk', A, B, A.T)
#  10 loops, best of 3: 51.9 ms per loop

或使用双重np.tensordot():

T3 = np.tensordot(A, np.tensordot(A, B, axes=(1, 1)), axes=((0, 1), (0, 2)))
# 100 loops, best of 3: 2.73 ms per loop

我的结论是,分两步进行此操作,您将获得更好的性能。这可能是由于一次执行操作时会发生更大的步幅,可能会导致更多的缓存丢失。

【讨论】:

    【解决方案2】:

    您在其他答案中得到的非常聪明的方法。我想将基于numpy.dot 的方法添加到也使用一些reshaping 的组合中。这是这样做的一种方法-

    k,m,n = A.shape
    ((A.transpose(2,0,1).reshape(-1,m).dot(B.T)).reshape(n,-1)).dot(A.reshape(-1,n)).T
    

    运行时测试 -

    本部分基于本文前面列出的一种方法比较了other answer 和numpy.dot 中列出的所有方法。

    In [130]: k = 100 
         ...: m = 50
         ...: n = 10
         ...: A = np.arange(k*m*n).reshape(k, m, n)
         ...: B = np.arange(m*m).reshape(m, m)
         ...: 
    
    In [131]: %timeit np.einsum('nij,njk->ik', np.einsum('nij,jk->nik', A.transpose(0,2,1), B), A)
    100 loops, best of 3: 10.7 ms per loop
    
    In [132]: %timeit np.einsum('nij, il, kln ->jk', A, B, A.T)
    10 loops, best of 3: 105 ms per loop
    
    In [133]: %timeit np.tensordot(A, np.tensordot(A, B, axes=(1, 1)), axes=((0, 1), (0, 2)))
    100 loops, best of 3: 6.22 ms per loop
    
    In [134]: %timeit ((A.transpose(2,0,1).reshape(-1,m).dot(B.T)).reshape(n,-1)).dot(A.reshape(-1,n)).T
    100 loops, best of 3: 5.3 ms per loop
    

    【讨论】:

    • 在内部,我相信tensordot 使用与您相同的transpose 和reshape。时间已经足够接近了。
    • @hpaulj 嗯,它可能。从我的基准测试来看,我总是发现np.dot 比np.tensordot 快一点,所以这可能是函数调用开销。在这种情况下,有很多方法可以重塑和转置,经过多次试验,我发现列出的方法是最优化的。另外,np.dot 给了我更多的控制权,所以我认为可以在这里尝试 :)
    猜你喜欢
    • 1970-01-01
    • 2018-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-17
    • 1970-01-01
    相关资源
    最近更新 更多