12

質問に対する正しい答えが 1 つあるかどうかはわかりませんが、ここで説明します。多くの数値問題は線形代数形式で述べることができますが、私の限られた経験から、Math.NET を使用して生の配列に同等の操作を記述すると、単純な操作のパフォーマンス オーバーヘッドがあるようです。

テスト ケースとして、ベクトルとリスト内の最も近いベクトルの間の距離を計算するコードを作成しました。3 つのバージョンがあります。配列での操作、密なベクトルでの操作、および MKL プロバイダーを使用した密なベクトルでの操作です。配列での作業は、ベクトルよりも約 4 倍速く、MKL プロバイダーを使用するよりも 3 倍速く実行されました。

欠点は、組み込みの Norm 関数を利用する代わりに、手動で距離計算を記述しなければならなかったことです。利点は、はるかに高速であることです。注: 私はコードを投稿しませんでした。必要に応じて喜んで投稿します。Math.NET を不適切に使用している可能性もあります。

私の質問は次のとおりです。より高いレベルの抽象化を使用すると、パフォーマンスが犠牲になるように思えます。それは一般的なケースですか、それとも配列に対して手動で記述された操作よりも Math.NET を使用することが期待される状況 (インスタンスのスパース行列など) はありますか?

その場合、Math.NET の線形代数部分を使用することは、行列を含む「実際の」代数に最も役立ち、より複雑な計算/アルゴリズムの再実装を回避し、潜在的にコードの読みやすさのために役立つと考える傾向があります。 、しかし、より単純なベクトルごとの操作である操作の場合、生の配列で作業する方が良い考えかもしれません.

ライブラリを使用するのが良いアイデアである場合と、自分で作成する必要がある場合に点灯するライトは大歓迎です!

4

1 に答える 1

27

免責事項: 私は Math.NET Numerics を保守しています。

Math.NET Numerics のようなツールキットが提供しようとする主な価値は、開発者の生産性です。特に、この分野の博士号を取得していない人にとっては、これらの非常に複雑なアルゴリズムを自分で実装するのに苦労したり、多くの時間を無駄にしたりします。彼らの実際の問題に時間を費やすこと。

次に、必要な機能が以前に他の人によって使用されている可能性があります。それらの一部は、すでにいくつかの問題を発見して指摘し、改善に貢献している可能性があります。ユーザーが増えると、コードの品質と堅牢性が向上します。残念ながら、これには大きな欠点もあります。コードをより一般的にする傾向があるため、必要なことを正確に実行する高度に専門化された実装よりも効率が低下することがよくあります。

これはすべて、Cody Gray のコメントの行に沿っています: 動作し、十分に高速である場合は使用してください。そうでない場合は、修正して動作させる (そして高速にする) か、動作する別のツールキットを選択するか、必要なものを正確に実装してください。幸いなことに、Math.NET Numerics にはさらにいくつかのオプションがあります。以下を参照してください。

そのため、私はあなたの結論に同意します。複雑な操作が実際に必要ない場合は、非常に大きなデータを操作しないでください。ただし、パフォーマンスは重要です。配列や別のデータ構造を直接使用しても問題はありません (特に F# では、個人的には、生のネイティブ データ構造を C# よりも頻繁に検討します)。もちろん、これにはいくつかの利便性が失われるという代償が伴います。また、より多くの操作が必要になったときにツールキットを再実装することになるリスクもあります。最終的には、これがプロジェクトにとってどれほど重要であるか、および独自の数学コードを維持するためにリソースと時間を費やすことができるかどうかにも依存します。

それにもかかわらず、私自身の経験では、コードを所有すること (変更を加えてすぐに有効にすることができる) と、コードをシンプルで集中的に保つこと (つまり、必要なことだけを正確に実行すること) が有利な場合がよくあります。

Math.NET 数値に固有

  • 非常に具体的な管理された実装は、常に一般的な管理された実装よりも優れています。ただし、管理された実装は、管理された代替手段よりも大幅に遅くなるべきではありません。結局のところ、私たちのアルゴリズムは配列に対して直接動作するだけでなく、内部的にも動作します (適切に最適化されている場合)。代替アルゴリズムがはるかに高速である場合は、実装をその代替アルゴリズムに置き換える方がよいようですので、それについてお知らせください (または、変更を提供することをお勧めします)。
  • MKL のようなネイティブ プロバイダーを活用できる道にたどり着き、大規模なデータを処理する場合、より高いレベルの抽象化にもかかわらず、Math.NETの方がはるかに高速であることが期待されます。
  • Math.NET Numerics のすべてのコード パスが、まだ等しく最適化されているわけではなく、ネイティブ プロバイダーを利用しているわけでもありません。線形代数については、過去数回のマイナー バージョンで多くの作業が行われたため、徐々にではありますが改善されています。まだ多くの作業が必要です (特にスパース型の場合)。あなたの場合、ほとんど最適化されていないパスにヒットした可能性があります。したがって、この特定のケースに取り組むことができるように、実際にあなたのコード サンプルに非常に興味があります

Math.NET Numerics パフォーマンスのヒント

  • ネイティブ プロバイダーを使用する
  • Control クラスの並列化設定を少し試してみてください (ただし、v2.4 までの並列化の実装は実際には非常に悪いことがわかっており、v2.5 で完全に置き換える予定です。最初のベンチマークは有望です)。
  • 独自の操作を実装するときは、At/インデクサーへのアクセスを避け、代わりに生の配列に直接アクセスしてください (.Storage を参照)。
  • 多くの操作で、結果のベクトル/行列を指定できます。これは、オペランドの 1 つ (インプレース) と同じになることもあります。すべての操作で新しい配列を作成することを回避するため、非常に大きなデータを扱う場合にメモリ負荷を軽減します。残念ながら、コードを醜くします。
于 2013-03-22T10:01:44.997 に答える