Matlab中的多线程稀疏矩阵乘法

时间:2014-08-15 15:48:46

标签: multithreading matlab matrix-multiplication sparse-matrix

我正在执行NxN稀疏(~1-2%)矩阵的几个矩阵乘法,让我们称之为B,用NxM密集矩阵,让它称之为A(其中M <1)。 N)。 N很大,M也是如此;大约几千。我正在运行Matlab 2013a。

现在,通常,矩阵乘法和大多数其他矩阵运算在Matlab中隐式并行化,即它们自动使用多个线程。 如果任何一个矩阵稀疏(例如this StackOverflow discussion - 没有对预期问题的答案 - 和this largely unanswered MathWorks thread),情况似乎并非如此。 这对我来说是一个相当不愉快的惊喜。

我们可以通过以下代码验证多线程对稀疏矩阵操作没有影响:

clc; clear all; 

N = 5000;         % set matrix sizes
M = 3000;       
A = randn(N,M);   % create dense random matrices
B = sprand(N,N,0.015); % create sparse random matrix
Bf = full(B);     %create a dense form of the otherwise sparse matrix B

for i=1:3 % test for 1, 2, and 4 threads
  m(i) = 2^(i-1);
  maxNumCompThreads(m(i)); % set the thread count available to Matlab
  tic                      % starts timer
    y = B*A; 
  walltime(i) = toc;       % wall clock time
  speedup(i) = walltime(1)/walltime(i);
end

% display number of threads vs. speed up relative to just a single thread
[m',speedup']

这会产生以下输出,这表明使用1,2和4个线程进行稀疏操作没有区别:

threads   speedup
1.0000    1.0000
2.0000    0.9950
4.0000    1.0155

另一方面,如果我用密集形式替换B,称之为Bf,我获得了显着的加速:

threads   speedup
1.0000    1.0000
2.0000    1.8894
4.0000    3.4841

(说明Matlab中密集矩阵的矩阵运算确实是隐式并行化的)

所以,我的问题是:有没有办法访问稀疏矩阵的矩阵运算的并行/线程版本(在Matlab中)而不将它们转换为密集形式? 我发现了一个旧的suggestion involving .mex files at MathWorks,但似乎链接已经死了,没有很好的记录/没有反馈?任何替代方案?

这似乎是对隐式并行功能的一个相当严格的限制,因为稀疏矩阵在计算量很大的问题中比比皆是,并且在这些情况下非常需要超线程功能。

3 个答案:

答案 0 :(得分:7)

MATLAB已经使用 Tim Davis SuiteSparse对稀疏矩阵的许多操作(例如see here),但我认为它们都不是多线程的。

通常,稀疏矩阵的计算受内存限制而不是CPU绑定。所以即使你使用多线程库,我怀疑你会在性能方面看到巨大的好处,至少不能与那些专注于密集矩阵的那些相比......

毕竟design of sparse matrices的目标与常规密集矩阵不同,因为高效的内存存储通常更为重要。


我做了一个快速search online,并在那里找到了一些实现:

答案 1 :(得分:2)

我最终使用OpenMP编写自己的mex文件以进行多线程处理。代码如下。编译时不要忘记使用-largeArrayDims和/ openmp(或-fopenmp)标志。

#include <omp.h>
#include "mex.h"
#include "matrix.h"

#define ll long long

void omp_smm(double* A, double*B, double* C, ll m, ll p, ll n, ll* irs, ll* jcs)
{
    for (ll j=0; j<p; ++j)
    {
        ll istart = jcs[j];
        ll iend = jcs[j+1];
        #pragma omp parallel for
        for (ll ii=istart; ii<iend; ++ii)
        {
            ll i = irs[ii];
            double aa = A[ii];
            for (ll k=0; k<n; ++k)
            {
                C[i+k*m] += B[j+k*p]*aa;
            }
        }
    }
}


void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    double *A, *B, *C; /* pointers to input & output matrices*/
    size_t m,n,p;      /* matrix dimensions */

    A = mxGetPr(prhs[0]); /* first sparse matrix */
    B = mxGetPr(prhs[1]); /* second full matrix */

    mwIndex * irs = mxGetIr(prhs[0]);
    mwIndex * jcs = mxGetJc(prhs[0]);

    m = mxGetM(prhs[0]);  
    p = mxGetN(prhs[0]);
    n = mxGetN(prhs[1]);

    /* create output matrix C */
    plhs[0] = mxCreateDoubleMatrix(m, n, mxREAL);
    C = mxGetPr(plhs[0]);

    omp_smm(A,B,C, m, p, n, (ll*)irs, (ll*)jcs);
}

答案 2 :(得分:1)

matlab central上提出同样的问题,并给出了答案:

I believe the sparse matrix code is implemented by a few specialized TMW engineers rather than an external library like BLAS/LAPACK/LINPACK/etc... 

这基本上意味着,你运气不好。


但是我可以想到一些技巧来实现更快的计算:

  1. 如果您需要进行多次乘法:一次多次乘法并同时处理它们?
  2. 如果您只想进行一次乘法:将矩阵切割成碎片(例如上半部分和下半部分),并行计算部件,然后将结果合并
  3. 这些解决方案可能不会像正确实现的多线程一样快,但希望你仍能获得加速。