【问题标题】:Cythonized function unexpectedly slowCythonized 功能意外缓慢
【发布时间】:2012-10-04 07:37:11
【问题描述】:

我想加快一个我经常使用的功能,我想使用 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 加速吗?

编辑:

为了记录,我试图加速该功能的另一件事是按 fortran 顺序传递点,因为我的点存储在列中并且其中有很多。我还将本地 tmp 定义为 fortran 顺序。我认为函数的减法部分应该更快,但 numpy.dot 似乎需要 C 顺序输出(无论如何要解决这个问题?),所以总的来说也没有加速。我还尝试转置点,以便 C 顺序中的减法部分更快,但似乎点积仍然是最昂贵的部分。

另外,我注意到 numpy.dot 不能使用 memoryviews 作为 out 参数,即使它是 C 顺序,这是一个错误吗?

【问题讨论】:

  • numpy 已经在使用 cfortran 库进行计算。通常你不需要做任何事情来获得加速..

标签: python numpy cython


【解决方案1】:

看看你的代码,它看起来像是 numpy 已经非常优化的东西(数组和点积的减法。)。

Cython 非常适合加速 numpy 通常表现不佳的情况(例如,迭代是用 python 编写的迭代算法),但在这种情况下,内部循环已经由 BLAS 库执行。

如果您想加快速度,我首先要看的是 BLAS/LAPACK/ATLAS/etc 库 numpy 所链接的对象。在这种情况下,使用“调整过的”线性代数库(例如 ATLAS 或英特尔的 MKL)会产生很大的差异(在某些情况下超过 10 倍)。

要了解您当前使用的内容,请查看numpy.show_config() 的输出

【讨论】:

  • 好的,谢谢,我明白了。我已经运行了 numpy.show_config() 但我不确定如何解释结果:
    mkl_info: libraries = ['mkl_lapack95', 'mkl_blas95', 'mkl_intel_c', ...] library_dirs = ['C:/Program Files (x86)/Intel/Compiler/11.1/070/mkl/ia32/lib'] define_macros = [('SCIPY_MKL_H', None)] include_dirs = ['C:/Program Files (x86)/Intel/Compiler/11.1/070/mkl/include'] 我得到了 lapack_opt_info、blas_opt_info、lapack_mkl_info 和 blas_mkl_info 的类似结构这是否意味着我的 numpy 版本与 MKL 相关联?或 [('SCIPY_MKL_H', None)] 表示没有?
  • 仅作记录,我的 numpy 版本是 '1.6.2',我在 windows7 机器上安装了 EPD 免费分发版
  • 是的,您的 numpy 已与 MKL 链接。那么我的建议对你帮助不大。 MKL 已尽您所能优化。
  • 另一个想法:对于小型输入数组,您通常会多次调用它吗?调用任何特定的 numpy 函数都会产生很多开销。如果您正在迭代一个更大的数组并多次调用此函数,您可以通过使用tensordoteinsum 并一次对所有更大的数组进行操作来获得加速。当然,如果您不遍历更大的数组,这将无济于事。
  • 好的,谢谢。我用数百个点调用这个函数,这是最小化过程中目标函数的一部分。其实我说的就是最小化here我想我不能把所有的点放在一起,因为最小化是连续的。
猜你喜欢
  • 1970-01-01
  • 2023-04-01
  • 2015-12-15
  • 1970-01-01
  • 2018-11-11
  • 2017-11-08
  • 1970-01-01
  • 2016-10-08
  • 2018-05-19
相关资源
最近更新 更多