malang5 Ответов: 1

Производительность 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

Я подозреваю, что в библиотеке есть оптимизация, которая пропустит весь цикл строк/столбцов, если увидит, что скалярный коэффициент равен нулю.

1 Ответов

Рейтинг:
2

KarstenK

Питер прав. Хорошая библиотека ищет оптимизацию, прежде чем начать тяжелые вычисления.

А на матрицах пропуск для 0 значений является основным шагом оптимизации, на котором матрица упрощается.

Вот такой прекрасная статья от CMSoft в котором обсуждается весь этот вопрос, и они называют его "предварительной обработкой".