[英]sparse x dense matrix multiplication performance under-efficient
背景 :我使用Eigen進行人工神經網絡,其中典型的維度是每層大約1000個節點。 因此,大多數操作是將大小為〜(1000,1000)的矩陣M
與大小為1000的向量或一批B向量相乘, 其被表示為大小為Bx1000的矩陣 。
在訓練神經網絡之后,我正在使用修剪 - 這是一種常見的壓縮技術,最終得到稀疏矩陣(非空參數的密度在10%到50%之間)。
目標 :我想使用稀疏矩陣進行壓縮,其次是性能優化,但這不是主要目標
問題 :我正在比較不同批量大小的稀疏和密集矩陣乘法(僅計算乘法時間)的性能,我觀察以下(使用Eigen 3.2.8,MacBook Pro 64位,沒有open_mp,並使用標准g ++):
M稀疏/密集的MxN乘法時間(ms),以及大小為1000xB的N.
相同的數字,但顯示稀疏和密集矩陣的一批不同大小的每個矢量的時間。 當批量大小增加時,我們清楚地看到密集矩陣的時間減少,並且稀疏矩陣的增強顯示出一些錯誤。 B = 1時標准化
代碼 :我對稀疏和密集矩陣使用以下類型:
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稀疏/密集的性能和批量增長時的性能。
我測試了3種配置:
結果如下 - 其中數字是每列的比率時間,B = 32 /時間,B = 1,矩陣M,密度為0.3:
最初報告的問題是更糟糕的情況(M ColMajor,B RowMajor)。 對於(M RowMajor,B ColMajor),在B = 32和B = 1之間有5倍的加速,並且稀疏矩陣的性能幾乎等於密集矩陣。
在Eigen中,對於密集代數,矩陣矢量和矩陣矩陣產品都經過高度優化,並充分利用了矢量化。 正如您所觀察到的,基質矩陣產品具有更高的效率。 這是因為通過增加算術運算次數和存儲器訪問次數之間的比率,以及利用存儲器高速緩存,可以進一步優化矩陣矩陣產品。
然后關於稀疏密集型產品,有兩種策略:
Matrix<float,Dynamic,32,RowMajor>
)。 最后,在任何一種情況下,您都可以嘗試使用稀疏矩陣的行主要和列主要存儲,並確定稀疏矩陣的策略和存儲順序的哪種組合在您的情況下最有效。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.