boost::numeric::ublas::matrix
を使用して1つの行列乗算を実装しました( my full、working boost code を参照)
Result result = read ();
boost::numeric::ublas::matrix<int> C;
C = boost::numeric::ublas::prod(result.A, result.B);
標準アルゴリズムを使用した別のアルゴリズム( 完全な標準コード を参照):
vector< vector<int> > ijkalgorithm(vector< vector<int> > A,
vector< vector<int> > B) {
int n = A.size();
// initialise C with 0s
vector<int> tmp(n, 0);
vector< vector<int> > C(n, tmp);
for (int i = 0; i < n; i++) {
for (int k = 0; k < n; k++) {
for (int j = 0; j < n; j++) {
C[i][j] += A[i][k] * B[k][j];
}
}
}
return C;
}
これは私が速度をテストする方法です:
time boostImplementation.out > boostResult.txt
diff boostResult.txt correctResult.txt
time simpleImplementation.out > simpleResult.txt
diff simpleResult.txt correctResult.txt
両方のプログラムは、2つの2000 x 2000マトリックスを含むハードコードされたテキストファイルを読み取ります。両方のプログラムは、これらのフラグでコンパイルされました:
g++ -std=c++98 -Wall -O3 -g $(PROBLEM).cpp -o $(PROBLEM).out -pedantic
私の実装では15秒、ブーストでは4分 -実装!
編集:でコンパイルした後
g++ -std=c++98 -Wall -pedantic -O3 -D NDEBUG -DBOOST_UBLAS_NDEBUG library-boost.cpp -o library-boost.out
Ikj-アルゴリズムでは28.19秒、Boostでは60.99秒 。そのため、Boostは依然としてかなり低速です。
ブーストが実装よりもはるかに遅いのはなぜですか?
TJDが指摘したように、uBLASバージョンのパフォーマンスの低下は、後者のデバッグ機能によって部分的に説明できます。
デバッグをオンにしたuBLASバージョンの所要時間は次のとおりです。
real 0m19.966s
user 0m19.809s
sys 0m0.112s
デバッグをオフにしたu_BLASバージョンの所要時間(-DNDEBUG -DBOOST_UBLAS_NDEBUG
コンパイラフラグが追加されました):
real 0m7.061s
user 0m6.936s
sys 0m0.096s
したがって、デバッグをオフにすると、uBLASバージョンはほぼ3倍高速になります。
残りのパフォーマンスの違いは、 BLAS FAQ 「なぜuBLASが(atlas-)BLASよりもずっと遅いのか」の次のセクションを引用することで説明できます。
Ublasの重要な設計目標は、可能な限り一般的であることです。
この一般性にはほとんどの場合、コストが伴います。特に、prod
関数テンプレートは、スパース行列や三角行列など、さまざまなタイプの行列を処理できます。幸いなことに、uBLASは、特に axpy_prod およびblock_prod
のような密行列の乗算に最適化された代替手段を提供します。さまざまな方法を比較した結果は次のとおりです。
ijkalgorithm prod axpy_prod block_prod
1.335 7.061 1.330 1.278
ご覧のとおり、axpy_prod
とblock_prod
の両方が実装よりもやや高速です。 I/Oなしで計算時間のみを測定し、不必要なコピーを削除し、block_prod
(64を使用)のブロックサイズを慎重に選択すると、違いがさらに大きくなります。
BLAS FAQ および 効果的なuBlasおよび一般的なコード最適化 も参照してください。
あなたのコンパイラは十分に最適化されていないと思います。 uBLASコードはテンプレートを多用し、テンプレートは最適化を多用する必要があります。私はあなたのコードをMS VC 7.1コンパイラを1000x1000マトリックスのリリースモードで実行しました。
_10.064
_ s for uBLAS
ベクトルの_7.851
_ s
違いはまだありますが、決して圧倒的ではありません。 uBLASのコアコンセプトは遅延評価であるため、prod(A, B)
は必要な場合にのみ結果を評価します。 prod(A, B)(10,100)
はすぐに実行されます。実際には1つの要素のみが計算されるためです。そのようなものとして実際にあります 最適化できる全行列乗算専用のアルゴリズムはありません (下記参照)。しかし、あなたは図書館を少し助けて、宣言することができます
_matrix<int, column_major> B;
_
実行時間を_4.426
_ sに短縮します。この宣言により、行列を乗算するときにメモリへのアクセスがよりシーケンシャルになり、キャッシュの使用が最適化されます。
追伸uBLASのドキュメントを最後まで読んだら、実際にwhole行列を一度に乗算する専用の関数があることに気付くはずです。 2つの関数-_axpy_prod
_および_opb_prod
_。そう
_opb_prod(A, B, C, true);
_
最適化されていないrow_major B行列でも_8.091
_秒で実行され、ベクトルアルゴリズムと同等です
P.P.S.さらに多くの最適化があります:
_C = block_prod<matrix<int>, 1024>(A, B);
_
bがcolumn_またはrow_ majorであるかどうかに関係なく、_4.4
_ sで実行されます。 「関数block_prodは、大密度行列用に設計されています」という説明を考慮してください。特定のタスクに特定のツールを選択してください!
私は小さなウェブサイトを作成しました BLASを使用したマトリックス-マトリックス製品実験 。マトリックスマトリックス製品の新しい実装をuBLASに統合することです。ブーストライブラリが既にある場合、追加の4つのファイルのみで構成されます。だから、それはほとんど自己完結型です。
他の人が異なるマシンで簡単なベンチマークを実行できるかどうかに興味があります。