MATLAB コンパイラを使用すると大幅な速度向上が見られないのはなぜですか?
-
02-07-2019 - |
質問
素晴らしい MATLAB コードがたくさんありますが、実行が遅すぎるため、C で書き直すのは面倒です。C 用の MATLAB コンパイラは、たとえあったとしてもあまり役に立たないようです。実行をさらに高速化する必要がありますか?私はめちゃくちゃですか?
解決
dwj が言ったことを繰り返します。MATLAB コードが遅い場合は、おそらく十分にベクトル化されていないことが原因です。配列全体に対して操作を実行できるときに明示的なループを実行している場合、それが原因です。
これは、すべての配列指向の動的言語に同様に当てはまります。Perl データ言語、数値 Python、MATLAB/Octave などこれは、コンパイルされた C および FORTRAN コンパイルされたコードでもある程度当てはまります。特別に設計されたベクトル化ライブラリは通常、慎重にハンドコーディングされた内部ループと SIMD 命令を使用します (例:MMX、SSE、AltiVec)。
他のヒント
MATLABコンパイラ(MATLABの最新バージョン)を使用している場合、ほとんど確実にスピードアップはまったく見られません。これは、コンパイラが実際に行うのは、MATLABを持たない人に配布できるようにコードをパッケージ化する方法を提供するだけだからです。マシンコードやCなど、より高速なものには変換されません。Cでラップするだけなので、呼び出すことができます。
これは、基本的にMATLAB計算カーネルであるMATLAB Compiler Runtime(MCR)でコードを実行することによりこれを行います-コードはまだ解釈されています。 MCRを呼び出さなければならないペナルティのおかげで、コンパイルされたコードの実行は、MATLABで実行した場合よりも遅くなることがあります。
別の言い方をすれば-少なくとも伝統的な意味では、コンパイラは実際にはコンパイルしないと言うかもしれません。
古いバージョンのコンパイラは異なる動作をし、特定の状況でスピードアップが発生する可能性がありました。 Mathworkのこれについては、次のページをご覧ください
http://www.mathworks.com/support/solutions/ data / 1-1ARNS.html
私の経験では、MATLABコードが遅いのは通常、コードをベクトル化しないことです(つまり、配列を単に乗算する代わりにforループを記述します(単純な例))。
ファイルI / Oを実行している場合は、一度に1つずつデータを読み取ることに注意してください。 fscanfのベクトル化バージョンのヘルプファイルを参照してください。
MATLABにはプロファイラーも含まれていることを忘れないでください!
最初に、プロファイリングとベクトル化に関する上記のコメントをすべて2つ目にします。
歴史的な観点から...
Matlabの旧バージョンでは、mコードを事前解析し、それを一連のmatlabライブラリ呼び出しに変換することにより、mファイルをmex関数に変換できました。これらの呼び出しには、インタープリターが行ったすべてのエラーチェックがありますが、インタープリターおよび/またはオンラインパーサーの古いバージョンは遅いため、mファイルのコンパイルが役立つ場合があります。通常、MatlabがCでその一部をインライン化するのに十分スマートであるため、ループがあるときに役立ちました。Matlabのこれらのバージョンのいずれかを使用している場合、mexスクリプトに.cファイルを保存して、それが何であるかを正確に見ることができますやっています。
最近のバージョン(おそらく2006a以降ですが、覚えていません)では、Mathworksはインタープリターにジャストインタイムコンパイラーの使用を開始しました。実際、このJITコンパイラーはすべてのmex関数を自動的にコンパイルするため、明示的にオフラインで実行してもまったく役に立ちません。それ以降の各バージョンでは、インタープリターをより高速にするために多大な労力を費やしました。 Matlabの新しいバージョンでは、mファイルをmexファイルに自動的にコンパイルすることさえできません。これはもはや意味をなさないためです。
MATLABコンパイラはmコードをラップして、MATLABランタイムにディスパッチします。したがって、MATLABで表示されるパフォーマンスは、コンパイラーで表示されるパフォーマンスになります。
他の回答ごとに、コードをベクトル化することは役に立ちます。しかし、最近では、MATLAB JITは非常に優れており、多くの処理がほぼベクトル化されているかどうかに関係なく実行されます。それは、ベクトル化によって得られるパフォーマンス上の利点がないと言っているわけではありません。それはかつての魔法の弾丸ではありません。実際に伝える唯一の方法は、プロファイラーを使用して、コードでボトルネックが発生している場所を見つけることです。多くの場合、ローカルのリファクタリングを行ってコードのパフォーマンスを本当に改善できる場所がいくつかあります。
パフォーマンスに使用できるハードウェアアプローチは他にもいくつかあります。まず、線形代数サブシステムの多くはマルチスレッドです。マルチコアまたはマルチプロセッサプラットフォームで作業している場合は、設定でそれを有効にしていることを確認することができます。第二に、並列計算ツールボックスを使用して、複数のプロセッサをより活用できる場合があります。最後に、Simulinkユーザーであれば、emlmexを使用してmコードをcにコンパイルできる場合があります。これは、固定小数点の作業に特に効果的です。
コードのプロファイリングを試みましたか?すべてのコードをベクトル化する必要はなく、実行時間を支配する関数だけをベクトル化する必要があります。 MATLABプロファイラーは、コードが最も時間を費やしている場所に関するヒントを提供します。
mccはコードをまったく高速化しません。実際にはコンパイラーではありません。
あきらめる前に、プロファイラーを実行し、すべての時間がどこに向かっているのかを把握する必要があります([ツール]-> [プロファイラーを開く])。また、「tic」の賢明な使用および「toc」助けられる。時間の経過がわかるまでコードを最適化しないでください(推測しようとしないでください)。
matlabでは次のことに注意してください:
- ビットレベルの操作は本当に遅い
- ファイルI / Oが遅い
- ループは一般に低速ですが、ベクトル化は高速です(ベクトル構文がわからない場合は学習してください)
- コア操作は非常に高速です(行列乗算、fftなど)
- C / Fortran / etcでもっと速くできると思うなら、MEXファイルを書くことができます
- matlabをCに変換する商用ソリューション(google" matlab to c")があり、動作します
コードを" Embedded Matlab"に移植できます。その後、Realtime-Workshopを使用してCに変換します。
Embedded MatlabはMatlabのサブセットです。セル配列、グラフィックス、動的サイズのマリセス、または一部のマトリックスアドレッシングモードはサポートしていません。 Embedded Matlabに移植するにはかなりの労力を要する場合があります。
Realtime-Workshopは、コード生成製品の中核です。汎用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を学んだ後は、これに戻るとは思わない。
他の人が指摘したように、Matlabのコードが遅いのは、多くの場合、ベクトル化が不十分なためです。
ただし、完全にベクトル化されたコードでさえ遅い場合があります。次に、さらにいくつかのオプションがあります:
- 使用できるライブラリ/ツールボックスがあるかどうかを確認します。これらは通常、非常に最適化されるように記述されています。
- コードのプロファイルを作成し、タイトなスポットを見つけて、プレーンCでそれらを書き換えます。Cコード(たとえばDLL)をMatlabに接続するのは簡単で、ドキュメントに記載されています。
Matlabコンパイラでは、おそらくコマンドmccを意味します。これは、Matlabインタープリターを回避することでコードを少し高速化します。 MAtlabコードを大幅に(50〜200倍)高速化するのは、mexコマンドでコンパイルされた実際のCコードを使用することです。