Производительность cblas gemm для разреженных матриц
Что может быть причиной того, что вызов cblas_sgemm занимает гораздо меньше времени для матриц с большим количеством нулей по сравнению с тем же вызовом cblas_sgemm для плотных матриц?
Я знаю, что gemv предназначен для матрично-векторного умножения, но почему я не могу использовать gemm для векторно-матричного умножения, если это занимает меньше времени, особенно для разреженных матриц
Ниже приводится краткий репрезентативный код. Он просит ввести значение, а затем заполняет вектор этим значением. Затем он заменяет каждое 32-е значение своим индексом. Итак, если мы введем "0", то получим разреженный вектор, но для других значений мы получим плотный вектор.
#include <iostream> #include <stdio.h> #include <time.h> #include <cblas.h> #include <cublas_v2.h> using namespace std; int main() { const int m = 5000; timespec blas_start, blas_end; long totalnsec; //total nano sec double totalsec, totaltime; int i, j; float *A = new float[m]; // 1 x m float *B = new float[m*m]; // m x m float *C = new float[m]; // 1 x m float input; cout << "Enter a value to populate the vector (0 for sparse) "; cin >> input; // enter 0 for sparse // input martix A: every 32nd element is non-zero, rest of the values = input for(i = 0; i < m; i++) { A[i] = input; if( i % 32 == 0) //adjust for sparsity A[i] = i; } // input matrix B: identity matrix for(i = 0; i < m; i++) for(j = 0; j < m; j++) B[i*m + j] = (i==j); clock_gettime(CLOCK_REALTIME, &blas_start); cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 1, m, m, 1.0f, A, m, B, m, 0.0f, C, m); //cblas_sgemv(CblasRowMajor, CblasNoTrans, m, m, 1.0f, B, m, A, 1, 0.0f, C, 1); clock_gettime(CLOCK_REALTIME, &blas_end); /* for(i = 0; i < m; i++) printf("%f ", C[i]); printf("\n\n"); */ // Print time totalsec = (double)blas_end.tv_sec - (double)blas_start.tv_sec; totalnsec = blas_end.tv_nsec - blas_start.tv_nsec; if(totalnsec < 0) { totalnsec += 1e9; totalsec -= 1; } totaltime = totalsec + (double)totalnsec*1e-9; cout<<"Duration = "<< totaltime << "\n"; return 0; }
Когда я запускаю этот код в Ubuntu 14.04, я получаю следующие результаты
erisp@ubuntu:~/uas/stackoverflow$ g++ gemmcomp.cpp -o gemmcomp.o -lblas erisp@ubuntu:~/uas/stackoverflow$ ./gemmcomp.o Enter a value to populate the vector (0 for sparse) 5 Duration = 0.0291558 erisp@ubuntu:~/uas/stackoverflow$ ./gemmcomp.o Enter a value to populate the vector (0 for sparse) 0 Duration = 0.000959521
показав, что вызов cblas_sgemm для разреженных матриц намного эффективнее, чем тот же вызов для плотных матриц. В чем может быть причина?
Что я уже пробовал:
Я уже проверил выход и он правильный
Peter_in_2780
Я подозреваю, что в библиотеке есть оптимизация, которая пропустит весь цикл строк/столбцов, если увидит, что скалярный коэффициент равен нулю.