Cython偏导数

时间:2014-11-12 00:25:51

标签: python numpy cython

我有一个python脚本,作为进化优化算法的一部分,我正在评估偏导数数千次。我已经逐行完成了一个行,这个偏导数计算占用了大部分的运行时间。我正在使用scipy.optimize.approx_fprime计算偏导数,我试图在cython中重写它而没有太大的成功。

逐行配置文件如下。我的scipy.optimize.approx_fprime的cython化版本简称为approx_fprime

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
84                                           @profile
100      1500     14889652   9926.4     25.3      df1 = approx_fprime(inp_nom,evaluate1,epsilon)
101      1500     14939889   9959.9     25.4      df2 = scipy.optimize.approx_fprime(inp_upp,evaluate1,epsilon)

下面是我的cython文件。

import numpy as np
cimport numpy as np
cimport cython
@cython.boundscheck(False) # turn of bounds-checking for entire function
def approx_fprime(np.ndarray xk, f, double epsilon, *args):
    # From scipy.optimize.approx_fprime
    f0 = f(*((xk,) + args))
    cdef np.ndarray grad = np.zeros((len(xk),), float)
    cdef np.ndarray ei = np.zeros((len(xk),), float)
    cdef np.ndarray d = epsilon * ei
    for k in xrange(len(xk)):
        ei[k] = 1.0
        grad[k] = (f(*((xk + d,) + args)) - f0) / d[k]
        ei[k] = 0.0
    return grad

我试图输入所有相关的类型声明,并确保它与numpy很好地配合。不过,最终,正如他们所说,证据就在于布丁。这个版本并不比scipy版本快。该函数只有一些变量,因此它不是一个庞大的计算,并且在一次迭代中可能只有增量改进的空间。然而,函数被反复调用,因为它被用在进化优化算法中,所以我期望/希望增量性能增益倍增会产生很大的回报。

那里的一位cython专家可以看看这段代码并帮我弄清楚我是否在正确的轨道上,或者这只是一个傻瓜的差事?

谢谢!

1 个答案:

答案 0 :(得分:0)

首先要注意的是优化代码就是要找到代码中的瓶颈。通常很少有功能,循环等消耗大部分时间。这些是优化的合适候选者。最重要的是: 使用分析器评估代码性能

优化python代码的第一件事是逐行遍历代码并检查每一行是否创建了新对象。这是因为对象创建与简单算术相比非常昂贵。经验法则:尽可能避免创建对象。但请确保您没有在时间关键循环中创建任何新对象。

看看f*((xk + d,) + args)。这是非常好的python代码 - 但如果你需要高性能则不适合。它将在循环的每个步骤中创建一个新的参数元组。以不会创建任何对象的方式重写它可能会为您带来巨大的性能提升。

下一步是静态输入。确保键入循环中使用的所有内容。输入k可能会获得很多收益。

之后,您可以尝试通过取消设置boundscheck等来进一步优化。

最重要的是:迭代地进行优化,并通过分析代码来检查性能提升。大多数情况下,很难看出代码中的瓶颈究竟是什么。分析将给你提示:如果优化没有获得太多,你可能错过了瓶颈。