Optimisation NumPy avec Cython
-
26-10-2019 - |
Question
Je tente actuellement d'optimiser le code que je l'avais écrit en Python pur. Ce code utilise NumPy très fortement que je travaille avec des tableaux numpy. Ci-dessous vous pouvez voir la plus simple de mes cours que je me suis converti Cython . Ce qui ne fait que la multiplication de deux tableaux NumPy. Ici:
bendingForces = self.matrixPrefactor * membraneHeight
Ma question est, si et comment je peux optimiser ce que, quand je regarde le code C qui « cython -a » génère a beaucoup de numpy-appels, ce qui ne semble pas très efficace.
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
L'idée que j'avais été d'utiliser deux boucles de for
et itérer sur les entrées des tableaux. Peut-être que je pourrais utiliser le compilateur pour optimiser ce cas avec SIMD opérations ?! J'ai essayé, que je pouvais compiler, mais il a donné des résultats étranges et a pris une éternité. Voici le code de la fonction de remplacement:
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
Cependant, ce code comme je l'ai dit, est vraiment lent et ne fonctionne pas comme prévu. Alors qu'est-ce que je fais mal? Quelle serait la meilleure façon d'optimiser cela et supprimer les opérations appelant NumPy?
La solution
Pour multiplications simples de la matrice, le code NumPy est déjà fait que la boucle et en multipliant de manière native, il serait donc difficile de battre en Cython. Cython est idéal pour les situations où vous remplacez des boucles en Python avec ceux cython. L'une des raisons pour lesquelles votre code est plus lent que NumPy est parce que chaque fois que vous faites une recherche d'index dans votre tableau,
self.bendingForces[ index1, index2 ] = self.matrixPrefactor.data[ index1, index2 ] * membraneHeight.data[ index1, index2 ]
il fait plus de calculs comme la vérification des limites (l'indice est valide). Si vous lancez vos indices à ints non signés, vous pouvez utiliser le @cython.boundscheck(False)
décorateur avant la fonction.
tutoriel pour plus de détails en accélérant le code Cython.