我想加快我经常使用的功能,并且我考虑使用 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 代码做些什么来使其更快吗?
如果forward1无法在cython中加速,我可以希望使用weave加速吗?
EDIT:
仅供记录,我尝试加快该功能的另一件事是按 Fortran 顺序传递点,因为我的点存储在列中,并且其中有相当多的列。我还将本地 tmp 定义为 fortran 命令。我认为函数的减法部分应该更快,但 numpy.dot 似乎需要 C 阶输出(无论如何要解决这个问题?),所以总的来说,这也没有加速。我还尝试转置这些点,以便减法部分在 C 顺序中更快,但似乎点积仍然是最昂贵的部分。
另外,我注意到 numpy.dot 不能使用内存视图作为输出参数,即使它是 C 顺序,这是一个错误吗?