2017-08-28 1 views
0

J'ai passé des semaines littéralement à changer mon code cython en C pur (toujours en Cython) pour gagner en vitesse et être capable de supprimer le GIL pour faire du multithreading pour gagner encore plus de vitesse.Cython convertit numpy ndarray (N, 4,2) en vecteur [vecteur [paire [double, double]]

Avec l'aide des utilisateurs de collègues que j'a finalement réussi et a gagné un facteur 10 pur C vs cython avec un certain python, puis de nouveau un facteur 3 en utilisant 4 fils (avec Prange) dans la double boucle partie de mon code.

MAIS pour entrer dans cette boucle I d'abord le convertir deux trois dimensions numpy ndarrays de dimensions (N, 4,2) (et (K, 4,2)) à vector[vector[pair[double,double]]]. K et N étant raisonnablement grands.

Pour ce que je fais:

cdef int N=200000 #Of this order of magnitude 
cdef np.ndarray[DTYPE_t,ndim=3] numpy_array=np.random.uniform(size=(N,4,2)) 
t1=time.time() 
cdef vector[vector[pair[double,double]]] c_structure 
c_structure.reserve(N) 
cdef int i 
for i in range(N): 
    c_structure.push_back(numpy_array[i]) 
t2=time.time() 

Pourtant, cette partie du code que je jugeais trivial est devenu le nouveau goulot d'étranglement de mon code !!! Le double pour boucle prend sur mon ordinateur 0.1s (au lieu de 1.11s dans l'implémentation d'origine) fil unique et cette partie prend 3 entières secondes (1.5s pour chaque tableau)! Ce qui rend mon code super optimisé 3 fois plus lent que mon code d'origine (1.5 * 2 + 0.1)!

Qu'est-ce que je fais de mal?! Comment accélérer cela?!

Voir another related question that I asked

+1

Pas vraiment important dans ce contexte, mais 'np.random.uniform ((N, 4,2))' ne retourne pas un tableau 3D ... S'il vous plaît essayez de rendre le [mcve] au moins relativement correct. – MSeifert

+0

Merci, il est maintenant corrigé – jean

+0

Est-il possible que la plupart du temps est dans la génération de nombres aléatoires? –

Répondre

0

J'ai gagné un facteur de vitesse de 100 en initialisant explicitement chaque élément du vecteur. En effet avec un cython -a il a maintenant 0 lignes jaunes.

cdef int N=200000 #Of this order of magnitude 
cdef np.ndarray[DTYPE_t,ndim=3] numpy_array=np.random.uniform(size=(N,4,2)) 
t1=time.time() 
cdef vector[vector[pair[double,double]]] c_structure 
cdef vector[pair[double,double]] empty_vector, vector 
cdef pair[double,double] a1, a2, a3, a4 
c_structure.reserve(N) 
cdef int i 
for i in range(N): 
    a1.first=numpy_array[i,0,0] 
    a1.second=numpy_array[i,0,1] 
    a2.first=numpy_array[i,1,0] 
    a2.second=numpy_array[i,1,1] 
    a3.first=numpy_array[i,2,0] 
    a3.second=numpy_array[i,2,1] 
    a4.first=numpy_array[i,3,0] 
    a4.second=numpy_array[i,3,1] 
    vector.push_back(a1) 
    vector.push_back(a2) 
    vector.push_back(a3) 
    vector.push_back(a4) 
    c_structure.push_back(vector) 
    vector=empty_vector 
t2=time.time() 

0.036s au lieu de 3 s

+0

Bon de voir que vous êtes sur la bonne voie. 'empty_vector' et a1/a2/a3/a4 peuvent être supprimés si vous faites simplement' vector.resize (4) 'une fois en haut puis assigner directement dedans, par ex. 'vecteur [0] .first = numpy_array [i, 0,0]'. –

+0

Merci pour le commentaire! Je ne connaissais pas la méthode .resize()! – jean

2

Vous avez un tableau Nx4x2 et vous convertissez à vector[vector[pair[double,double]]. En C++, les vecteurs de vecteurs ne sont pas efficaces. Au lieu de cela, vous devez créer une structure 4x2 et en faire un seul vecteur. Ou, mieux encore, vous devriez utiliser directement le tableau NumPy en C++ comme un pointeur sur le tableau Nx4x2. En d'autres termes, arrêtez de copier vos données inutilement, mais si nécessaire, copiez-les dans une structure Nx4x2 fixe au lieu de NxMx2 qui est lente.

+0

J'ai upvoted la réponse mais j'ai trouvé beaucoup mieux et j'ai gagné un facteur 100 sur l'initialisation. – jean

+0

Je verrai peut-être struct plus tard – jean

+0

J'ai mes raisons pour avoir une structure de taille variable à l'intérieur du vecteur, donc j'ai besoin d'un 'fixed_size_vector [variable_sized_vector [(double, double)]' c'est pourquoi j'ai choisi 'vector [vector [ paire [double, double]]] ' – jean