Как использовать Numba для ускорения интеграции, используя значения из массива для переопределения интеграла - PullRequest
0 голосов
/ 21 декабря 2018

Я попытался получить более быстрое вычисление интегралов, используя 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 сек

1 Ответ

0 голосов
/ 21 декабря 2018

Обратите внимание, что вы измеряете время для назначения переменных и определения включенной функции.

Кроме того, 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)
...