実行速度が遅すぎて、C で書き直すのが面倒な素敵な MATLAB コードがたくさんあります。C 用の MATLAB コンパイラは、まったく役に立たないようです。実行をもっと高速化する必要がありますか? 私はめちゃくちゃですか?
11 に答える
(MATLABの最近のバージョンで) MATLABコンパイラーを使用している場合、ほぼ確実にスピードアップはまったく見られません。これは、コンパイラが実際に行うのは、MATLABを持っていない人に配布できるように、コードをパッケージ化する方法を提供することだけだからです。それはそれをより速いもの(マシンコードやCなど)に変換しません-それはあなたがそれを呼び出すことができるようにそれをCでラップするだけです。
これは、本質的にMATLAB計算カーネルであるMATLABコンパイラランタイム(MCR)でコードを実行することによって行われます。コードはまだ解釈されています。MCRを呼び出さなければならないことによるペナルティのおかげで、コンパイルされたコードは、MATLABで実行した場合よりも実行が遅くなる場合があります。
別の言い方をすれば、少なくとも従来の意味では、コンパイラは実際にはコンパイルされないと言うかもしれません。
古いバージョンのコンパイラは動作が異なり、特定の状況で高速化が発生する可能性があります。Mathworkのこれに関する見解については、
http://www.mathworks.com/support/solutions/data/1-1ARNS.html
私の経験では、遅いMATLABコードは通常、コードをベクトル化しないことから発生します(つまり、配列を乗算するだけでなく、forループを記述します(単純な例))。
ファイルI/Oを実行している場合は、一度に1つのデータを読み取ることに注意してください。fscanfのベクトル化されたバージョンのヘルプファイルを調べてください。
MATLABにはプロファイラーも含まれていることを忘れないでください。
dwjが言ったことをエコーします。MATLABコードが遅い場合、これはおそらく十分にベクトル化されていないためです。配列全体に対して操作を実行できるときに明示的なループを実行している場合は、それが原因です。
これは、すべての配列指向の動的言語(Perlデータ言語、数値Python、MATLAB / Octaveなど)に等しく当てはまります。コンパイルされたCおよびFORTRANコンパイルされたコードでもある程度当てはまります。特別に設計されたベクトル化ライブラリは通常、慎重に手作業でコーディングされた内部を使用します。ループとSIMD命令(MMX、SSE、AltiVecなど)。
まず、プロファイリングとベクトル化に関する上記のすべてのコメントを 2 つ目にします。
歴史的な観点から...
以前のバージョンの Matlab では、ユーザーは m コードを事前に解析し、それを一連の matlab ライブラリ呼び出しに変換することで、m ファイルを mex 関数に変換できました。これらの呼び出しには、インタープリターが行ったすべてのエラー チェックがありますが、古いバージョンのインタープリターやオンライン パーサーは低速であったため、m ファイルをコンパイルすると役立つ場合があります。Matlab は C でループの一部をインライン化するのに十分スマートだったので、通常はループがあったときに役立ちました。Matlab のこれらのバージョンのいずれかを使用している場合は、.c ファイルを保存するように mex スクリプトに指示してみると、それが何であるかを正確に確認できます。やっています。
最近のバージョン (おそらく 2006a 以降ですが、覚えていません) では、Mathworks はインタプリタにジャストインタイム コンパイラを使い始めました。実際、この JIT コンパイラはすべての mex 関数を自動的にコンパイルするため、オフラインで明示的に実行してもまったく役に立ちません。それ以降の各バージョンでは、インタープリターをより高速にするために多大な努力も払ってきました。私は、Matlab の新しいバージョンでは、m ファイルを mex ファイルに自動的にコンパイルすることさえできなくなっていると考えています。
MATLAB コンパイラは m コードをラップして、MATLAB ランタイムにディスパッチします。したがって、MATLAB で見られるパフォーマンスは、コンパイラで見られるパフォーマンスになるはずです。
他の回答によると、コードをベクトル化すると便利です。しかし、最近の MATLAB JIT は非常に優れており、ベクトル化されているかどうかにかかわらず、多くのことが大まかに実行されます。これは、ベクトル化から得られるパフォーマンス上の利点がないと言っているわけではありません。ベクトル化は、かつての特効薬ではありません。実際に確認する唯一の方法は、プロファイラーを使用して、コードでボトルネックが発生している場所を見つけることです。多くの場合、コードのパフォーマンスを実際に改善するためにローカル リファクタリングを実行できる場所がいくつかあります。
パフォーマンスを向上させるためのハードウェア アプローチは他にもいくつかあります。まず、線形代数サブシステムの多くがマルチスレッド化されています。マルチコアまたはマルチプロセッサ プラットフォームで作業している場合は、設定でそれが有効になっていることを確認することをお勧めします。次に、並列計算ツールボックスを使用して、複数のプロセッサをさらに活用できる場合があります。最後に、Simulink ユーザーの場合は、emlmex を使用して m コードを c にコンパイルできる場合があります。これは特に定点作業に有効です。
コードのプロファイリングを試しましたか? すべてのコードをベクトル化する必要はなく、実行時間を支配する関数だけをベクトル化する必要があります。MATLAB プロファイラーは、コードが最も多くの時間を費やしている場所に関するヒントを提供します。
MathWorks マニュアルの「パフォーマンスを改善するためのヒント」セクションには、他にも読むべきことがたくさんあります。
コードを「EmbeddedMatlab」に移植してから、Realtime-Workshopを使用してコードをCに変換できます。
Embedded Matlabは、Matlabのサブセットです。セル配列、グラフィックス、動的サイズのマリス、または一部のマトリックスアドレッシングモードはサポートしていません。EmbeddedMatlabへの移植にはかなりの労力がかかる場合があります。
リアルタイム-ワークショップは、コード生成製品の中核です。汎用Cを吐き出すか、さまざまな組み込みプラットフォーム向けに最適化できます。最も興味深いのは、おそらくxPC-Targetです。これは、汎用ハードウェアを組み込みターゲットとして扱います。
プロファイリングに賛成票を投じてから、ボトルネックは何かを調べます。
ボトルネックが行列演算である場合、おそらくこれ以上うまくいくことはありません...1 つの大きな落とし穴が配列の割り当てであることを除けば。たとえば、ループがある場合:
s = [];
for i = 1:50000
s(i) = 3;
end
これは、配列のサイズを変更し続ける必要があります。配列のサイズを事前に設定し (ゼロまたは NaN で開始)、そこから埋める方がはるかに高速です。
s = zeros(50000,1);
for i = 1:50000
s(i) = 3;
end
ボトルネックが多くの関数呼び出しの繰り返し実行である場合、それは難しいものです。
ボトルネックが MATLAB が迅速に処理できないもの (特定の種類の解析、XML など) である場合、MATLAB は既に JVM で実行されており、任意の JAR ファイルに非常に簡単に接続できるため、Java を使用します。私は C/C++ とのインターフェースを見ましたが、それは本当に醜いです。Microsoft COM は問題ありませんが (Windows のみ)、Java を学んだ後は、二度と戻ることはないと思います。
mcc はコードをまったくスピードアップしません。実際にはコンパイラではありません。
あきらめる前に、プロファイラーを実行して、すべての時間がどこに費やされているかを把握する必要があります ([ツール] -> [プロファイラーを開く])。また、「tic」と「toc」を適切に使用することも役立ちます。時間がどこに行くのかがわかるまで、コードを最適化しないでください (推測しようとしないでください)。
matlab では次のことに注意してください。
- ビットレベルの操作は本当に遅い
- ファイル I/O が遅い
- ループは一般的に遅いですが、ベクトル化は高速です (ベクトル構文がわからない場合は学習してください)。
- コア操作は非常に高速です (例: 行列乗算、fft)
- C/Fortran/etc でより高速に実行できると思われる場合は、MEX ファイルを作成できます。
- matlab を C に変換する商用ソリューションがあり (google "matlab to c")、それらは機能します
他の人が指摘しているように、遅い Matlab コードは、多くの場合、不十分なベクトル化の結果です。
ただし、完全にベクトル化されたコードでも遅い場合があります。次に、さらにいくつかのオプションがあります。
- 使用できるライブラリ/ツールボックスがあるかどうかを確認してください。これらは通常、非常に最適化されるように記述されています。
- コードをプロファイリングし、タイトなスポットを見つけて、プレーン C で書き直します。C コードを (たとえば DLL として) Matlab に接続するのは簡単で、ドキュメントで説明されています。
Matlab コンパイラーとは、おそらくコマンド mcc を意味します。これは、Matlab インタープリターを回避することでコードを少し高速化します。MAtlab コードを大幅に (50 ~ 200 倍) 高速化するのは、mex コマンドでコンパイルされた実際の C コードを使用することです。