2016-08-19 1 views
8

J'essaie d'améliorer les performances de certains calculs métriques avec Cython prange. Voici mes codes:Prange pas améliorer les performances de Cython

def shausdorff(float64_t[:,::1] XA not None, float64_t[:,:,::1] XB not None): 
    cdef: 
     Py_ssize_t i 
     Py_ssize_t n = XB.shape[2] 
     float64_t[::1] hdist = np.zeros(n) 

    #arrangement to fix contiguity 
    XB = np.asanyarray([np.ascontiguousarray(XB[:,:,i]) for i in range(n)]) 

    for i in range(n): 
     hdist[i] = _hausdorff(XA, XB[i]) 
    return hdist 

def phausdorff(float64_t[:,::1] XA not None, float64_t[:,:,::1] XB not None): 
    cdef: 
     Py_ssize_t i 
     Py_ssize_t n = XB.shape[2] 
     float64_t[::1] hdist = np.zeros(n) 

    #arrangement to fix contiguity (EDITED) 
    cdef float64_t[:,:,::1] XC = np.asanyarray([np.ascontiguousarray(XB[:,:,i]) for i in range(n)]) 

    with nogil, parallel(num_threads=4): 
     for i in prange(n, schedule='static', chunksize=1): 
      hdist[i] = _hausdorff(XA, XC[i]) 
    return hdist 

En fait, à chaque itération la métrique de Hausdorff est calculée entre XA et chaque XB[i]. Voici la signature de la fonction _hausdorff:

cdef inline float64_t _hausdorff(float64_t[:,::1] XA, float64_t[:,::1] XB) nogil: 
    ... 

mon problème est que le shausdorff et le phausdorff parallèle séquentiel ont les mêmes horaires. En outre, il semble que phausdorff ne crée aucun thread.

Donc, ma question est ce qui ne va pas avec mon code, et comment puis-je le réparer pour que le thread fonctionne.

Voici mon setup.py:

from distutils.core import setup 
from distutils.extension import Extension 
from Cython.Build import cythonize 
from Cython.Distutils import build_ext 

ext_modules=[ 
    Extension("custom_metric", 
       ["custom_metric.pyx"], 
       libraries=["m"], 
       extra_compile_args = ["-O3", "-ffast-math", "-march=native", "-fopenmp" ], 
       extra_link_args=['-fopenmp'] 
      ) 
] 

setup( 
    name = "custom_metric", 
    cmdclass = {"build_ext": build_ext}, 
    ext_modules = ext_modules 
) 

EDIT 1: Voici un lien vers le code HTML généré par cython -a: custom_metric.html

EDIT 2: Voici un exemple sur la façon d'appeler les fonctions correspondantes (vous devez d'abord compiler the Cython file)

import custom_metric as cm 
import numpy as np 

XA = np.random.random((9000, 210)) 
XB = np.random.random((1000, 210, 9)) 

#timing 'parallel' version 
%timeit cm.phausdorff(XA, XB) 

#timing sequential version 
%timeit cm.shausdorff(XA, XB) 
+0

Avez-vous essayé d'imprimer l'équivalent de 'omp_get_thread_num()' dans le corps de la boucle de 'prange'. Voir http://cython.readthedocs.io/en/latest/src/userguide/parallelism.html – Harald

+2

Peut-être que 'XB' est un objet Python? Exécutez 'cython -a custom_metric.pyx' avec une annotation. – cgohlke

+0

Y a-t-il des changements si 'phausdorff' est décoré avec' @ cython.boundscheck (False) 'et @ @ cython.wraparound (False)'? –

Répondre

4

Je pense que la parallélisation fonctionne, mais la surcharge supplémentaire de la parallélisation est en train de réduire le temps qu'elle aurait économisé. Si je tente avec différents tableaux de taille alors je ne commence à voir une vitesse dans la version parallèle

XA = np.random.random((900, 2100)) 
XB = np.random.random((100, 2100, 90)) 

Voici la version parallèle prend ~ 2/3 du temps de la version de série pour moi, ce qui ISN certainement » t le 1/4 que vous attendez, mais montre au moins un avantage.


Une amélioration que je peux offrir est de remplacer le code qui fixe contiguïté:

XB = np.asanyarray([np.ascontiguousarray(XB[:,:,i]) for i in range(n)]) 

avec

XB = np.ascontiguousarray(np.transpose(XB,[2,0,1])) 

Cela accélère à la fois les fonctions parallèles et non parallèles assez nettement (un facteur de 2 avec les tableaux que vous avez initialement donnés). Il est un peu plus évident que vous êtes ralenti par les frais généraux dans le prange - la version série est en fait plus rapide pour les tableaux dans votre exemple.

+0

(Publié comme wiki de la communauté car cela ne présente pas une solution, donc je voulais l'enlever de la contention pour la prime) – DavidW