2016-04-06 2 views
1

Ich habe ein Problem bei der Zuweisung von temporären Ergebnissen zu einem Array mit Cython. Hier erkläre ich eine test_array, und weight_array, und unter Verwendung for Schleife, ich speichern jedes gewichtete Ergebnis in eine res_array. Sowohl test_array als auch weight_array sind in Cython als C-zusammenhängende Arrays definiert. Die test.pyx und setup.py Dateien sind wie folgt aufgeführt:Warum Werte zuweisen C-zusammenhängende Array ist langsam in meinem Fall mit Cython

# test.pyx 
import numpy as np 
cimport numpy as np 
import random 
cimport cython 
from cython cimport boundscheck, wraparound 


@cython.boundscheck(False) 
@cython.wraparound(False) 
@cython.nonecheck(False) 
@cython.cdivision(True) 
@cython.profile(True) 
def cython_sample(int res_size, int sample_size, double[::1] all_data, double[::1] weight_array): 
    # using c-contiguous array can speed up a little bit 
    cdef int ii, jj 
    cdef double tmp_res, dot_result 
    cdef double[::1] tmp_sample = np.ones(sample_size, dtype=np.double) 
    cdef double[::1] res_array = np.ones(res_size, dtype=np.double) 

    ran = random.normalvariate # generate random value as a test 
    for ii in range(res_size): 
     tmp_sample = all_data[ii:(ii + sample_size)] 

     # inner product operation 
     dot_result = 0.0 
     for jj in range(sample_size): 
      dot_result += tmp_sample[jj]*weight_array[jj] 

     # save inner product result into array 
     res_array[ii] = dot_result 
     #res_array[ii] = ran(10000,20000) 

    return res_array 

# setup.py 
from setuptools import setup,find_packages 
from distutils.extension import Extension 
from Cython.Build import cythonize 
import numpy as np 

ext = Extension("mycython.test", sources=["mycython/test.pyx"]) 
setup(ext_modules=cythonize(ext), 
     include_dirs=[np.get_include()], 
     name="mycython",  
     version="0.1", 
     packages=find_packages(), 
     author="me", 
     author_email="[email protected]", 
     url="http://example.com/") 

Und der Python test.py ist:

import time 
import random 
import numpy as np 
from strategy1 import __cyn__ 

sample_size = 3000 
test_array = [random.random() for _ in range(300000)] 
res_size = len(test_array) - sample_size + 1 
weight_array = [random.random() for _ in range(sample_size)] 
c_contig_store_array = np.ascontiguousarray(test_array, dtype=np.double) 
c_contig_weigh_array = np.ascontiguousarray(weight_array, dtype=np.double) 


replay = 100 
start_time = time.time() 
for ii in range(int(replay)): 
    __cyn__.cython_sample(res_size, sample_size, c_contig_store_array, c_contig_weigh_array) 
per_elapsed_time = (time.time() - start_time)/replay 
print('Elapse time :: %g sec' % (per_elapsed_time)) 

So teste ich zwei Szenarien:

# 1. when saving dot_result into 'res_array': 
    res_array[ii] = dot_result 

Geschwindigkeit Test zeigt: Elapse time :: 0.821084 sec

# 2. when saving a random value ran(10000,20000) into 'res_array': 
    res_array[ii] = ran(10000,20000) 

Geschwindigkeitstest zeigt: Elapse time :: 0.214591 sec.

Der Grund, dass ich ran(*,*) verwenden, um die Codes zu testen ist, dass ich gefunden, wenn ich beide res_array[ii] = dot_result und res_array[ii] = ran(10000,20000) in dem ursprünglichen Codes auf Kommentar, wird die Geschwindigkeit fast 30-100 mal erhöhen (Elapse time :: 0.00633394 sec). Dann dachte ich, das Problem könnte darin liegen, Wert zu res_array zuzuweisen, was wahr wird, da die Geschwindigkeit der Zuordnung eines zufällig generierten Doppelwerts ran(10000,20000) zu res_array ziemlich schnell ist (fast 4 mal schneller, wie oben gezeigt).

Gibt es eine Möglichkeit, dieses Problem zu lösen? Dank

Antwort

3

Wenn Sie den Wert von dot_result do't verwenden, entfernen Sie den Compiler die Schleife:

dot_result = 0.0 
for jj in range(sample_size): 
    dot_result += tmp_sample[jj]*weight_array[jj] 

der inneren Schleife Kosten die meiste Zeit.

Sie Cython Code scheinen, wie correlate(), können Sie es mithilfe von fft beschleunigen:

from scipy import signal 
res = signal.fftconvolve(c_contig_store_array, c_contig_weigh_array[::-1], mode="valid") 
+0

Danke für den Hinweis! Der erste Punkt ist ziemlich cool, und ich stimme dem zu. Für das signal.fftconvolve versuche ich es in meinen Cython- oder Python-Codes, und es kann kaum beschleunigen (aus irgendeinem Grund wird es langsamer) und das innere Produkt scheint die einfachste Lösung zu sein, da wir viele Male innere Produktoperationen ausführen ein rollendes Fenster. Glaubst du, gibt es einen besseren Weg, um das Produkt in Cython zu beschleunigen? Danke – Alvin

+0

mein Beispielcode für 'signal.fftconvolve()' gibt das gleiche Ergebnis wie die 'cython_sample()' Funktion zurück. Sie müssen es nicht in Cython aufrufen. Es gibt keine innere Schleife, wenn Sie die fft-Methode verwenden. – HYRY

+0

Ja, ich habe es! Brilliante Lösung, es ist wirklich schnell, sogar 17 mal schneller als mit *** cdef extern von "cblas.h": doppelter ddot "cblas_ddot" (int, double *, int, double *, int) *** wie in http://maldun.lima-city.de/introduction_to_python/Cython.html. Dein Weg ist eine ziemlich coole Idee! – Alvin