ランタイムが行列演算にバインドされているものを計算しています。 (興味がある場合は、以下の詳細をご覧ください。)この経験から、次の質問がありました。
人々は、行列演算用のJavaライブラリー(例えば、乗算、逆数など)のパフォーマンスの経験がありますか?例えば:
検索しても何も見つかりませんでした。
速度比較の詳細:
Intel FORTRAN(ifort(IFORT)10.1 20070913)を使用しています。 Apache commons math 1.2 matrix opsを使用してJava(1.6)で再実装しましたが、精度のすべての桁に同意します。 (Javaでそれを必要とする理由があります。)(Javaは倍増し、Fortranは本物* 8です)。 Fortran:6分、Java 33分、同じマシン。 jvisualmプロファイリングは、RealMatrixImpl。{getEntry、isValidCoordinate}で多くの時間を費やしていることを示しています(未公開のApache commons math 2.0ではなくなっているようですが、2.0は速くありません)。 FortranはAtlas BLASルーチン(dpotrfなど)を使用しています。
明らかに、これは各言語のコードに依存する可能性がありますが、ほとんどの場合、同等の行列演算であると考えています。
ライブラリを必要としない他のいくつかの計算では、Javaはそれほど遅くなく、時にははるかに高速です。
ちょうど私の2セントを追加します。これらのライブラリのいくつかを比較しました。 3000 x 3000の倍精度行列をそれ自体で行列乗算しようとしました。結果は次のとおりです。
C/C++、Octave、PythonおよびRでマルチスレッドATLASを使用すると、所要時間は約4秒でした。
JavaでJamaを使用すると、所要時間は50秒でした。
ColtおよびParallel ColtとJavaを使用すると、所要時間は150秒でした!
JavaでJBLASを使用すると、JBLASはマルチスレッドATLASを使用するため、所要時間は約4秒でした。
そのため、Javaライブラリのパフォーマンスがあまり良くないことは明らかでした。ただし、誰かがJavaでコーディングする必要がある場合、最良のオプションはJBLASです。 Jama、Colt、Parallel Coltは高速ではありません。
私はJava Matrix Benchmark( JMatBench )の著者であり、この議論について考えたいと思います。
Javaライブラリには大きな違いがあり、操作の全範囲にわたって明確な勝者は存在しませんが、 最新のパフォーマンス結果 ( 2013年10月)。
「大きな」行列で作業しており、ネイティブライブラリを使用できる場合、明確な勝者(約3.5倍高速)は MTJ with system optimize netlib です。純粋なJavaソリューションが必要な場合 MTJ 、 OjAlgo 、 EJML および パラレルColt は良い選択です。小さい行列の場合、EJMLが明確な勝者です。
私が言及しなかったライブラリは、重大なパフォーマンスの問題を示しているか、主要な機能が欠けていました。
私はjblasの主な著者であり、2009年12月下旬にバージョン1.0をリリースしたことを指摘したかったのです。 Windows、Linux、Mac OS X、32ビットおよび64ビット(Windowsを除く)。このように、jarファイルをクラスパスに追加するだけで、ネイティブのパフォーマンスが得られます。 http://jblas.org !
ジェイゲン https://github.com/hughperkins/jeigen
2つの密な行列を掛けることによる簡単なテスト、すなわち:
import static jeigen.MatrixUtil。*;
int K = 100;
int N = 100000;
DenseMatrix A = Rand(N, K);
DenseMatrix B = Rand(K, N);
Timer timer = new Timer();
DenseMatrix C = B.mmul(A);
timer.printTimeCheckMilliseconds();
結果:
Jama: 4090 ms
Jblas: 1594 ms
Ojalgo: 2381 ms (using two threads)
Jeigen: 2514 ms
Apache Commons Mathとjlapackを比較しました。
テスト:ランダムな1024x1024行列の特異値分解。
マシン:Intel(R)Core(TM)2 Duo CPU E6750 @ 2.66GHz、linux x64
オクターブコード:A = Rand(1024); tic; [U、S、V] = svd(A); toc
結果の実行時間 ------------------------------------- -------------------- オクターブ36.34秒 JDK 1.7u2 64bit jlapack dgesvd 37.78 sec Apache commons math SVD 42.24 sec JDK 1.6u30 64bit jlapack dgesvd 48.68 sec Apache commons math SVD 50.59 sec ネイティブルーチン Cから呼び出されるLapack *:37.64秒 Intel MKL 6.89秒(!)
私の結論は、JDK 1.7から呼び出されたjlapackはlapackのネイティブバイナリパフォーマンスに非常に近いということです。 Linux Distroに付属のlapackバイナリライブラリを使用し、dgesvdルーチンを呼び出して、U、S、VTマトリックスも取得しました。すべてのテストは、実行ごとに正確に同じ行列で(オクターブを除く)倍精度を使用して行われました。
免責事項-私は線形代数の専門家ではなく、上記のライブラリのいずれにも属しておらず、これは厳密なベンチマークではありません。私はJDK 1.7から1.6へのパフォーマンスの向上とcommons数学SVDからjlapackへのパフォーマンスの比較に興味があったので、「自家製」のテストです。
特定のライブラリについて実際にコメントすることはできませんが、原則として、Javaでこのような操作が遅くなる理由はほとんどありません。 Hotspotは通常、コンパイラに期待する種類のことを行います。Java変数の基本的な数学演算を対応するマシン命令にコンパイルします(SSE命令を使用しますが、操作);配列の要素へのアクセスは、予想どおり「生の」MOV命令を使用するようにコンパイルされます。可能なときにレジスタに変数を割り当てる方法を決定します。プロセッサアーキテクチャを活用するために命令を並べ替えます。可能な例外は、前述したように、HotspotはSSE命令ごとに1つの操作のみを実行することです。原則として、命令ごとに複数の操作を実行する素晴らしく最適化されたマトリックスライブラリを使用できますが、たとえば、特定のFORTRANライブラリが実行するかどうか、またはそのようなライブラリが存在するかどうかはわかりません。存在する場合、現在、Java(または少なくともHotspot)がそれと競合する方法はありません(もちろん、Javaから呼び出す最適化を使用して独自のネイティブライブラリを作成することもできます)。
それで、これはどういう意味ですか?まあ:
行列演算の障害は、多くの場合、行ごとおよび列ごとに両方を走査する必要があるときに発生するデータの局所性の問題です。行列乗算では、どちらか一方を最適化する順序でデータを保存する必要があるためです。ただし、コードを手書きする場合は、操作を組み合わせてデータの局所性を最適化するを使用できます(たとえば、行列に変換を乗算する場合、列トラバーサルを行トラバーサルに変換できます2つのライブラリ関数を結合する代わりに、専用の関数を作成します)。人生でいつものように、ライブラリは開発の高速化と引き換えに最適でないパフォーマンスを提供します。パフォーマンスがあなたにとってどれほど重要かを決める必要があります。
いくつかの異なるハードウェア構成の http://code.google.com/p/Java-matrix-benchmark/ でJava upで利用可能なさまざまなマトリックスパッケージのベンチマークがあります。しかし、独自のベンチマークを実行することに代わるものではありません。
パフォーマンスは、所有しているハードウェアのタイプ(CPU、コア、メモリ、L1-3キャッシュ、バス速度)、マトリックスのサイズ、使用するアルゴリズムによって異なります。ライブラリが異なれば、アルゴリズムが異なると並行性が異なるため、単一の答えはありません。また、ネイティブライブラリが期待する形式に変換するオーバーヘッドにより、ユースケースのパフォーマンス上の利点が失われる場合があります(Javaライブラリの一部には、マトリックスストレージに関するより柔軟なオプションがあり、さらにパフォーマンスの最適化)。
ただし、一般的に、JAMA、Jampack、COLTは古くなっており、線形代数のJavaで利用可能な現在のパフォーマンスの状態を表していません。最新のライブラリは、複数のコアとCPUキャッシュをより効果的に使用します。 JAMAはリファレンス実装であり、パフォーマンスをほとんど考慮せずにテキストブックアルゴリズムを実装しています。 COLTとIBM Ninjaは、ネイティブライブラリよりも50%遅れていたとしても、Javaでパフォーマンスが可能であったことを示す最初のJavaライブラリでした。
私は la4j (Java用の線形代数)ライブラリの著者であり、ここに私のポイントがあります。私は3年間la4jに取り組んでおり(最新リリースは0.4.0 [2013年6月1日])、必要な最小限の機能を説明しただけなので、パフォーマンス分析と最適化を開始できるようになりました。そのため、la4jは思ったほど高速ではありませんが、それを変更するために多くの時間を費やしています。
現在、la4jの新しいバージョンを JMatBench platformに移植しています。 la4jには、内部マトリックス形式の高速化、安全でないアクセサー、マトリックス乗算の高速ブロックアルゴリズムなど、いくつかの改善が行われているため、新しいバージョンのパフォーマンスが以前のものよりも向上することを願っています。
Intel Math Kernel Library をご覧になりましたか? ATLAS でさえも性能が優れていると主張しています。 MKLは、JNIラッパーを介して Javaで使用 にできます。
かなり大規模で深刻な財務計算にCOLTを使用し、非常に満足しています。高度にプロファイル化されたコードでは、COLT実装を独自のものに置き換える必要はほとんどありませんでした。
独自のテスト(明らかに独立していない)では、Intelの手で最適化されたアセンブラールーチンの2倍以内であると主張しています。うまく使うための秘Theは、それらの設計哲学を理解し、余分なオブジェクトの割り当てを避けることです。
Pentium固有のネイティブコードの方が優れているというVarkhanの投稿に基づいて作成します。
jBLAS:AtlasのJNIラッパーを使用したアルファ段階のプロジェクト: http://www.jblas.org 。
MTJ:別のそのようなプロジェクト: http://code.google.com/p/matrix-toolkits-Java/
3Dグラフィックアプリケーションの場合、lwjgl.utilベクトルの実装は、上記のjblasを約3倍上回りました。
Vec4と4x4マトリックスの100万回のマトリックス乗算を行いました。
lwjglは約18msで終了し、jblasは約60msを必要としました。
(JNIアプローチは、比較的小さな乗算の高速連続アプリケーションにはあまり適していないと思います。変換/マッピングには、実際の乗算の実行よりも時間がかかる場合があるためです。)
UJMP もあります
Apache Mahoutを買い物リストに追加する必要があります。
Matrix Tookits Java(MTJ)は以前に言及されましたが、おそらくこのスレッドにつまずく他の誰かのために再び言及する価値があります。興味のある人にとっては、MTJが Apache commons math 2. のlinalgライブラリを置き換えることについての話があるように思えますが、それが最近どのように進んでいるかはわかりません。
多くの高次元行列を作成している場合、2次元配列ではなく1次元配列を使用するように変更すると、Jamaを約20%高速化できることがわかりました。これは、Javaが多次元配列を効率的にサポートしていないためです。すなわち。配列の配列を作成します。
Coltはすでにこれを実行していますが、Jamaよりも複雑で強力であることがわかりました。これは、単純な関数がColtで遅い理由を説明するかもしれません。
答えは本当にあなたがしていることに依存します。ジャマは、コルトができることのうち、より大きな違いを生むものの一部をサポートしていません。
さまざまな自由に利用できるJava線形代数ライブラリがあります。 http://www.ujmp.org/Java-matrix/benchmark/ 残念ながら、そのベンチマークは行列の乗算に関する情報のみを提供します(テストの転置では、異なるライブラリがそれぞれの設計機能を活用することはできません) )。
さまざまな行列分解を計算するように求められたときに、これらの線形代数ライブラリがどのように動作するかを確認する必要があります。 http://ojalgo.org/matrix_compare.html