2017-02-21 27 views
1

Когда я пытаюсь скомпилировать код ниже, я получаю ошибкуCython отпускающий Жиль, когда мне нужно размер Numpy массива

return sign_match.sum()/y_true.shape[0] 
            ^

Преобразование в Python объект не допускается без Gil

Есть ли простой способ преодолеть это? Самое жизнеспособное решение, о котором я могу думать, - передать длину массивов в качестве другого аргумента. Я использую python 3.3.5.

cimport cython 
cimport numpy as np 


# Returns negative mean-squared error 
cdef double negative_mse(np.ndarray[double, ndim=1] y_true, 
         np.ndarray[double, ndim=1] y_pred) nogil: 
    cdef np.ndarray[double, ndim=1] err 
    err = y_true - y_pred 

    return -(err * err).sum()/y_true.shape[0] 

ответ

3

y_true и y_pred массивы, и, таким образом, объекты Python. Поэтому для любой операции, использующей их, потребуется gil, а не только форма.

Попробуйте компилировать без nogil и посмотрите на -a html. Какие линии темно-желтые, со многими ссылками на объекты Python?

+11:  return -(err * err).sum()/y_true.shape[0] 
    __pyx_t_7 = PyNumber_Multiply(((PyObject *)__pyx_v_err), ((PyObject *)__pyx_v_err)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 11, __pyx_L1_error) 
    __Pyx_GOTREF(__pyx_t_7); 
    __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_sum); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 11, __pyx_L1_error) 
    __Pyx_GOTREF(__pyx_t_8); 
    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; 
    .... 

Только часть расширенного кода C для вашего файла. См. Все звонки Pyx... Все они требуют gil.

http://docs.cython.org/en/latest/src/userguide/memoryviews.html показывает, что вы можете использовать nogil по памяти для массива numpy.

Рисунок из руководства memoryview я написал эту альтернативную функцию

cpdef double neg_mse_view(double[:] y_true, double[:] y_pred): 
    cdef double x, res 
    cdef int I 
    I = y_true.shape[0] 
    res = 0 
    for i in range(I): 
     x = y_true[i]-y_pred[i] 
     res += -(x*x) 
    res = res/I 
    return res 

Это можно назвать таким же образом. Эти тайминги показывают 2x ускорение. nogil работает, но не имеет значения.

In [10]: a=np.arange(1000000.) 
In [11]: timeit negmse.negative_mse(a,a-10) 
10 loops, best of 3: 16.9 ms per loop 
In [12]: timeit negmse.neg_mse_view(a,a-10) 
100 loops, best of 3: 7.17 ms per loop 
In [13]: timeit negmse.neg_mse_nogil(a,a-10) 
100 loops, best of 3: 7.19 ms per loop 

Для функции это простой, чистый NumPy версия, в основном, как хорошо:

In [20]: timeit ((a-(a-10))**2).sum()/a.shape[0] 
100 loops, best of 3: 16.8 ms per loop 
+0

ти ти! haha Я бы подумал, что numpy будет так же быстро. Я хотел использовать функцию nogil (небольшую часть большего процесса) внутри цикла. Мне просто нужен простой пример для начала. Это очень полезно. – itzjustricky