Python 加速scipy中集成的功能评估
我正在尝试将代码从Matlab移植到SciPy。以下是我迄今为止编写的代码的简化版本:。然而,Python版本比Matlab慢得多。我在要点中包含了评测结果,它们显示python几乎90%的时间都花在函数Python 加速scipy中集成的功能评估,python,numpy,scipy,Python,Numpy,Scipy,我正在尝试将代码从Matlab移植到SciPy。以下是我迄今为止编写的代码的简化版本:。然而,Python版本比Matlab慢得多。我在要点中包含了评测结果,它们显示python几乎90%的时间都花在函数f的评估上。除了用C或Cython重写它之外,还有什么方法可以加快它的计算速度吗?您的numpy版本在速度上可能与旧的MATLAB运行相当。但是新的MATLAB版本进行各种形式的即时编译,大大加快了重复计算的速度 我的猜测是,你可以一点一点地啃掉lambda和f代码,也许可以将它们的计算时间减半
f
的评估上。除了用C或Cython重写它之外,还有什么方法可以加快它的计算速度吗?您的numpy
版本在速度上可能与旧的MATLAB运行相当。但是新的MATLAB版本进行各种形式的即时编译,大大加快了重复计算的速度
我的猜测是,你可以一点一点地啃掉lambda
和f
代码,也许可以将它们的计算时间减半。但真正的杀手是你打了这么多次电话给f
首先,我会尝试在
f
中预先计算事物。例如,定义K1=K[1]
并在计算中使用K1
。这将减少索引调用的数量。指数的一部分是重复的吗?可能用常规的def
替换lambda
定义,或者将其与f
组合,正如我在评论中提到的那样,如果考虑到矩阵是对称的,您可以取消大约一半对quad
的调用(因此也可以取消复杂的函数f
)
在纯python中,通过重写这个复杂的函数可以进一步提高速度。我做的大部分都是出于同情
最后,我尝试使用np.vectorize
对quad
调用进行矢量化
from scipy.integrate import quad
from scipy.special import jn as besselj
from scipy import exp, zeros, linspace
from scipy.linalg import norm
import numpy as np
def complicated_func(lmbd, a, n, k):
u,v,w = 5, 3, 2
x = a*lmbd
fac = exp(2*x)
comm = (2*w + x)
part1 = ((v**2 + 4*w*(w + 2*x) + 2*x*(x - 1))*fac**5
+ 2*u*fac**4
+ (-v**2 - 4*(w*(3*w + 4*x + 1) + x*(x-2)) + 1)*fac**3
+ (-8*(w + x) + 2)*fac**2
+ (2*comm*(comm + 1) - 1)*fac)
return part1/lmbd *besselj(n+1, lmbd) * besselj(k+1, lmbd)
def perform_quad(n, k, a):
return quad(complicated_func, 0, np.inf, args=(a,n,k))[0]
def improved_main():
sz = 20
amatrix = np.zeros((sz,sz))
ls = -np.linspace(1, 10, 20)/2
inds = np.tril_indices(sz)
myv3 = np.vectorize(perform_quad)
res = myv3(inds[0], inds[1], ls.reshape(-1,1))
results = np.empty(res.shape[0])
for rowind, row in enumerate(res):
amatrix[inds] = row
symm_matrix = amatrix + amatrix.T - np.diag(amatrix.diagonal())
results[rowind] = norm(symm_matrix)
return results
计时结果显示速度提高了5倍(如果我只运行了一次,请原谅,它需要足够长的时间):
如果你立即用它的平方替换v
,也会有一个微增益,因为这是唯一一次在这个复杂函数中使用它:作为它的平方
对besselj
的调用中也存在大量重复,但我不知道如何避免,因为quad
将确定lmbd
,因此您无法轻松地预计算这些值,然后执行查找
如果您分析improved_main
,您将看到对complexed_func
的调用量几乎减少了2倍(对角线仍需要计算)。所有其他速度的提高都归功于np.vectorize
和复杂函数的改进
我的系统上没有Matlab,因此如果您改进那里的复杂函数,我无法对其速度增益做出任何说明。在动态类型语言中,您无法获得真正的速度。如果你想接近matlab,你必须开始静态地键入你的对象。我认为赛昂是正确的选择。你为什么不首先使用赛昂?你希望获得什么样的速度增益?我已经看过你的代码了,考虑到矩阵的对称性,你可以立即得到因子2。我这边的一些优化将运行时间从35.8秒减少到了8.2秒,但您可能希望获得更好的速度增益。在任何情况下,从Matlab强制复制粘贴将导致次优代码(顺便说一句,这种比较也不完全公平:Matlab有JIT,CPython没有)。无论如何,用C重写它仍然无法摆脱f
的大量求值,这是由quad
完成的。我完全忽略了这个矩阵是对称的这一事实。通过这一点和矢量化,我得到了7s的计时,因此f
中的简化似乎没有那么有用(我的意思是x
,fac
和comm
预计算值)。谢谢你,奥利弗,这些改进。@vaeea不客气。我认为这是一个有趣的问题,因为它不容易进行矢量化。顺便说一句,我读到np.vectorize
更像是一个方便的函数,它封装了一些循环,而不是人们通常所说的真正的矢量化。我也看到它更多地用于将循环包装在n、k
和a
上。
In [11]: %timeit -n1 -r1 improved_main()
1 loops, best of 1: 6.92 s per loop
In [12]: %timeit -n1 -r1 main()
1 loops, best of 1: 35.9 s per loop