CythonでNumpyを最適化します
-
26-10-2019 - |
質問
私は現在、Pure Pythonで書いたコードを最適化しようとしています。このコードは使用します numpy 私はnumpyアレイを使用しているので非常に重く。以下に、私が変換した私のクラスの最も単純なものを見ることができます システン. 。 2つのnumpy配列の乗算のみがあります。ここ:
bendingForces = self.matrixPrefactor * membraneHeight
私の質問は、「Cython -A」の生成には多くのnumpy-Callingsがあり、それはあまり効率的ではないCコードを見ると、これを最適化できるかどうか、どのようにできるかです。
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
私が持っていたアイデアは、2つを使用することでした for
配列のエントリをループして反復します。おそらく、コンパイラを使用して、Simd-Operationsでこれを最適化できますか?!コンパイルすることができましたが、奇妙な結果をもたらし、永遠にかかりました。代替機能のコードは次のとおりです。
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
しかし、このコードは、私が言ったように、本当に遅く、予想どおりに機能しません。それで、私は何が間違っているのですか?これを最適化し、numpy呼び出し操作を削除する最良の方法は何ですか?
解決
単純なマトリックスの乗算の場合、Numpyコードはすでにループを行い、ネイティブに乗算するだけであるため、Cythonでそれを打ち負かすことは困難です。 Cythonは、PythonのループをCithonのループに置き換える状況に最適です。コードがnumpyよりも遅い理由の1つは、配列でインデックスルックアップを行うたびに、
self.bendingForces[ index1, index2 ] = self.matrixPrefactor.data[ index1, index2 ] * membraneHeight.data[ index1, index2 ]
境界チェックなどのより多くの計算を行います(インデックスは有効です)。署名されていないINTにインデックスをキャストすると、デコレーターを使用できます @cython.boundscheck(False)
関数の前。
これを参照してください チュートリアル Cythonコードのスピードアップの詳細については。