由于我的np.dot
受到OpenBlas和Openmpi的加速,我想知道是否有可能编写双重求和。
for i in range(N):
for j in range(N):
B[k,l] += A[i,j,k,l] * X[i,j]
作为内积。现在我正在使用。
B = np.einsum("ijkl,ij->kl",A,X)
但不幸的是它运行速度非常慢,并且只使用一个处理器。有什么好的想法吗?
编辑:我已经用一个简单的例子对给出的答案进行了基准测试,似乎它们都处于同一数量级:
A = np.random.random([200,200,100,100])
X = np.random.random([200,200])
def B1():
return es("ijkl,ij->kl",A,X)
def B2():
return np.tensordot(A, X, [[0,1], [0, 1]])
def B3():
shp = A.shape
return np.dot(X.ravel(),A.reshape(shp[0]*shp[1],1)).reshape(shp[2],shp[3])
%timeit B1()
%timeit B2()
%timeit B3()
1 loops, best of 3: 300 ms per loop
10 loops, best of 3: 149 ms per loop
10 loops, best of 3: 150 ms per loop
从这些结果来看,我会选择np.einsum,因为它的语法仍然是最易读的,而其他两个选项的改进只有2倍的因素。我猜下一步是将代码外部化为C或Fortran。
for
循环的第一部分非常容易理解,但最后一行并没有帮助我们理解完整的流程。请发布完整的代码。 - Pralhad Narsinh Sonarnp.einsum
在 C 中已经进行了优化并使用了 SSE 向量化,因此即使在单线程执行中使用 OpenBlas,您也无法获得数量级的速度提升。使用所提出的方法可以实现 2 倍的加速是合理的。 - rthnp.dot
方法中有一个错别字:A.reshape(shp[0]*shp[1],1)
,其中应该使用-1
。 - Divakartensordot
几乎没有什么好处。然而,当您实际执行张量积时(即当两个矩阵都具有不被求和的维度时),tensordot
显示出巨大的优势。另一种说法是,如果您可以将问题“重塑”为矩阵-向量乘积,则einsum
的速度与tensordot
相同。但是,如果您只能将问题“重塑”为矩阵-矩阵乘积,则tensordot
将更快。 - Will Martin