2016-08-19 18 views
8

私はCythonのprangeでいくつかのメトリック計算のパフォーマンスを改善しようとしています。ここに私のコードは次のとおりです。Cythonの性能が向上しないprange

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 

基本的には、各反復でハウスドルフメトリックがXAと各XB[i]の間で計算されます。ここ_hausdorff関数のシグネチャは次のとおりです。

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

私の問題は、シーケンシャルshausdorffと並行phausdorffの両方が同じタイミングを有することです。さらに、phausdorffはスレッドをまったく作成していないようです。

私の質問には私のコードが間違っていますし、どうやってスレッディングを修正することができますか?ここで

は私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:ここcython -aによって生成されたHTMLへのリンクです:custom_metric.html

EDIT 2:ここでは、呼び出す方法の例です。対応する関数(最初に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

'prange'のループ本体の中で' omp_get_thread_num() 'に相当するものを印刷しようとしましたか? – Harald

+2

'XB'はPythonオブジェクトである可能性がありますか?http://cython.readthedocs.io/en/latest/src/userguide/parallelism.htmlを参照してください。アノテーションを付けて 'cython -a custom_metric.pyx'を実行します。 – cgohlke

+0

'phausdorff'が' @cython.boundscheck(False) 'と' @cython.wraparound(False) 'で修飾されていれば変更はありますか? –

答えて

4

これは並列化が機能していると思いますが、並列化の余分なオーバーヘッドは、保存した時間を浪費しています。私は、異なるサイズの配列をしようとした場合、私は、並列バージョンは確かに「にISN私のためのシリアルバージョンの時間の〜2月3日を要しパラレルバージョンここで

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

でスピードアップを見始めるん1/4あなたが期待するだろうが、少なくともいくつかの利点を示しています。 (これはかなり大幅に両方のパラレルと非パラレル機能をスピードアップ

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

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

で:私が提供できる


1つの改良は、連続性修正コードを交換することですもともと与えた配列で2倍になります)。 prangeのオーバーヘッドによって遅くなっていることをもう少し明らかにしています。シリアルバージョンは実際には例の配列より高速です。

+0

(コミュニティウィキとして掲示されています。これは解決策を提示しないので、私は賞金の競争からそれを削除したいと思います) – DavidW

関連する問題