Я хотел ускорить функцию, которую часто использую, и думал об использовании cython. Однако, попробовав все возможные оптимизации cython, которые мне удалось найти в документации, код cython примерно в 6 раз медленнее, чем функция python+numpy. Разочаровывает!
Это мой тестовый код: (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?
ИЗМЕНИТЬ:
Просто для протокола: еще одна вещь, которую я пытался ускорить, - это передача точек в порядке фортрана, поскольку мои точки хранятся в столбцах, и их довольно много. Я также определяю локальный tmp как порядок fortran. Я думаю, что часть вычитания функции должна быть быстрее, но numpy.dot, похоже, требует вывода порядка C (в любом случае, чтобы обойти это?), Так что в целом с этим тоже нет ускорения. Я также попытался переставить точки так, чтобы часть вычитания выполнялась быстрее в порядке C, но кажется, что скалярное произведение по-прежнему является самой дорогой частью.
Кроме того, я заметил, что numpy.dot не может использовать представления памяти в качестве аргумента out, даже если это порядок C, это ошибка?
numpy
уже использует для расчетов библиотекиc
иfortran
. обычно вам не нужно ничего делать, чтобы получить ускорение. - person none   schedule 14.10.2012