Numba и Cython существенно не улучшают производительность по сравнению с CPython, может, я неправильно их использую?

БОЛЬШОЕ РЕДАКТИРОВАНИЕ:

================

Для ясности я удаляю старые результаты и заменяю их более свежими. Вопрос все тот же: правильно ли я использую и Cython, и Numba, и какие улучшения в код можно внести? (У меня есть более новая и более простая временная записная книжка IPython со всем кодом и результатами здесь)

1)

Думаю, я понял, почему изначально не было разницы между Cython, Numba и CPython: это потому, что я их накормил

массивы numpy в качестве ввода:

x = np.asarray([x_i*np.random.randint(8,12)/10 for x_i in range(n)])

вместо списков:

x = [x_i*random.randint(8,12)/10 for x_i in range(n)]

Тестирование с использованием массивов Numpy в качестве входных данных

введите описание изображения здесь

Тестирование с использованием списков Python в качестве входных данных

введите описание изображения здесь

2)

Я заменил функцию zip() явными циклами, однако особой разницы это не имело. Код будет таким:

CPython

def py_lstsqr(x, y):
    """ Computes the least-squares solution to a linear matrix equation. """
    len_x = len(x)
    x_avg = sum(x)/len_x
    y_avg = sum(y)/len(y)
    var_x = 0
    cov_xy = 0
    for i in range(len_x):
        temp = (x[i] - x_avg)
        var_x += temp**2
        cov_xy += temp*(y[i] - y_avg)
    slope = cov_xy / var_x
    y_interc = y_avg - slope*x_avg
    return (slope, y_interc) 

Cython

%load_ext cythonmagic

%%cython
def cy_lstsqr(x, y):
    """ Computes the least-squares solution to a linear matrix equation. """
    cdef double x_avg, y_avg, var_x, cov_xy,\
         slope, y_interc, x_i, y_i
    cdef int len_x
    len_x = len(x)
    x_avg = sum(x)/len_x
    y_avg = sum(y)/len(y)
    var_x = 0
    cov_xy = 0
    for i in range(len_x):
        temp = (x[i] - x_avg)
        var_x += temp**2
        cov_xy += temp*(y[i] - y_avg)
    slope = cov_xy / var_x
    y_interc = y_avg - slope*x_avg
    return (slope, y_interc)

Нумба

from numba import jit

@jit
def numba_lstsqr(x, y):
    """ Computes the least-squares solution to a linear matrix equation. """
    len_x = len(x)
    x_avg = sum(x)/len_x
    y_avg = sum(y)/len(y)
    var_x = 0
    cov_xy = 0
    for i in range(len_x):
        temp = (x[i] - x_avg)
        var_x += temp**2
        cov_xy += temp*(y[i] - y_avg)
    slope = cov_xy / var_x
    y_interc = y_avg - slope*x_avg
    return (slope, y_interc)

person Community    schedule 08.05.2014    source источник
comment
Для вашего первого примера я бы не ожидал, что numba принесет значительный выигрыш, поскольку вы все равно выполняете все вычисления в numpy.   -  person BrenBarn    schedule 08.05.2014
comment
Спасибо, есть предложения, как я могу реализовать его в Numba, чтобы сравнить с CPython? Из документации Numba я прочитал, что Numba - это специализированный компилятор, работающий точно в срок, который компилирует аннотированный код Python и NumPy в LLVM (через декораторы). , поэтому я подумал, что код Numpy тоже выиграет   -  person    schedule 08.05.2014
comment
Из примеров на странице Numba я ожидал, что это может ускорить код, который использует циклы кода Python над структурами numpy, но ваш пример ничего не делает, кроме вызова функций numpy, которые уже написаны на C. Я мало знаю о Нумба, но я думаю, ты не сможешь ускорить свой первый пример. Отсутствие ускорения во втором примере немного более удивительно, посмотрим, ответит ли кто-нибудь, кто знает больше о Numba.   -  person BrenBarn    schedule 08.05.2014
comment
Вот почему я также реализовал его как классический подход, в котором я вообще не использую Numpy. Я добавил рисунок, чтобы показать вам, что Cython значительно улучшает производительность, скомпилировав его на C, но Numba этого не делает.   -  person    schedule 08.05.2014
comment
Самым быстрым методом может быть использование np.linalg.lstsq, а не выполнение обычных уравнений.   -  person YXD    schedule 08.05.2014
comment
Кстати, фантастический репозиторий.   -  person YXD    schedule 08.05.2014
comment
Спасибо, но на самом деле np.linalg.lstsq работает медленнее! Самый быстрый подход - реализовать классический в Cython. Я провел тест Cython vs. numpy (np.linalg.lstsq) vs. scipy (scipy.stats.linregress) здесь   -  person    schedule 08.05.2014
comment
@BrenBarn Нет, это только половина правды;) Я использую Numpy (специально) только для одного сравнения: numba_mat_lstsqr (x, y) vs. py_mat_lstsqr (x, y). И второе сравнение numba_lstsqr (x, y) vs py_lstsqr (x, y) полностью без numpy   -  person    schedule 09.05.2014
comment
@SebastianRaschka: Да, может быть, я не понял. Под вашим первым примером я имел в виду сравнение между py_mat_lstsqr и numba_mat_lstsqr (что меня не удивляет). Но то, что я называю вашим вторым примером, - это сравнение между numba_lstsqr и py_lstsqr (что меня удивляет). Погуглив, я вижу несколько случаев, когда кто-то сказал, что Numba не может вывести типы в некоторых функциях, поэтому не было ускорения, но я недостаточно знаю о Numba, чтобы знать, что здесь происходит, или как улучшить Это.   -  person BrenBarn    schedule 09.05.2014
comment
@BrenBarn Спасибо за разъяснения! Да, это меня тоже удивляет, и мне просто интересно, что с этим можно сделать. Когда я, например, использую Cython, у меня есть ~ 30-кратное улучшение, когда я вообще не меняю код, и ~ 80-кратное улучшение, когда я добавляю объявления статического типа.   -  person    schedule 09.05.2014
comment
@SebastianRaschka, Cython не дает вам увеличения скорости без объявления типов. Ваш %pylab inline вызов перезаписывает sum встроенный, что нарушает ваши тайминги. Я тебе это сказал. Я написал эту кучу кода, чтобы доказать это вам. Так почему вы все еще говорите, что у меня есть ~ 30-кратные улучшения, когда я вообще не меняю код? ...   -  person Veedrac    schedule 09.05.2014
comment
Это про CPython или Cython? Может быть, стоит подумать об изменении названия вопроса.   -  person Jonas Schäfer    schedule 09.05.2014
comment
@Veedrac Да, но это не должно быть проблемой, так как время рассчитывается ДО того, как я загружу% pylab   -  person    schedule 09.05.2014
comment
@JonasWielicki на самом деле это Numba против CPython, и просто для сравнения я добавил Cython против CPython   -  person    schedule 09.05.2014
comment
@Veedrac Я заменю эти строчки% pylab на строчки% matplotlib, которые, как мне кажется, этого не делают. Также я обязательно перезапускаю ядро ​​после каждого шага тайминга / построения графика. Это займет некоторое время, также я удалю zip (), чтобы посмотреть, как будет работать Numba ... еще раз спасибо   -  person    schedule 09.05.2014
comment
@SebastianRaschka Я не понимаю, как вы можете сказать это, когда это буквально третий блок в вашем блокноте iPython. : /   -  person Veedrac    schedule 09.05.2014
comment
Я обновил исходный пост - проблема была вызвана множеством массивов, которые я передал в качестве входных данных ... но я все еще недоволен производительностью, или это максимум, что я могу получить для этого кода?   -  person    schedule 10.05.2014


Ответы (2)


Вот что, я думаю, происходит с Numba:

Numba работает с Numpy массивами. Ничего больше. Все остальное не имеет отношения к Numba.

zip возвращает итератор произвольных элементов, в которые Numba не может заглянуть. Таким образом, Numba не может много компилировать.

Цикл по индексам с for i in range(...), вероятно, даст гораздо лучший результат и позволит более надежный вывод типов.

person Veedrac    schedule 09.05.2014
comment
Спасибо! Я перепишу его и переделаю тест на этих выходных. Сообщу о результатах! - person ; 09.05.2014
comment
zip не так уж и много ... Я заменил его сейчас, но настоящая проблема заключалась в массиве numpy, который я передал в качестве входных данных. - person ; 10.05.2014
comment
Насколько я понимаю, дело не в том, что Numba не может видеть ничего, кроме Numpy, а в том, что способ, которым он справляется с такими вещами, не является улучшением. Ознакомьтесь с Numba - Скажи этим хулиганам C ++, чтобы они заблудились, чтобы получить отличное объяснение многого. Нумбы. - person Post169; 13.06.2018

Использование встроенной sum () может вызвать проблемы.

Вот код линейной регрессии, который будет работать быстрее в Numba:

@numba.jit
def ols(x, y):
    """Simple OLS for two data sets."""
    M = x.size

    x_sum = 0.
    y_sum = 0.
    x_sq_sum = 0.
    x_y_sum = 0.

    for i in range(M):
        x_sum += x[i]
        y_sum += y[i]
        x_sq_sum += x[i] ** 2
        x_y_sum += x[i] * y[i]

    slope = (M * x_y_sum - x_sum * y_sum) / (M * x_sq_sum - x_sum**2)
    intercept = (y_sum - slope * x_sum) / M

    return slope, intercept
person Turtles Are Cute    schedule 18.04.2015