pac*_*man 4 python optimization numpy cython matrix-multiplication
我目前正在尝试优化我用纯Python编写的代码.此代码使用NumPy的很沉重,因为我与NumPy的阵列工作.下面你可以看到我转换为Cython的最简单的类.这只是两个Numpy数组的乘法.这里:
bendingForces = self.matrixPrefactor * membraneHeight
Run Code Online (Sandbox Code Playgroud)
我的问题是,我是否以及如何优化它,当我看到"cython -a"生成的C代码有很多NumPy调用时,这看起来效率不高.
import numpy as np
cimport numpy as np
ctypedef np.float64_t dtype_t
ctypedef np.complex128_t cplxtype_t
ctypedef Py_ssize_t index_t
cdef class bendingForcesClass( object ):
cdef dtype_t bendingRigidity
cdef np.ndarray matrixPrefactor
cdef np.ndarray bendingForces
def __init__( self, dtype_t bendingRigidity, np.ndarray[dtype_t, ndim=2] waveNumbersNorm ):
self.bendingRigidity = bendingRigidity
self.matrixPrefactor = -self.bendingRigidity * waveNumbersNorm**2
cpdef np.ndarray calculate( self, np.ndarray membraneHeight ) :
cdef np.ndarray bendingForces
bendingForces = self.matrixPrefactor * membraneHeight
return bendingForces
Run Code Online (Sandbox Code Playgroud)
我的想法是使用两个for循环并迭代数组的条目.也许我可以使用编译器来优化SIMD操作?!我试过,我可以编译,但它给出了奇怪的结果,并且永远.这是替代函数的代码:
cpdef np.ndarray calculate( self, np.ndarray membraneHeight ) :
cdef index_t index1, index2 # corresponds to: cdef Py_ssize_t index1, index2
for index1 in range( self.matrixSize ):
for index2 in range( self.matrixSize ):
self.bendingForces[ index1, index2 ] = self.matrixPrefactor.data[ index1, index2 ] * membraneHeight.data[ index1, index2 ]
return self.bendingForces
Run Code Online (Sandbox Code Playgroud)
然而,正如我所说,这段代码非常慢,并且没有按预期运行.那么我做错了什么?什么是优化这个并删除NumPy调用操作的最佳方法?
对于简单的矩阵乘法,NumPy代码本身只进行循环和乘法运算,因此在Cython中很难击败它.Cython非常适合用Python替换Python中的循环的情况.您的代码比NumPy慢的原因之一是因为每次在数组中进行索引查找时,
self.bendingForces[ index1, index2 ] = self.matrixPrefactor.data[ index1, index2 ] * membraneHeight.data[ index1, index2 ]
Run Code Online (Sandbox Code Playgroud)
它做更多的计算,如边界检查(索引有效).如果将索引转换为无符号整数,则可以@cython.boundscheck(False)在函数之前使用装饰器.
有关加速Cython代码的更多详细信息,请参阅本教程.
| 归档时间: |
|
| 查看次数: |
3566 次 |
| 最近记录: |