Эффективное умножение матрицы на вектор в cuSparse

Я использую jCUSPARSE (оболочку библиотеки cuSparse) для умножения матрицы на вектор, и у меня проблема с функцией

cusparseDcsrmv(handle, cusparseOperation.CUSPARSE_OPERATION_NON_TRANSPOSE, matrixSize, matrixSize, alpha, descra, d_csrValA, d_rowPtrA, d_colIndA, x, beta, y);

Если я использую для инициализации дескриптора

cusparseSetMatType(descra, cusparseMatrixType.CUSPARSE_MATRIX_TYPE_GENERAL); 

работает в 5-10 раз быстрее, чем я использую

cusparseSetMatType(descra, cusparseMatrixType.CUSPARSE_MATRIX_TYPE_SYMMETRIC);

Я проверял на маленькой симметричной матрице 5х5 и ОБЩИЙ работает в 4 раза быстрее, чем симметричный

Я проверял на симметричной матрице 10000x10000 и ОБЩАЯ работает в 10 раз быстрее, чем симметричная.


person shurik    schedule 02.11.2011    source источник
comment
Матрицы бывают и симметричными, и квадратными?   -  person Tudor    schedule 02.11.2011
comment
У меня такая же проблема со сложными аналогами (CUSPARSE_MATRIX_TYPE_HERMITIAN).   -  person leftaroundabout    schedule 04.04.2012


Ответы (1)


Похоже, что ОП ответил на этот вопрос по побочному каналу и получил официальный ответ от njuffa. :

Я связался с командой библиотеки CUDA, и они предоставили следующее объяснение:

  1. Для умножения несимметричной разреженной матрицы на вектор выполняется операция y = A*x (A хранится явно).

  2. Для симметричной матрицы хранится только ее нижняя (или верхняя) треугольная часть матрицы A. Мы можем написать y = A*x = (L+D)*x + L^{T}*x, где A = (L+D) + L^{T} где L — строго нижняя треугольная часть матрицы, а D — диагональ. Поскольку хранится только L+D, нам нужно выполнить операцию с транспонированием матрицы (L^{T}), чтобы вычислить результирующий вектор y. В этой операции используется атомарность, поскольку строки матрицы необходимо интерпретировать как столбцы, а поскольку их обходят несколько потоков, разные потоки могут добавлять значения в одну и ту же ячейку памяти в результирующем векторе y. По этой причине умножение матрицы на вектор с транспонированной матрицей и симметричной матрицей выполняется медленнее, чем с несимметричной матрицей.

Лучший способ ускорить вычисления (если вы не ограничены памятью) — преобразовать симметричную матрицу в несимметричную и вызвать для нее соответствующую процедуру CUSPARSE.

Короче говоря, это узкое место в общей памяти. Не удивительно, но интересно. :)

person MrGomez    schedule 08.04.2012
comment
Жалость. В моей проблеме я не могу позволить себе переход на несимметричный, потому что память является основным ограничением. Полагаю, тогда мне придется жить с более медленным вычислением! Или была бы другая возможность, которая не требует слишком много памяти? - person leftaroundabout; 08.04.2012
comment
@leftaroundabout Интуитивно было бы идеально оптимизировать матрицу только для используемых частей. К сожалению, я не знаю, как это сделать с текущим API, если не считать слипстриминга в нескольких низкоуровневых расширениях, которые немного выше моего понимания. Мне нужно оставить это кому-то более умному и осведомленному о внутренностях CUDA, чем я, извините! - person MrGomez; 09.04.2012