简化双重einsum

时间:2015-10-28 19:31:36

标签: python arrays numpy vectorization numpy-einsum

我正在尝试使用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而不是两个?

2 个答案:

答案 0 :(得分:4)

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

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

我的结论是,您正在通过两个步骤执行更好的性能执行此操作。这可能是由于在一次执行操作时发生了更大的步幅,可能导致更多的缓存丢失。

答案 1 :(得分:3)

你在另一个答案中得到了真正聪明的方法。我想将基于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 answernumpy.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