Python 加速scipy中集成的功能评估

Python 加速scipy中集成的功能评估,python,numpy,scipy,Python,Numpy,Scipy,我正在尝试将代码从Matlab移植到SciPy。以下是我迄今为止编写的代码的简化版本:。然而,Python版本比Matlab慢得多。我在要点中包含了评测结果,它们显示python几乎90%的时间都花在函数f的评估上。除了用C或Cython重写它之外,还有什么方法可以加快它的计算速度吗?您的numpy版本在速度上可能与旧的MATLAB运行相当。但是新的MATLAB版本进行各种形式的即时编译,大大加快了重复计算的速度 我的猜测是,你可以一点一点地啃掉lambda和f代码,也许可以将它们的计算时间减半

我正在尝试将代码从Matlab移植到SciPy。以下是我迄今为止编写的代码的简化版本:。然而,Python版本比Matlab慢得多。我在要点中包含了评测结果,它们显示python几乎90%的时间都花在函数
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