多くの小さな行列に対する行列-ベクトル乗算の最適化


8

私は行列-ベクトル積の高速化を検討していますが、私が読むすべては非常に大きな行列に対してそれを行う方法についてです。私の場合、行列は小さいですが、実行しなければならない回数は非常に多いです。

これを最適化する方法はありますか?小さな行列と小さなベクトルで構成される1つの大きなベクトルから非常に大きな対角ブロック行列を作成し、大きな行列ベクトルの高速化の手法を使用する方が高速でしょうか?または、グローバルマトリックスとベクトルを設定すると、そこでメリットが失われますか?


同じ行列に多くのベクトルを掛ける必要がありますか、それとも行列の再利用はありませんか?
ブライアンボーチャーズ2014年

大きなブロック対角の大きな行列の手法を使用すると、大幅なスピードアップが得られるとは思いません。あなたの場合、「小さい」とはどのくらい小さいのでしょうか。これらの行列について他に何か知っていますか、たとえば、それらは回転などを記述しますか?
クリスチャンワルガ2014年

@BrianBorchersマトリックスの再利用はありません。タイムステップごとにポイントごとに異なります
tpg2114

@ChristianWalugaそれらは、5x5から10x10までの場合があり、密度が高く、対称的ではなく、一般的に言えば対角線的に支配的ではありません。何回実行する必要があるかはケースによって異なりますが、通常はタイムステップごとに
10000〜60000

回答:


7

コードを最適化する前に、まず最適化するものがあるかどうかを確認することをお勧めします。マトリックスとベクトルの積を最適化するライブラリは、キャッシュのサイズの制限とメモリからデータをロードするためのレイテンシという2つの問題に対処することで最適化します。1つ目は、他のデータで置き換える前に使用する必要があるすべてのデータについて、現在キャッシュ内にあるデータを最大限に使用することで行われます。後者は、実際に使用する前にデータをキャッシュにプリフェッチすることで行われます。

あなたのケースでは、データの算術強度が比較的少ないです-メモリからデータをロードし、それを1回だけ使用してから、次の行列に進みます。これは、最適化する2つ目の手段のみを残します。つまり、使用する前にデータをプリフェッチします。

しかし、先に述べたように、物事を最適化する前に、すでに持っているものを把握する価値があります。1秒あたりに行列ベクトル積を何回実行しているかを調べ、メモリからプロセッサにロードするために必要なバイト数を計算します。次に、これをマシンにあるプロセッサの帯域幅と比較します。物事をより速くするためにあなたができることは何もないことに気付くかもしれません。


4

それは実際に問題あなたの行列はキャッシュが既に含まれているためではないかもしれませんが、呼び出しされなければならないdgemv()か、sgemv()あなたは上のあなたの手を得ることができる最高のBLASライブラリーから、または同等。インテルMKLにアクセスできる場合は、インテルMKLを試してみてください。また、BLISまたはATLAS、あるいは他の多くの最適化されたBLASライブラリの1つを試してみてください。


1
興味深いことに、BKLルーチンは、MKLおよびハードウェア固有の実装を使用しても、FortranのMATMUL組み込み関数よりも実行速度が遅くなります。
tpg2114 2014年

1
私はそれに完全に驚いているわけではありませんが、確実に知るためにはコードを見る必要があります。気になる問題がたくさんあります。MKLを書き込む前に、配列の配置を確認することをお勧めしますが、これらの小さなサイズでは、MKL MATVECはあまり最適化されていない可能性があります。
Bill Barth

私の同僚であるビルも同じ問題に遭遇しました。結論は、MKL呼び出しに無視できないオーバーヘッドがあったか、さもなければ小さな行列に対して最適化されていなかったということです。いずれにせよ、手書きのmatmulは、非常に多数の5x5行列乗算を実行するときにかなり高速でした。
Aurelius

2
ON2ON

3
行列が非常に小さい(4x4など)場合は、テンプレート化されたライブラリの1つを試してみてください。これにより、関数呼び出しのオーバーヘッドが大幅に削減される可能性があります。アイゲンは良い候補です。
ダミアン

4

C ++コードの生成とEigen / Armadilloの使用は可能ですが、これはアプリケーションによって異なります。

N<8

データのメモリアラインメント(最大64バイトアラインメント)に注意し、ポインターを制限して、コンパイラーの処理を容易にします。これらの行列サイズでマルチコアサポートを使用する必要はありません。オーバーヘッドはゲインよりも大きくなります。

スクリプトを使用して、可能な組み合わせごとに個別の関数を自動的に生成し、連続した呼び出しのために関数ポインターをキャッシュします。

N8

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.