4

numpy配列にアクセスするためにcythonでmemoryviewsを使い始めました。それらが持つさまざまな利点の1つは、古いnumpyバッファサポートよりもかなり高速であることです:http: //docs.cython.org/src/userguide/memoryviews.html#comparison-to-the-old-buffer-support

ただし、古いnumpyバッファのサポートがmemoryviewsよりも高速である例があります。どうすればいいの?!memoryviewsを正しく使用しているかどうか疑問に思いますか?

これは私のテストです:

import numpy as np
cimport numpy as np
cimport cython

@cython.boundscheck(False)
@cython.wraparound(False)
cpdef np.ndarray[np.uint8_t, ndim=2] image_box1(np.ndarray[np.uint8_t, ndim=2] im, 
                                               np.ndarray[np.float64_t, ndim=1] pd,  
                                               int box_half_size):
    cdef unsigned int p0 = <int>(pd[0] + 0.5)  
    cdef unsigned int p1 = <int>(pd[1] + 0.5)    
    cdef unsigned int top = p1 - box_half_size
    cdef unsigned int left = p0 - box_half_size
    cdef unsigned int bottom = p1 + box_half_size
    cdef unsigned int right = p0 + box_half_size    
    cdef np.ndarray[np.uint8_t, ndim=2] box = im[top:bottom, left:right] 
    return box 

@cython.boundscheck(False)
@cython.wraparound(False)
cpdef np.uint8_t[:, ::1] image_box2(np.uint8_t[:, ::1] im, 
                                    np.float64_t[:] pd,  
                                    int box_half_size):

    cdef unsigned int p0 = <int>(pd[0] + 0.5)  
    cdef unsigned int p1 = <int>(pd[1] + 0.5)    
    cdef unsigned int top = p1 - box_half_size
    cdef unsigned int left = p0 - box_half_size
    cdef unsigned int bottom = p1 + box_half_size
    cdef unsigned int right = p0 + box_half_size     
    cdef np.uint8_t[:, ::1] box = im[top:bottom, left:right]   
    return box 

タイミングの結果は次のとおりです。

image_box1:typed numpy:100000ループ、ベスト3:ループあたり11.2 us

image_box2:memoryview:100000ループ、ベスト3:ループあたり18.1 us

これらの測定は、%timeit image_box1(im、pd、box_half_size)を使用してIPythonから実行されます。

4

1 に答える 1

2

大丈夫!問題を見つけました。sebergが指摘したように、測定にはnumpy配列からmemoryviewへの自動変換が含まれていたため、memoryviewsの表示が遅くなりました。

次の関数を使用して、cythonモジュール内から時間を測定しました。

def test(params):   
    import timeit
    im = params[0]
    pd = params[1]
    box_half_size = params[2]
    t1 = timeit.Timer(lambda: image_box1(im, pd, box_half_size))
    print 'image_box1: typed numpy:'
    print min(t1.repeat(3, 10))
    cdef np.uint8_t[:, ::1] im2 = im
    cdef np.float64_t[:] pd2 = pd
    t2 = timeit.Timer(lambda: image_box2(im2, pd2, box_half_size))
    print 'image_box2: memoryview:'
    print min(t2.repeat(3, 10)) 

結果:

image_box1:入力されたnumpy:9.07607864065e-05

image_box2:memoryview:5.81799904467e-05

したがって、memoryviewsは確かに高速です!

image_box2を呼び出す前に、imとpdをmemoryviewsに変換したことに注意してください。この手順を実行せず、imとpdを直接渡すと、image_box2の速度が低下します。

image_box1:入力されたnumpy:9.12262257771e-05

image_box2:memoryview:0.000185245087778

于 2012-10-09T15:22:05.153 に答える