Массив cyth numpy с Openmp (No GIL)

Я не уверен, если это было адресовано ранее, я пытался искать, но не нашел именно то, что я искал. Я хотел бы, чтобы следующий код работал (имя файла some_CD.дарохранительница)

import numpy as np
cimport numpy as np
cimport cython
from cython.parallel import *

ctypedef np.float64_t DTYPE

cdef DTYPE evaluate_objective(np.ndarray[DTYPE, ndim=2] A,np.ndarray[DTYPE, ndim=1] b,np.ndarray[DTYPE, ndim=1] x):
    return x.dot(A.dot(x) - b.dot(x))

cpdef DTYPE coordinate_descent(np.ndarray[DTYPE, ndim=2] A,np.ndarray[DTYPE, ndim=1] b,int nDim, int nIter ):
    cdef int i, iter
    cdef np.ndarray[DTYPE,
                    ndim=1] x = 
                    np.zeros(nDim, )
    cdef DTYPE temp
    for iter in prange(nIter,nogil=True):
        i = (iter%nDim)
        temp = (b[i]-( A[:,i].dot(x)*x[i] ) + (A[i,i]*x[i]*x[i]))/A[i,i]
        x[i] = np.max([0,np.min([temp,1])])
    return evaluate_objective(A,b,x)

Мой setup.py выглядит следующим образом

from distutils.core import setup, Extension
from Cython.Build import cythonize
import numpy

ext_modules = [
    Extension(
        "some_CD",
        ["some_CD.pyx"],
        extra_compile_args=['-fopenmp'],
        extra_link_args=['-fopenmp'],
    )
]

setup(
    name='some_parallel',
    ext_modules=cythonize(ext_modules),
    include_dirs=[numpy.get_include()]
)

Есть много вещей, в которых я не уверен в этом коде. Прежде всего, правильно ли я использую массивы numpy? Использует float64, np.int типизированные переменные, разрешенные в prange?

1 ответ

  1. Этот цикл нельзя распараллелить, потому что это итерационный алгоритм. Другими словами, последующие итерации зависят от результата предыдущих итераций.

    Игнорируя эту проблему, вот как вы бы изменили код..

    Без GIL вы можете использовать только базовое индексирование (без нарезки) и очень небольшое количество функций Python, специальных В случае Cython (в основном те, которые перечислены здесь ). Так что вы просто должны сделать тело prangeболее простым и явным.

    for iter in prange(nIter, nogil=True):
        i = iter % nDim
    
        Ai_dot_x = 0
        for j in range(x.shape[0]):
            Ai_dot_x += A[j,i] * x[j]
    
        temp = (b[i] - Ai_dot_x*x[i] + A[i,i]*x[i]*x[i]) / A[i,i]
        x[i] = max(0, min(temp, 1))
    

    Ai_dot_x является дополнительной временной переменной, которая вам необходима cdef.