2016-03-26 4 views
0

Ich versuche, den folgenden Code parallelisieren, die zahlreiche numpy Array-OperationenWie parallelisieren die numpy Operationen in cython

#fft_fit.pyx 
    import cython 
    import numpy as np 
    cimport numpy as np 
    from cython.parallel cimport prange 
    from libc.stdlib cimport malloc, free 

    dat1 = np.genfromtxt('/home/bagchilab/Sumanta_files/fourier_ecology_sample_data_set.csv',delimiter=',') 
    dat = np.delete(dat1, 0, 0) 
    yr = np.unique(dat[:,0]) 
    fit_dat = np.empty([1,2]) 


    def fft_fit_yr(np.ndarray[double, ndim=1] yr, np.ndarray[double, ndim=2] dat, int yr_idx, int pix_idx): 
     cdef np.ndarray[double, ndim=2] yr_dat1 
     cdef np.ndarray[double, ndim=2] yr_dat 
     cdef np.ndarray[double, ndim=2] fft_dat 
     cdef np.ndarray[double, ndim=2] fft_imp_dat 
     cdef int len_yr = len(yr) 
     for i in prange(len_yr ,nogil=True): 
      with gil: 

       yr_dat1 = dat[dat[:,yr_idx]==yr[i]] 
       yr_dat = yr_dat1[~np.isnan(yr_dat1).any(axis=1)] 
       print "index" ,i 
       y_fft = np.fft.fft(yr_dat[:,pix_idx]) 
       y_fft_abs = np.abs(y_fft) 
       y_fft_freq = np.fft.fftfreq(len(y_fft), 1) 
       x_fft = range(len(y_fft)) 
       fft_dat = np.column_stack((y_fft, y_fft_abs)) 
       cut_off_freq = np.percentile(y_fft_abs, 25) 
       imp_freq = np.array(y_fft_abs[y_fft_abs > cut_off_freq]) 
       fft_imp_dat = np.empty((1,2)) 
     for j in range(len(imp_freq)): 
        freq_dat = fft_dat[fft_dat[:, 1]==imp_freq[j]] 
        fft_imp_dat = np.vstack((fft_imp_dat , freq_dat[0,:]))  
       fft_imp_dat = np.delete(fft_imp_dat, 0, 0) 
       fit_dat1 = np.fft.ifft(fft_imp_dat[:,0]) 
       fit_dat2 = np.column_stack((fit_dat1.real, [yr[i]] * len(fit_dat1))) 
       fit_dat = np.concatenate((fit_dat, fit_dat2), axis = 0) 

habe ich für setup.py den folgenden Code haben umfasst

####setup.py 
    from distutils.core import setup 
    from distutils.extension import Extension 
    from Cython.Distutils import build_ext 

    setup(
cmdclass = {'build_ext': build_ext}, 
ext_modules = [Extension("fft_fit_yr", ["fft_fit.pyx"])] 
    extra_compile_args=['-fopenmp'], 
    extra_link_args=['-fopenmp'])] 
    ) 

Aber Ich erhalte den folgenden Fehler, wenn ich das fft_fit.pyx in Cython kompiliere:

for i in prange(len_yr ,nogil=True): 
    target may not be a Python object as we don't have the GIL 

Ple Lass mich wissen, wo ich falsch liege, während ich die Prange-Funktion nutze. Danke.

+0

Drei Punkte: 1) die spezifische Fehlermeldung erhalten Sie wahrscheinlich, weil Sie nicht 'cdef'ed' i' zu einer Ganzzahl haben. 2) es ist in Ordnung, 'mit gil:' in 'prange' für kleine Stücke zu verwenden, aber diese Teile können nicht parallel ausgeführt werden, so dass es völlig sinnlos ist, das _whole_ Ding in' mit gil: 'zu haben. 3) Ali_m ist richtig - die Sachen, die du machst, funktionieren nicht in einer "Prange" -Sektion. Die Mehrfachverarbeitung ist wahrscheinlich die beste Wahl. – DavidW

+0

Danke für Ihre Kommentare! Es wäre eine große Hilfe, wenn Sie mir bitte mitteilen, wie Sie Multiprocessing in diesem Code verwenden. –

Antwort

2

Sie können nicht (zumindest nicht mit Cython).

Numpy-Funktionen arbeiten mit Python-Objekten und erfordern daher GIL, wodurch verhindert wird, dass mehrere native Threads parallel ausgeführt werden. Wenn Sie Ihren Code mit cython -a kompilieren, erhalten Sie eine HTML-Datei mit Anmerkungen, die zeigt, wo Python C-API-Aufrufe vorgenommen werden (und daher, wo die GIL nicht freigegeben werden kann).

Cython ist am nützlichsten, wenn Sie einen bestimmten Engpass in Ihrem Code haben, der nicht einfach durch Vektorisierung beschleunigt werden kann. Wenn Ihr Code bereits die meiste Zeit mit numpy-Funktionsaufrufen verbracht hat, führt das Aufrufen der exakt gleichen Funktionen von Cython zu keiner wesentlichen Leistungsverbesserung. Um einen bemerkenswerten Unterschied zu sehen, müssten Sie einige oder alle Array-Operationen als explizite for-Schleifen schreiben. Es sieht jedoch so aus, als gäbe es viel einfachere Optimierungen, die an Ihrem Code vorgenommen werden könnten.

Ich schlage vor, dass Sie Folgendes tun:

  1. ursprünglichen Python-Code Profil (zum Beispiel unter Verwendung von line_profiler), um zu sehen, wo die Engpässe sind.
  2. Konzentrieren Sie sich auf die Beschleunigung dieser Engpässe in der single-threaded Version. Sie sollten eine separate Frage zu SO stellen, wenn Sie Hilfe dabei benötigen.
  3. Wenn die optimierte single-threaded-Version für Ihre Anforderungen immer noch zu langsam ist, parallelisieren Sie sie mit joblib oder multiprocessing. Parallelisierung ist in der Regel das letzte Werkzeug zu erreichen, sobald Sie bereits alles andere versucht haben, was Sie denken können.
+0

Vielen Dank für Ihre Kommentare und erklären den Standard in meinem Code. Ich werde versuchen, diesen Code auf Single-Thread zu optimieren. Aber es wäre eine große Hilfe, wenn Sie mich zu irgendwelchen ähnlichen Codes oder Hinweisen führen könnten, wo die Parallelisierung bei mehreren anzahligen Array-Operationen durchgeführt wird. –

+0

Es ist viel hilfreicher für zukünftige Leser, wenn Sie Ihre Fragen konzentriert halten - es wäre besser, eine separate Frage zu stellen, wenn Sie Hilfe bei der Optimierung Ihrer Singlethread-Version benötigen. Wie bereits erwähnt, ist 'joblib' eine der einfachsten Methoden, um Ihre numpy-Funktionsaufrufe zu parallelisieren.Es ist im Grunde ein Convenience-Wrapper um das 'multiprocessing' Python-Modul. Sie sollten die Dokumentation, auf die ich in meiner Antwort verlinkte, für einige Beispiele ansehen, die zeigen, wie man sie benutzt. –