【问题标题】:How to use numba for speeding up integration using values from array to redefine the integral如何使用 numba 加速积分,使用数组中的值重新定义积分
【发布时间】:2019-05-21 15:19:50
【问题描述】:

我尝试使用 python numba 更快地计算积分。即使使用 numba 进行单次计算的时间几乎快 10 倍,但当我循环重新定义积分的过程时,它变得非常慢。我尝试过使用其他装饰器,例如 @vectorize@jit,但没有成功。有什么建议吗?

import numpy as np
import datetime as dd
from scipy.integrate import quad
from numba import cfunc, types, carray
tempText = 'Time Elapsed: {0:.6f} sec'
arr = np.arange(0.01,1.01,0.01)
out = np.zeros_like(arr)
def tryThis():           # beginner's solution
    for i in range(len(arr)):
        def integrand(t):
            return np.exp(-arr[i]*t)/t**2
        def do_integrate(func):
            return quad(func,1,np.inf)[0]
        out[i] = do_integrate(integrand)
    # print (out)
init = dd.datetime.now()
tryThis()
print (tempText.format((dd.datetime.now()-init).total_seconds()))

经过的时间:0.047950 秒

def try2VectorizeThat(): # using numpy
    def do_integrate(arr):
        def integrand(t):
            return np.exp(-arr*t)/t**2
        return quad(integrand,1,np.inf)[0]
    do_integrate = np.vectorize(do_integrate)
    out = do_integrate(arr)
    # print (out)
init = dd.datetime.now()
try2VectorizeThat()
print (tempText.format((dd.datetime.now()-init).total_seconds()))

经过的时间:0.026424 秒

def tryThisFaster():    # attempting to use numba
    for i in range(len(arr)):
        def get_integrand(*args):
            a = args[0]
            def integrand(t):
                return np.exp(-a*t)/t**2
            return integrand
        nb_integrand = cfunc("float64(float64)")(get_integrand(arr[i]))
        def do_integrate(func):
            return quad(func,1,np.inf)[0]
        out[i] = do_integrate(nb_integrand.ctypes)
    # print (out)
 init = dd.datetime.now()
tryThisFaster()
print (tempText.format((dd.datetime.now()-init).total_seconds()))

经过的时间:1.905140 秒

【问题讨论】:

    标签: python arrays scipy integration numba


    【解决方案1】:

    请注意,您正在测量分配变量和定义包含的函数的时间。

    此外,numba 可能会在作业太小时变得(或看起来)更慢,因为它需要时间来编译自身然后应用。

    integrand 放在循环之外并使用@njit 进行装饰可以提高性能。让我们看一些比较:

    from numba import njit
    @njit
    def integrand(t, i):
        return np.exp(-arr[i]*t)/t**2
    
    def tryFaster():     
        for i in range(len(arr)):
            out[i] = quad(integrand, 1, np.inf, args=(i))[0]
    

    len(arr) = 100时所用的时间:

    arr = np.arange(0.01,1.01,0.01)
    
    %timeit tryThis()
    # 29.9 ms ± 4.59 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    %timeit tryFaster()
    # 4.99 ms ± 11.5 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
    

    len(arr) = 10,000时所用的时间:

    arr = np.arange(0.01,100.01,0.01)
    
    %timeit tryThis()
    # 1.43 s ± 208 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    %timeit tryFaster()
    # 142 ms ± 17.7 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    

    【讨论】:

    • 值得一提的是,Numba 编译函数中实际上没有全局变量。它们是编译时常量,如果不重新编译就无法更改。
    • 答案是正确的,但是,@max9111 的评论让我意识到为什么我试图做的事情没有奏效。谢谢你们俩。
    猜你喜欢
    • 1970-01-01
    • 2016-12-13
    • 1970-01-01
    • 1970-01-01
    • 2018-08-26
    • 2021-06-19
    • 2016-12-13
    • 2021-01-31
    • 2022-10-05
    相关资源
    最近更新 更多