Python 是否有一个「;增强型;numpy/scipy点法? 问题

Python 是否有一个「;增强型;numpy/scipy点法? 问题,python,math,numpy,scipy,Python,Math,Numpy,Scipy,我想使用numpy或scipy计算以下内容: Y = A**T * Q * A 其中A是mxn矩阵,A**T是A的转置,Q是mxm对角矩阵 因为Q是一个对角矩阵,所以我只把它的对角元素存储为向量 解决Y 目前,我可以想出两种方法来计算Y: Y=np.dot(np.dot(A.T,np.diag(Q)),A) Y=np.dot(A.T*Q,A) 显然,选项2比选项1好,因为不必使用diag(Q)创建实数矩阵(如果numpy真的这样做的话… 然而,这两种方法都存在必须分配比实际需要更多内存的缺陷,

我想使用numpy或scipy计算以下内容:

Y = A**T * Q * A
其中
A
mxn
矩阵,
A**T
A
的转置,
Q
mxm
对角矩阵

因为Q是一个对角矩阵,所以我只把它的对角元素存储为向量

解决
Y
目前,我可以想出两种方法来计算
Y

  • Y=np.dot(np.dot(A.T,np.diag(Q)),A)
  • Y=np.dot(A.T*Q,A)
  • 显然,选项2比选项1好,因为不必使用
    diag(Q)
    创建实数矩阵(如果numpy真的这样做的话…
    然而,这两种方法都存在必须分配比实际需要更多内存的缺陷,因为
    A.T*Q
    np.dot(A.T,np.diag(Q))
    必须与
    A
    一起存储以计算
    Y

    问题: numpy/scipy中是否有一种方法可以消除不必要的额外内存分配,即只传递两个矩阵
    a
    B
    (在我的例子中
    B
    a.T
    )和一个加权向量
    Q
    (w/r/t OP的最后一句话:我不知道有这样的numpy/scipy方法,但w/r/t OP标题中的问题(即,提高numpy dot性能)下面的内容应该会有所帮助。换句话说,我的答案是针对提高包含Y函数的大多数步骤的性能)。

    首先,这应该会给你一个明显的提升,超过香草NumPydot方法:

    >>> 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          # refers to C-contiguous order
          F_CONTIGUOUS : False         # fortran-contiguous
          OWNDATA : True
          MASKNA : False
          OWNMASKNA : False
          WRITEABLE : True
          ALIGNED : True
          UPDATEIFCOPY : False
    
    要更改其中一个数组的顺序以使两者对齐,只需调用NumPy数组构造函数,传入数组并将相应的顺序标志设置为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
    
    您可以通过利用阵列顺序对齐来进一步优化,以减少由于复制原始阵列而导致的过量内存消耗

    但是为什么数组在传递给dot之前要被复制呢

    点积依赖于BLAS操作。这些操作需要以C-连续顺序存储数组——正是这种约束导致数组被复制

    另一方面,转置不会影响副本,但不幸的是,它会以Fortran顺序返回结果:

    因此,要消除性能瓶颈,需要消除谓词数组复制步骤;要做到这一点,只需将两个数组以C连续顺序*传递给点

    因此,要计算点(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)
    

    我只是想把它放在上面,但是这个pull请求应该会很有帮助,并且不需要为numpy.dot提供单独的函数 这应该在numpy 1.7中提供

    同时,我使用上面的示例编写了一个函数,该函数可以替换numpy dot,无论数组的顺序如何,并正确调用fblas.dgemm。


    希望这能有所帮助,

    numpy.einsum是您需要的:

    numpy.einsum('ij, i, ik -> jk', A, Q, A)
    

    这不需要任何额外的内存(尽管通常einsum的工作速度比BLAS操作慢)

    这确实是访问BLAS例程的一种很好的方式。我相信我将来可以很好地利用它。但是,仍然有一个
    Q
    要插入到这里的某个地方…:)当然,我应该用“我不知道您在OP的最后一句中描述的numpy/scipy方法,但这里介绍了如何提高构成Y函数的大多数步骤的性能;抱歉,如果这是误导(我的回答相应地编辑)。@doug速度呢?在我的测试中,无论矩阵的阶数是多少,dgemm似乎比np.dot慢得多。dgemm应该比numpy.dot快吗?你能解释一下“trans_b=True”是什么意思吗?参考资料没有对此进行详细描述。您是否有任何关于np.dot(在numpy 1.8中)何时复制/不复制arg的示例?或者,我怎么知道?