Сокращение времени выполнения для графика CCH - PullRequest
0 голосов
/ 24 октября 2018

Я пытаюсь сократить время, необходимое для отображения следующей функции:

def cch(tau):
    return np.sum(abs(-1*np.diff(cartprod)-tau)<0.001)

, где "cartprod" - это сокращение от:

cartprod = np.asarray(list(itertools.product(times1,times2)))

times1 и times2 - спискичьи элементы распространяются не более чем на 0,25 от примерно 0,0123 до примерно 99,9948.В списке также около 5000 элементов.Если вы родом из области неврологии, это время всплеска.ПРИМЕЧАНИЕ: эта информация избыточна для проблемы, но только для любопытных.

Я отображаю ее на графике с помощью следующего материала для черчения:

t = np.linspace(-0.25,0.25,1250) 
vfunc = np.vectorize(cch)
y = vfunc(t)
plt.plot(t,y,'g')

построение графика занимает около 4 минут.Меня не слишком беспокоит время прорисовки (пока оно разумно: скажем, в течение 5-10 минут).Что меня беспокоит, так это то, что мне придется составить график в среднем по 10 000 этих функций, и я должен быть в состоянии сделать это быстро.Есть ли способ ускорить каждый вызов функции с помощью numba или алгоритмического улучшения?

Спасибо

1 Ответ

0 голосов
/ 30 октября 2018

Я не могу воспроизвести ваш код с использованием np.vectorize, поскольку формы t с (1250,) и cartprod с (25000000, 2) (я предположил это из длины ваших списков times1 и times2) не совпадают.

Кроме того, к сожалению, функции numpy, необходимые для ускорения этого процесса, еще не реализованы в numba.Но все же переписывание вашего кода в numpy дает значительно улучшенную скорость.На моем компьютере вычисление cartprod можно легко ускорить примерно в 25 раз.

def cartprod(arr_times1, arr_times2):
    res = np.empty((arr_times1.size * arr_times2.size, 2))
    res[:, 0] = np.repeat(arr_times1, arr_times2.size)
    res[:, 1] = np.tile(arr_times2, arr_times1.size)
    return res
def cartprod_iter(times1, times2):
    return np.asarray(list(itertools.product(times1, times2)))

arr_times1 = np.random.rand(5000)
arr_times2 = np.random.rand(5000)
times1 = list(arr_times1)
times2 = list(arr_times2)

%timeit cartprod_iter(times1, times2)
%timeit cartprod(arr_times1, arr_times1)
# 12.9 s ± 954 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# 521 ms ± 53.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
print(np.all(cartprod(arr_times1, arr_times1) == cartprod_iter(times1, times2)))
# Out: True

Теперь для функции cch:
np.tile и np.repeat can 'Тумба в сочетанииЕсли вы хотите jit cch, вам нужно будет переписать их вручную.Или вы можете jit некоторые части функции cch:

import numba as nb
@nb.njit
def cch_core(cp, tau):
    return np.sum(np.abs(-1 * np.diff(cp) - tau) < 0.001)

def cch_nb(arr_times1, arr_times2, tau):
    cp = cartprod(arr_times1, arr_times2)
    return cch_core(cp, tau)

def cch(arr_times1, arr_times2, tau):
    return np.sum(np.abs(-1 * np.diff(cartprod(arr_times1, arr_times2)) - tau) < 0.001)

tau2 = np.linspace(-0.25, 0.25, 50)

%timeit cch_nb(arr_times1, arr_times2, tau2)
#2.81 s ± 144 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit cch(arr_times1, arr_times2, tau2)
#15.2 s ± 494 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
print(cch_nb(arr_times1, arr_times2, tau2) == cch(arr_times1, arr_times2, tau2))
# Out: True

Это еще одно ускорение в 5,4 раза.Я использовал уменьшенный прицел tau, чтобы сделать время возможным.Кроме того, tau формы (1250,) приведет к ошибке памяти без numba, но будет работать с numba!

Если вам нужна большая скорость, вам нужно внедрить itertools.product в numba самостоятельно.Если этот код работает неправильно: учтите, что код, который вы разместили в своем вопросе, не может быть воспроизведен.Размещение полностью работающего минимального примера может помочь.

...