2016-04-06 13 views
1

Cythonを使って配列に一時的な結果を割り当てる問題があります。ここで私はtest_arraysample-sizeweight_arrayを宣言し、forループを使用して、それぞれの重み付け結果をres_arrayに保存します。 test_arrayweight_arrayはCythonのC連続配列として定義されています。 test.pyxとsetup.pyファイルは、以下のように記載されています:私の場合Cythonを使用してC連続配列に値を割り当てるのが遅い

# 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/") 

をとPythonのtest.pyは次のとおりです。

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)) 

だから私は2つのシナリオをテスト:

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

速度をテスト結果はElapse time :: 0.821084 sec

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

スピードテストはElapse time :: 0.214591 secを示します。私はコードをテストするためにran(*,*)を使用

理由は、私は、私は、元のコードの両方のres_array[ii] = dot_resultres_array[ii] = ran(10000,20000)をコメントアウトした場合、速度はほぼ30-100回(Elapse time :: 0.00633394 sec)を増加させる見つけたことです。それで、私はこの問題がres_arraydot_resultの値を割り当てることにあると考えました。これは、ランダムに生成されたdouble値ran(10000,20000)res_arrayに割り当てる速度がかなり速い(上記のようにほぼ4倍速くなります)。

この問題を解決する方法はありますか?おかげ

答えて

3

あなたがdot_resultの値を使用しdo't場合、コンパイラはループを削除します:

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

内側のループは、ほとんどの時間がかかります。ノートの

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

ありがとう:

あなたは、コードをcythonあなたはFFTを使用して、それをスピードアップすることができ、correlate()のように見えます!最初の点はかなりクールで、私はそれに同意します。 signal.fftconvolveについては、私はcythonやpythonのコードで試してみました。何らかの理由でスピードアップすることはほとんどありません。内部製品は、何度も内部製品操作を行っているので、最も簡単な解決策です。ローリングウィンドウ。あなたはサイフォンの内側の製品をスピードアップする良い方法があると思いますか? Thanks – Alvin

+0

私の 'signal.fftconvolve()'のサンプルコードは、 'cython_sample()'関数と同じ結果を返します。 Cythonで呼び出す必要はありません。 fftメソッドを使用する場合、内部ループはありません。 – HYRY

+0

いや、私はそれを持っている!素晴らしいソリューション、それは "cblas.h"から*** cdef externを使用するよりも17倍も高速です:double ddot "cblas_ddot"(int、double *、int、double *、int)*** http://maldun.lima-city.de/introduction_to_python/Cython.html。あなたの方法はかなりクールなアイデアです! – Alvin

関連する問題