化简双einsum
Simplifying double 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
而不是两个?
在我的电脑上你的时间是:
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
我的结论是,执行此操作 分两步 ,您将获得 更好的性能。这可能是由于一次执行操作时步幅较大,可能导致更多缓存丢失。
你在另一个答案中得到的方法非常聪明。我想将基于 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
运行时测试 -
本节比较 中列出的所有方法和本 post 前面列出的基于 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
我正在尝试使用 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
而不是两个?
在我的电脑上你的时间是:
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
我的结论是,执行此操作 分两步 ,您将获得 更好的性能。这可能是由于一次执行操作时步幅较大,可能导致更多缓存丢失。
你在另一个答案中得到的方法非常聪明。我想将基于 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
运行时测试 -
本节比较 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