Matlabで計算の速度を上げます

こんにちは、ハブロビテス!



Matlabクラスターの最近の投稿が私にやる気を起こさせた記事を私はあなたの注意にもたらします。 かつて、このトピックの作者と同じ問題に直面していましたが、生産性を高めるために、分散コンピューティングのジャングルには入らず、できるだけコードを最適化することにしました。 Matlabでこれを行う方法は、カットの下で詳細を尋ねます。



この記事は、人生経験の説明と英語の出版物の無料翻訳です。



大規模な数値計算がコンピュータのハードウェアにかなりの要件を課すことは秘密ではありません。 論文に座って、自宅のコンピューターがコンピューティングのニーズを満たせなくなったことに気付きました。 2か月前にコンピューターを変更し、トップエンドのハードウェアを組み立てたため、ハードウェアを変更するオプションは私には適していませんでした。 コードの最適化はそれほど重要ではないという意見があります。最新のハードウェアを購入するための費用の増加に対処する方が簡単です。この意見は存在する権利があります。



Matlabはインタプリタ言語であり、大規模な科学計算には不適切と思われるでしょう。 言語のすべての潜在的な機能は、ライブラリとベクトル化操作の広範なセットのおかげで実現されます。 ベクトル化の概念は、効率的なMatlabコードを記述する方法を理解するための中心です。 すべてのデータはベクトルの形式でRAMに格納されるため、Matlabの数値アルゴリズムの速度はベクトル化操作の使用に直接依存します。



以下は、Matlabで効率的な手順を書くのに役立つ、Matlabの公式ドキュメントからの重要な抜粋です。 あなたは夢中になり、コードを最適化するために非常に多くの労働時間を費やすことができます。これはほんの数秒でプログラムの実行時間を稼ぐのに役立ちますが、私はそれが私の生産の必要だと繰り返します。



次の手法を使用すると、プログラムのパフォーマンスが大幅に向上する可能性があります。





これらの各ポイントをより詳細に検討しましょう。



ループの代わりにベクトル演算を使用する


次の例を考えてみましょう。

dx = pi/30;

nx = 1 + 2*pi/dx;

for i = 1:nx

x(i) = (i-1)*dx;

y(i) = sin(3*x(i));

end






ベクトルxおよびyが作成されていることは明らかです。 ただし、Matlabはその場で変数にメモリを割り当てます。 サイクルの最初のパス中に、長さ1の単一行に2つのベクトルが作成されます。次の各ステップで、ベクトルの長さが増加します。 サイクルの各実行中に、メモリがMatlab変数に割り当てられ、プロセッサ時間がかかります。

ベクトルを定義するには、次の方法を使用することをお勧めします。

x = 0:pi/30:2*pi

y = sin(3*x);






コードの最初の行は行ベクトルxを作成し、その長さに応じてメモリサイズが割り当てられ、ベクトル要素が隣接するRAMセルに格納されます。 コードの2行目は、2行目のベクトルの作成を開始します。Matlabは、この質問に戻らずに、必要なメモリをすぐに割り当てます。

主なことを覚えておいてください。Matlabはベクトルとマトリックスの計算により適応しており、これが開発された理由です。



ベクトルと行列のメモリの事前割り当て


Matlabはベクトルとマトリックスのサイズを自動的に調整しますが、マトリックスを事前に選択することをお勧めします。 事前割り当ては、メモリの割り当てを1回だけ処理します。これにより、マトリックス要素が隣接するメモリセル(列)に格納されます。

次のコードを検討してください。

dx = pi/30;

nx = 1 + 2*pi/dx;

nx2 = nx/2;



for i = 1:nx2

x(i) = (i-1)*dx;

y(i) = sin(3*x(i));

end



for i = nx2+1:nx

x(i) = (i-1)*dx;

y(i) = sin(5*x(i));

end






私たちは人々を考えているので、このコードは最適化されていません。ベクトルxとyのサイズを知っており、この知識を使用できます。

dx = pi/30;

nx = 1 + 2*pi/dx;

nx2 = nx/2;



x = zeros(1,nx);

y = zeros(1,nx);



for i = 1:nx2

x(i) = (i-1)*dx;

y(i) = sin(3*x(i));

end



for i = nx2+1:nx

x(i) = (i-1)*dx;

y(i) = sin(5*x(i));

end






このコードは変換されましたが、事前割り当てルールを適用できるビットがまだあります。 ベクトルx(i)= ...、およびy(i)= ...は、ベクトル化を利用しません。

最善の方法は、次のように書くことです。

dx = pi/30;

nx = 1 + 2*pi/dx;

nx2 = nx/2;

x = zeros(1,nx);

y = x;



for i = 1:nx2

x(i) = (i-1)*dx;

y(i) = sin(3*x(i));

end



for i = nx2+1:nx

x(i) = (i-1)*dx;

y(i) = sin(5*x(i));

end






この記事が他の誰かに役立つことを願っています。一時、多くの待ち時間を節約し、タスクを正常に完了するのに役立ちました。



All Articles