关于原帖中的最后一句话:我不知道是否有这样的numpy/scipy方法,但是关于原帖标题中的问题(即如何提高NumPy点积性能),以下内容应该会对你有所帮助。换句话说,我的回答旨在改善大部分构成Y函数的步骤的性能。
首先,这应该比原始的NumPy点积方法给你带来明显的提升:
>>> from scipy.linalg import blas as FB
>>> vx = FB.dgemm(alpha=1., a=v1, b=v2, trans_b=True)
请注意,这两个数组v1、v2都是按照C_FORTRAN顺序排列的。
您可以通过数组的flags属性来访问NumPy数组的字节顺序,如下所示:
>>> c = NP.ones((4, 3))
>>> c.flags
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
MASKNA : False
OWNMASKNA : False
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False
要改变其中一个数组的顺序,使两个数组对齐,只需调用NumPy数组构造函数,传入该数组并将适当的order标志设置为True即可。
>>> c = NP.array(c, order="F")
>>> c.flags
C_CONTIGUOUS : False
F_CONTIGUOUS : True
OWNDATA : True
MASKNA : False
OWNMASKNA : False
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False
您可以通过利用数组顺序对齐来进一步优化,以减少由于复制原始数组而导致的过多内存消耗。
但是为什么在传递给点乘之前要复制数组呢?
点积依赖于BLAS操作。这些操作需要以C连续顺序存储的数组--正是这个约束导致数组被复制。
另一方面,转置不会产生副本,但不幸的是结果返回为Fortran顺序:
因此,为了消除性能瓶颈,您需要消除谓词数组复制步骤;只需要以C连续顺序将两个数组传递给点乘即可做到这一点*。
因此,要计算dot(A.T., A)而不需要额外复制:
>>> import scipy.linalg.blas as FB
>>> vx = FB.dgemm(alpha=1.0, a=A.T, b=A.T, trans_b=True)
总之,上面的表达式(连同谓词导入语句)可以替代点号以提供相同的功能但更好的性能。
您可以将该表达式绑定到一个函数中,如下所示:
>>> super_dot = lambda v, w: FB.dgemm(alpha=1., a=v.T, b=w.T, trans_b=True)