В настоящее время я должен выполнить 128 независимых последовательных матрично-векторных операций CUBLAS. Все матрицы и векторы разные. Каждая независимая матрица сохраняется сразу после следующей в памяти, а векторы также сохраняются в памяти непрерывно (все в виде строки-мажора).
Немного больше контекста:
Матрицы (2048 X 8) и вектор длиной 2048. Выходные данные все независимый. Поскольку у меня есть супер матрицы, у меня есть следующее:
matrix[(2048*128)x8]
vector[(2048*128)x1]
output[(8*128)x1]
С cublasSgemv Сначала я делаю транспонирование для каждой мини-матрицы, а затем добавляю (а не заменяю) результат в память:
cublasSgemv(*handle, CUBLAS_OP_T, Bdim, Adim, scale1, d_matrix + offset1, Bdim, d_vector + offset2, 1, scale2, out + offset3, 1);
Я делаю 128 таких звонков, которые я хотел бы сделать в один.
Профилировщик показывает значительное снижение производительности от выполнения этих нескольких вызовов. Каков наилучший способ сделать несколько матрично-векторных операций? Есть ли способ объединить их в один быстрый звонок?
Являются ли потоки лучшим способом или есть какой-то способ сделать вызов с соответствующими смещениями (для индексации в моем массиве матриц и векторов)? Похоже, что единственным эффективным способом является использование вызова CUSPASE и прикрепление всех матриц к диагонали.
ПРИМЕЧАНИЕ: меня не интересует правильное расположение транспонирования или основного порядка строк / столбцов в вызове gemv для этого конкретного вопроса.
На самом деле вы должны обратить особое внимание на порядок крупных заказов, если вы хотите ускорить ваш код в этом случае.
Как показано в вашем пересмотренном вопросе, вы используете матрицы строк. тогда у вас есть суперматрица A [(2048 * 128) x8] и супер вектор V [(2048 * 128) x1]. И здесь я предполагаю, что вы хотите получить матричный вывод матрицы больших значений [8×128] (может рассматриваться как супер-вектор [(8 * 128) x1]), где каждый столбец col является результатом транспонирования (miniA [2048×8]) * miniV [2048×1].
С другой стороны, CUBLAS предполагает, что матрицы хранятся в столбце-мажоре. Поэтому для изменения порядка может потребоваться дополнительная процедура транспонирования матрицы.
Поскольку вам нужно 128 независимых [8×1] результатов, он должен иметь возможность рассчитать результат в 4 вызовы API cuda, которые должны быть более эффективными, чем ваши оригинальные 128 звонки.
1. Row-major A[(2048*128)x8] can be seen as colum-major AA[8x(2048*128)]
B[8x(2048*128)] = AA[8x(2048*128)] * diag( V[[(2048*128)x1]] ) by 1 dgmm()
2. C[(2048*128)x8] = transpose( B[8x(2048*128)] ) by 1 geam()
3. Col-major C[(2048*128)x8] can be seen as col-major CC[2048x(8*128)]
O[1x(8*128)] = ones[1x2048] * CC[2048x(8*128)] by 1 gemv()
4. Row vector O[1x(8*128)] can be seen as col-major matrix OO[128x8]
output[8x128] = transpose( OO[128x8] ) by 1 geam()
Этот основной вывод [8×128] — то, что вы хотите.
Так как вам нужно adding
скорее тогда replacing
, вам может понадобиться еще один вызов, чтобы добавить оригинальные значения output
Я сделал очень быстрый запуск batchCUBLAS
SDK пример. Я рассмотрел 128
независимые пробеги для матриц размера 2048x8
а также 8x1
, Вот результаты на NVIDIA GeForce GT 540M (вычислительная способность 2.1) и на Kepler K20c (вычислительная способность 3.5).
Для случая NVIDIA GeForce GT 540M не существует существенных улучшений для «потоковой» и «пакетной» версий по сравнению с «не потоковым» исполнением cuBLAS.
Для NVIDIA Kepler K20c я получил
sgemm
1,87 GFlops (без потока); 3,08 GFlops (в потоке); 6,58 GFlops (в пакетном режиме);
dgemm
1,00 GFlops (без потоковой передачи); 1,43 GFlops (в потоке); 6,67 GFlops (в пакетном режиме);
Похоже, что потоковые и пакетные кейсы значительно улучшают непотоковые кейсы с одинарной точностью.
Отказ от ответственности
Я надеюсь, что эти частичные результаты могут дать вам некоторую полезную информацию.