, гораздо проще распараллелить, потому что каждая строка получает свой собственный поток.

ользую дистрибутив Python Anaconda вместе с Numba, и я написал следующую функцию Python, которая умножает разреженную матрицуA (хранится в формате CSR) плотным векторомx:

@jit
def csrMult( x, Adata, Aindices, Aindptr, Ashape ):

    numRowsA = Ashape[0]
    Ax       = numpy.zeros( numRowsA )

    for i in range( numRowsA ):
        Ax_i = 0.0
        for dataIdx in range( Aindptr[i], Aindptr[i+1] ):

            j     = Aindices[dataIdx]
            Ax_i +=    Adata[dataIdx] * x[j]

        Ax[i] = Ax_i

    return Ax 

ВотA большойscipy разреженная матрица,

>>> A.shape
( 56469, 39279 )
#                  having ~ 142,258,302 nonzero entries (so about 6.4% )
>>> type( A[0,0] )
dtype( 'float32' )

а такжеx этоnumpy массив. Вот фрагмент кода, который вызывает вышеуказанную функцию:

x       = numpy.random.randn( A.shape[1] )
Ax      = A.dot( x )   
AxCheck = csrMult( x, A.data, A.indices, A.indptr, A.shape )

Обратите внимание на@jit-декоратор, который говорит Numba, чтобы сделать своевременную компиляцию дляcsrMult() функция.

В моих экспериментах моя функцияcsrMult() околов два раза быстрее какscipy .dot() метод. Это довольно впечатляющий результат для Numba.

Тем не менее, MATLAB все еще выполняет это умножение матрицы на векторВ 6 раз быстрее чемcsrMult(), Я полагаю, что это потому, что MATLAB использует многопоточность при выполнении разреженного умножения матрицы на вектор.

Вопрос:

Как я могу распараллелить внешнееforпетля при использовании Numba?

Нумба имел обыкновение иметьprange() функция, которая упростила параллелизациюfor-loops. К сожалению, Нумба больше не имеетprange() [на самом деле, это неверно, см. редактирование ниже].Так каков правильный способ распараллелить этоforсейчас, что Нумбаprange() функция ушла?

когдаprange() был удален из Numba, какую альтернативу имели в виду разработчики Numba?

Изменить 1:
Я обновил до последней версии Numba, которая составляет 0,35, иprange() вернулся! Это не было включено в версию .33, версию, которую я использовал.
Это хорошая новость, но, к сожалению, я получаю сообщение об ошибке, когда пытаюсь распараллелить цикл for, используяprange(), Вот параллель для циклапример из документации Numba (см. раздел 1.9.2 «Явные параллельные циклы») и ниже приведен мой новый код:

from numba import njit, prange
@njit( parallel=True )
def csrMult_numba( x, Adata, Aindices, Aindptr, Ashape):

    numRowsA = Ashape[0]    
    Ax       = np.zeros( numRowsA )

    for i in prange( numRowsA ):
        Ax_i = 0.0        
        for dataIdx in range( Aindptr[i],Aindptr[i+1] ):

            j     = Aindices[dataIdx]
            Ax_i +=    Adata[dataIdx] * x[j]

        Ax[i] = Ax_i            

    return Ax 

Когда я вызываю эту функцию, используя приведенный выше фрагмент кода, я получаю следующую ошибку:

AttributeError: Ошибка при nopython (преобразование в parfors) У объекта SetItem нет атрибута get_targets

Дано
вышеуказанная попытка использоватьprange вылетает, мой вопрос стоит:

Какой правильный путь ( с помощьюprange или альтернативный метод)распараллелить этот Питонfor-loop?

Как отмечено ниже, было довольно просто распараллелить аналогичный цикл for в C ++ и получить ускорение, пройденное на20-omp-темы. Должен быть способ сделать это с помощью Numba, так как цикл for смущающе параллелен (и поскольку редкое умножение матрицы на вектор является фундаментальной операцией в научных вычислениях).

Изменить 2:
Вот моя C ++ версияcsrMult(), Распараллеливаниеfor() цикл в версии C ++ делает код примерно в 8 раз быстрее в моих тестах. Это говорит мне о том, что подобное ускорение должно быть возможным для версии Python при использовании Numba.

void csrMult(VectorXd& Ax, VectorXd& x, vector<double>& Adata, vector<int>& Aindices, vector<int>& Aindptr)
{
    // This code assumes that the size of Ax is numRowsA.
    #pragma omp parallel num_threads(20)
    {       
        #pragma omp for schedule(dynamic,590) 
        for (int i = 0; i < Ax.size(); i++)
        {
            double Ax_i = 0.0;
            for (int dataIdx = Aindptr[i]; dataIdx < Aindptr[i + 1]; dataIdx++)
            {
                Ax_i += Adata[dataIdx] * x[Aindices[dataIdx]];
            }

            Ax[i] = Ax_i;
        }
    }
}

Ответы на вопрос(2)

Ваш ответ на вопрос