2

私がよく使っている関数を高速化したいと思っていたので、cython の使用について考えました。ただし、ドキュメントで見つけたすべての可能な cython 最適化を試した後、cython コードは python+numpy 関数よりも約 6 倍遅くなります。残念!

これは私のテスト コードです: (forward1 は python 関数、forward2 は cython 関数です)

#geometry.py
def forward1(points, rotation, translation):
    '''points are in columns'''
    return np.dot(rotation, points - translation[:, np.newaxis])

#geometry.pyx
import numpy as np
cimport numpy as np
cimport cython

@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
cdef np.float64_t[:,:] forward2(np.float64_t[:,:] points, np.float64_t[:,:] rotation, np.float64_t[:] translation):
    '''points are in columns'''
    cdef unsigned int I, J
    I = points.shape[0]
    J = points.shape[1]
    cdef np.float64_t[:,:] tmp = np.empty((I, J), dtype=np.float64)
    cdef unsigned int i
    for i in range(J):
        tmp[0, i] = points[0, i] - translation[0]        
        tmp[1, i] = points[1, i] - translation[1]        
    cdef np.float64_t[:,:] result = np.dot(rotation, tmp)
    return result

def test_forward2(points, rotation, translation):
    import timeit
    cdef np.float64_t[:,:] points2 = points
    cdef np.float64_t[:,:] rotation2 = rotation
    cdef np.float64_t[:] translation2 = translation
    t = timeit.Timer(lambda: forward2(points2, rotation2, translation2))
    print min(t.repeat(3, 10))

そして、私はそれを計ります:

t = timeit.Timer(lambda: forward1(points, rotation, translation))
print min(t.repeat(3, 10))
0.000368164520751

test_forward2(points, rotation, translation)
0.0023365181969

cython コードを高速化するためにできることはありますか?

cython で forward1 を高速化できない場合、weave を使用して高速化を期待できますか?

編集:

記録のために、関数を高速化するために私が試みたもう 1 つのことは、ポイントが列に格納されており、それらの数がかなりあるため、Fortran の順序でポイントを渡すことです。また、ローカル tmp を fortran オーダーとして定義します。関数の減算部分はもっと高速にすべきだと思いますが、numpy.dot には C オーダーの出力が必要なようです (とにかくこれを回避するには?)。減算部分がCオーダーで速くなるようにポイントを転置することも試みましたが、内積は依然として最も高価な部分のようです。

また、numpy.dot は C オーダーであってもメモリビューを out 引数として使用できないことに気付きましたが、これはバグですか?

4

1 に答える 1

4

numpyあなたのコードをちらりと見るだけで、それはすでに非常に最適化されて いるもの(配列と内積の減算)のように見えます。

Cython は、numpy のパフォーマンスがよくない場合 (たとえば、反復が Python で記述された反復アルゴリズム) の高速化に優れていますが、この場合、内側のループは既に BLAS ライブラリによって実行されています。

スピードアップしたい場合は、最初に調べるのは、numpy がリンクされている BLAS/LAPACK/ATLAS/etc ライブラリです。「調整された」線形代数ライブラリ (ATLAS や Intel の MKL など) を使用すると、このような場合に大きな (場合によっては 10 倍以上) 差が生じます。

現在使用しているものを調べるには、の出力を見てくださいnumpy.show_config()

于 2012-10-13T21:40:21.567 に答える