上下文:我使用的是人工神经网络的特征,其中典型的维度是每层大约1000个节点。因此,大多数操作是将大小为〜(1000,1000)的矩阵M
与大小为1000的向量或一批B向量相乘,表示为大小为Bx1000的矩阵
在训练神经网络后,我正在使用修剪 - 这是一种常见的压缩技术,最终得到稀疏矩阵(非空参数密度在10%到50%之间)。
目标:我想使用稀疏矩阵进行压缩,其次是性能优化但不是主要目标
问题: 我正在比较不同批量大小的稀疏和密集矩阵乘法(仅计算乘法时间)的性能,我观察以下(使用Eigen 3.2.8,MacBook Pro 64位,没有open_mp,并使用标准g ++):
MxN multiplication time (ms) for M sparse/dense, and N of size 1000xB
代码: 我对稀疏和密集矩阵使用以下类型:
typedef SparseMatrix<float> spMatFloat;
typedef Matrix<float, Dynamic, Dynamic, RowMajor> deMatRowFloat;
我正在进行基准测试的操作如下:
o.noalias()=m*in.transpose();
其中o
是密集矩阵(1000xB),m
是密集矩阵(1000x1000)或使用m.sparseView()
获得的相应稀疏矩阵,in
是密集矩阵(Bx1000)
完整代码如下(20个不同随机矩阵的平均时间,并且每次乘法运行50次) - B = 32且B = 1的时间低于。
欢迎任何反馈/直觉!
batch 1 ratio 0.3 dense 0.32 sparse 0.29
batch 32 ratio 0.3 dense 2.75 sparse 15.01
#include <Eigen/Sparse>
#include <Eigen/Dense>
#include <stdlib.h>
#include <boost/timer/timer.hpp>
using namespace Eigen;
using namespace boost::timer;
typedef SparseMatrix<float> spMatFloat;
typedef Matrix<float, Dynamic, Dynamic, RowMajor> deMatRowFloat;
void bench_Sparse(const spMatFloat &m, const deMatRowFloat &in, deMatRowFloat &o) {
o.noalias()=m*in.transpose();
}
void bench_Dense(const deMatRowFloat &m, const deMatRowFloat &in, deMatRowFloat &o) {
o.noalias()=m*in.transpose();
}
int main(int argc, const char **argv) {
float ratio=0.3;
int iter=20;
int batch=32;
float t_dense=0;
float t_sparse=0;
deMatRowFloat d_o1(batch,1000);
deMatRowFloat d_o2(batch,1000);
for(int k=0; k<iter; k++) {
deMatRowFloat d_m=deMatRowFloat::Zero(1000,1000);
deMatRowFloat d_b=deMatRowFloat::Random(batch,1000);
for(int h=0;h<ratio*1000000;h++) {
int i=rand()%1000;
int j=rand()%1000;
d_m(i,j)=(rand()%1000)/500.-1;
}
spMatFloat s_m=d_m.sparseView();
{
cpu_timer timer;
for(int k=0;k<50;k++) bench_Dense(d_m,d_b,d_o1);
cpu_times const elapsed_times(timer.elapsed());
nanosecond_type const elapsed(elapsed_times.system+elapsed_times.user);
t_dense+=elapsed/1000000.;
}
{
cpu_timer timer;
for(int k=0;k<50;k++) bench_Sparse(s_m,d_b,d_o2);
cpu_times const elapsed_times(timer.elapsed());
nanosecond_type const elapsed(elapsed_times.system+elapsed_times.user);
t_sparse+=elapsed/1000000.;
}
}
std::cout<<"batch\t"<<batch<<"\tratio\t"<<ratio<<"\tdense\t"<<t_dense/50/iter<<"\tsparse\t"<<t_sparse/50/iter<<std::endl;
}
ggael建议后的新结果:我尝试了不同的可能组合,并在更改M
和B
RowMajor / ColMajor时发现了巨大的性能差异。
总结一下,我感兴趣的是M*B
M
是(1000,1000)和B
是(1000,批处理):我有兴趣比较M sparse /的性能密集且批量生长时。
我测试了3种配置:
结果如下 - 其中数字是每列的比率时间,B = 32 /时间,B = 1,矩阵M,密度为0.3:
最初报道的问题是更糟糕的情况(M ColMajor,B RowMajor)。对于(M RowMajor,B ColMajor),在B = 32和B = 1之间有5倍的加速,稀疏矩阵的性能几乎等于密集矩阵。
答案 0 :(得分:2)
在Eigen中,对于密集代数,矩阵矢量和矩阵矩阵产品都经过高度优化,并充分利用了矢量化。正如您所观察到的,基质矩阵产品具有更高的效率。这是因为矩阵矩阵产品可以通过增加算术运算次数和内存访问次数之间的比率,以及利用内存缓存来进一步优化。
然后关于稀疏密集型产品,有两种策略:
Matrix<float,Dynamic,32,RowMajor>
)。最后,在任何一种情况下,您都可以尝试使用稀疏矩阵的行主要和列主要存储,并确定稀疏矩阵的策略和存储顺序的哪种组合在您的情况下最有效。