【发布时间】:2017-03-16 15:18:06
【问题描述】:
我想缩短 Scipy 的 odeint 求解微分的时间 方程。
为了练习,我使用Python in scientific computations 中的示例作为模板。因为 odeint 将函数 f 作为参数,所以我将此函数编写为静态类型的 Cython 版本并希望
odeint 的运行时间会显着减少。
函数f 包含在名为ode.pyx 的文件中,如下所示:
import numpy as np
cimport numpy as np
from libc.math cimport sin, cos
def f(y, t, params):
cdef double theta = y[0], omega = y[1]
cdef double Q = params[0], d = params[1], Omega = params[2]
cdef double derivs[2]
derivs[0] = omega
derivs[1] = -omega/Q + np.sin(theta) + d*np.cos(Omega*t)
return derivs
def fCMath(y, double t, params):
cdef double theta = y[0], omega = y[1]
cdef double Q = params[0], d = params[1], Omega = params[2]
cdef double derivs[2]
derivs[0] = omega
derivs[1] = -omega/Q + sin(theta) + d*cos(Omega*t)
return derivs
然后我创建一个文件setup.py 来编译函数:
from distutils.core import setup
from Cython.Build import cythonize
setup(ext_modules=cythonize('ode.pyx'))
求解微分方程的脚本(也包含 Python
f) 的版本被称为 solveODE.py,看起来像:
import ode
import numpy as np
from scipy.integrate import odeint
import time
def f(y, t, params):
theta, omega = y
Q, d, Omega = params
derivs = [omega,
-omega/Q + np.sin(theta) + d*np.cos(Omega*t)]
return derivs
params = np.array([2.0, 1.5, 0.65])
y0 = np.array([0.0, 0.0])
t = np.arange(0., 200., 0.05)
start_time = time.time()
odeint(f, y0, t, args=(params,))
print("The Python Code took: %.6s seconds" % (time.time() - start_time))
start_time = time.time()
odeint(ode.f, y0, t, args=(params,))
print("The Cython Code took: %.6s seconds ---" % (time.time() - start_time))
start_time = time.time()
odeint(ode.fCMath, y0, t, args=(params,))
print("The Cython Code incorpoarting two of DavidW_s suggestions took: %.6s seconds ---" % (time.time() - start_time))
然后我运行:
python setup.py build_ext --inplace
python solveODE.py
在终端中。
python版本的时间约为0.055秒, 而 Cython 版本大约需要 0.04 秒。
是否有人建议我改进我解决问题的尝试 微分方程,最好不要用 Cython 修改 odeint 例程本身?
编辑
我在ode.pyx 和solveODE.py 两个文件中加入了DavidW 的建议,运行这些建议的代码只用了大约0.015 秒。
【问题讨论】:
-
您应该将其发布到 codereview
-
我可能会尝试
numba而不是cython,但任何差异都可能很小。大部分计算时间可能是在odeint调用您的函数时发生的上下文切换。老实说,您可能会看到编写自己的数值积分函数(再次使用 cython 或 numba)以避免上下文切换的最佳收益 -
@Farhan.K 我有点同意,但经验表明人们在这里得到的“加速 Cython”问题的答案比 codereview 更好,所以我不确定这是否是个好建议
-
@fabian 我没有通读源代码本身,但你的函数
f和ode.f是python 对象,每次调用至少需要一次上下文切换(4000 次调用 0-200以 0.05 为步长)否则odeint将无法使用任何旧的自定义用户功能。我已经用 numba 获得了 4 倍的加速,但我正在努力获得更多... -
@Farhan.K 不要仅仅因为他们想让代码更快而建议 CodeReview。注意标签在相应板上的受欢迎程度。如果您想改进 C++ 或 Java 代码,CR 非常棒,但在处理像
Cython这样的专用包时,CR 就差了很多。
标签: python scipy cython differential-equations scientific-computing