Проблема в том, что cublas и т. Д. Предназначены для использования всех SM для умножения больших матриц. Это не то, что вы хотите; вы хотите сделать много маленьких матричных умножений.
Возможно, какой-то способ бросить это во что-то, что CUBLAS может преуспеть для вас, но я этого не вижу. Мое предложение было бы следующим:
Напишите ядро, которое использует один блок потока, чтобы умножить две из ваших маленьких матриц и вывести результат.
Затем запустите журнал N ядра с т блоков и снасти умножения парно:
- Шаг 1: умножить M х М , М х М ... М Н - 2 х М Н-1, выводя М ', М' .. М ' N/2
- Шаг 2: умножить М' х М ', М' х М ' ... М' N/2 - 2 х М Н/2-1, вывод M '' , М '' .. М '' N/4 ...
т.д.
Накладные расходы памяти 50%, но я думаю, что вы будете лучше использовать свои ядра таким образом.
Update
Хорошо, если вы действительно не хотите делать это поэтапно, вы могли бы сделать это таким образом, но это будет требовать больше кодирования, и производительность, вероятно, будет хуже, чем то, что вы может получить что-то вроде cuBLAS и асинхронную передачу. Я предполагаю, что вы используете Fermi, и вы отключили кеш L1, так что у вас есть 48K разделяемый mem для SM.
Сохраните 100 матриц в форме блока 2x2, каждый из которых будет сохранен в памяти. Таким образом, matrix[matrixnum,i,j]
начинается с matricies[matrixnum*100*100 + i*100*50 + j*50*50]
. Обратите внимание, что каждый блок составляет 50 * 50 * 4 байта ~ 10K, поэтому 4 удобно вписываются в общую память.
Назначьте длинную цепочку матриц длиной 4 бит (Nmatricies/Nblocks) для умножения, причем один из четырех отвечает за каждый блок умножения.
Предположим, вы являетесь файловым блоком 1 из 4, и первой из матриц, которые вы должны умножить, является AxB. Вы несете ответственность за (1,1) результата - (AB) 1,1 = A 1,1 B 1,1 + A 1,2 * B 2,1. Вы предварительно загрузите в A 1,1 в myblock [0] в общей памяти.
- нагрузка в myblock [1] = B 1,1 из глобальной памяти
- myblock [3] = myblock [0] * myblock [1] (матрица мульт, все в совместно используемой памяти)
- нагрузка в myblock [1] = A 1,2 от глобального
- нагрузки в myblock [2] = B 2,1 от глобального
- myblock [0] = myblock [3] + (myblock [ 1] * myblock [2]) (матрица mult и дополнение, все в общей памяти).
Теперь вы можете повторить это для остальной последовательности матриц в своей части цепочки, выводя только тогда, когда это делается.
Когда все будет готово, вы получите математику (#SMs) в глобальной памяти, которую еще нужно умножить, но в глобальной памяти не будет никакого дополнительного временного хранилища, t пришлось копировать данные в глобальную память, отличные от исходных матриц, и списки которых нужно решать.
Опять же, нет реальной причины для этого, за исключением того, что вы не можете беспокоиться о передаче данных на GPU поэтапно, и производительность почти наверняка будет хуже; есть меньше записей глобальной памяти, но вы, вероятно, заплатите за это с помощью ручного GEMM. Хорошей новостью является то, что 50 не кратно 8, так что у вас, вероятно, не будет слишком много конфликтов конфликтов с общей памятью.
Опять же, для бонусных очков вы можете предварительно скопировать все блоки всех попарно матричных продуктов, а затем половину длины вашего списка.
Являются ли матрицы особенными в любой полезной форме? Если они одновременно диагализуемы, это становится намного проще. –
@JonathanDursi: Единственные специальные характеристики матрицы - это то, что для каждой из матриц все значения суммируются до 1. и матрица квадратична, но это должно быть ясно из описания. –