2016-08-19 1 views
8

Cython의 prange을 사용하여 일부 메트릭 계산의 성능을 향상 시키려고합니다. 여기 내 코드는 다음과 같습니다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 

기본적으로, 반복 각각의 하우스 도르프 메트릭은 XAXB[i] 사이에 계산됩니다.

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

내 문제는 모두 순차적 shausdorff 및 병렬 phausdorff가 같은 타이밍을 가지고있다 : 여기에 _hausdorff 함수의 서명입니다. 또한 phausdorff이 스레드를 전혀 생성하지 않는 것으로 보입니다.

내 질문에 내 코드가 잘못되었습니다. 어떻게 스레드를 작동 시키면 고칠 수 있습니까? custom_metric.html

편집 2 : cython -a에 의해 생성 된 HTML에 대한 링크 여기된다

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 
) 

편집 1 : 여기

setup.py입니다 여기에 호출하는 방법에 대한 예입니다 해당 기능 (먼저 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()'과 같은 것을 인쇄 해 보았습니다. http://cython.readthedocs.io/en/latest/src/userguide/parallelism.html – Harald

+2

'XB'가 파이썬 객체 일 수 있습니까? 주석을 가지고'cython -a custom_metric.pyx'를 실행하십시오. – cgohlke

+0

'phausdorff'가'@cython.boundscheck (False)'와'@cython.wraparound (False)'로 꾸며져 있다면 어떤 변화가 있습니까? –

답변

4

필자는 이것이 병렬화가 작동한다고 생각하지만, 병렬화의 추가 오버 헤드로 인해 절약 할 시간을 먹고 있습니다. 나는 다른 크기의 배열을하려고하면 그때 병렬 버전 여기

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

병렬 버전은 확실히 '외설 나를 위해 직렬 버전의 시간 ~ 2/3을 필요에 속도를 볼 시작합니까 1/4 당신이 기대하는,하지만 적어도 몇 가지 이점을 보여줍니다. (이 상당히 크게 두 병렬 및 비 병렬 기능을 속도

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

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

로 : 내가 제공 할 수


한 개선 연속성 수정 코드를 대체하는 것입니다 원래 부여한 어레이의 인수 2). prange의 오버 헤드로 인해 속도가 느려지는 것이 약간 더 분명합니다. 직렬 버전은 실제로 예제의 배열보다 빠릅니다.

+0

(커뮤니티 위키로 게시 됨. 해결책이 없으므로 현상금에 대한 경합에서 제거하고 싶습니다.) – DavidW

관련 문제