私がよく使っている関数を高速化したいと思っていたので、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 引数として使用できないことに気付きましたが、これはバグですか?