4

しばらくの間、MATLAB スクリプトを作成していますが、「フードの下で」どのように機能するのかまだわかりません。次のスクリプトを考えてみましょう。これは、3 つの異なる方法で (大きな) ベクトルを使用して計算を行います。

  1. MATLAB ベクトル演算。
  2. コンポーネントごとに同じ計算を行うサイクルの場合は単純です。
  3. 一部の割り当てと一部の割り当てを回避するため、2.よりも高速であると想定される最適化されたサイクル。

コードは次のとおりです。

N = 10000000;

A = linspace(0,100,N);
B = linspace(-100,100,N);
C = linspace(0,200,N);
D = linspace(100,200,N);

% 1. MATLAB Operations
tic
C_ = C./A;
D_ = D./B;

G_ = (A+B)/2;
H_ = (C_+D_)/2;
I_ = (C_.^2+D_.^2)/2;

X = G_ .* H_;
Y = G_ .* H_.^2 + I_;
toc
tic
X;
Y;
toc

% 2. Simple cycle
tic
C_ = zeros(1,N);
D_ = zeros(1,N);
G_ = zeros(1,N);
H_ = zeros(1,N);
I_ = zeros(1,N);
X = zeros(1,N);
Y = zeros(1,N);
for i = 1:N,
  C_(i) = C(i)/A(i);
  D_(i) = D(i)/B(i);

  G_(i) = (A(i)+B(i))/2;
  H_(i) = (C_(i)+D_(i))/2;
  I_(i) = (C_(i)^2+D_(i)^2)/2;

 X(i) = G_(i) * H_(i);
 Y(i) = G_(i) * H_(i)^2 + I_(i);
end
toc
tic
X;
Y;
toc

% 3. Opzimized cycle
tic
X = zeros(1,N);
Y = zeros(1,N);
for i = 1:N,
  X(i) = (A(i)+B(i))/2 * (( C(i)/A(i) + D(i)/B(i) ) /2);
  Y(i) = (A(i)+B(i))/2 * (( C(i)/A(i) + D(i)/B(i) ) /2)^2 +  ( (C(i)/A(i))^2 + (D(i)/B(i))^2 ) / 2;
end
toc
tic
X;
Y;
toc

MATLAB は行列/ベクトル上に構築されているため、常に計算をベクトル化しようとする必要があることを知っているため (したがって、最近では、常に最適な選択とは限りません)、次のようなことを期待しています。

C = A .* B;

よりも高速です:

for i in 1:N,
  C(i) = A(i) * B(i);
end

私が期待していないのは、私が使用している 2 番目と 3 番目の方法は 1 サイクルしか実行しないにもかかわらず、上記のスクリプトでも実際には高速であることです。一方、最初の方法は多くのベクトル操作を実行します (理論的には、「 " 毎回サイクル)。これにより、MATLAB には(たとえば) 次のことを可能にする魔法があると結論付けざるを得ません。

C = A .* B;
D = C .* C;

内部にいくつかの操作がある単一の「for」サイクルよりも高速に実行されます。

そう:

  1. 最初の部分が速く実行されないようにする魔法は何ですか?
  2. "D= A .* B" と書くと、MATLAB は実際に "for" サイクルを使用してコンポーネント単位の計算を実行しますか、それとも D に "bla" と "bla" の乗算が含まれていることを単に追跡しますか?

編集

  1. C++ を使用して (おそらくいくつかのライブラリを使用して) 同じ計算を実装したいとします。MATLAB の最初のメソッドは、C++ で実装された 3 つ目のメソッドよりも高速ですか? (この質問には自分で答えます。少し時間をください。)

編集2

リクエストに応じて、ここに実験ランタイムがあります。

パート 1: 0.237143

パート 2: 4.440132 のうち 0.195154 を割り当て

パート 3: 2.280640 のうち 0.057500 を割り当て

そしてJITなし:

パート 1: 0.337259

パート 2: 149.602017 のうち 0.033886 を割り当て

パート 3: 82.167713 のうち 0.010852 を割り当て

4

2 に答える 2

3

ベクトル化されたコードは少数の最適化された C++ ライブラリ呼び出しに簡単に解釈できるため、最初のコードが最も高速です。Matlab は、より高いレベルで最適化することもできます。たとえば、コアではなくG*H+I最適化されたものに置き換えることができます。mul_add(G,H,I)add(mul(G,H),I)

2 番目のものは、C++ 呼び出しに簡単に変換できません。解釈またはコンパイルする必要があります。スクリプト言語の最新のアプローチは、JIT コンパイルです。Matlab JIT コンパイラはあまり良くありませんが、そうしなければならないという意味ではありません。MathWorks がそれを改善しない理由がわかりません。したがって、#2 の実行は非常に遅いため、"数学的" な操作を行っても、#1 の方が高速です。

Julia 言語は、Matlab 式と C++ の速度の妥協点として発明されました。ベクトル化されていない同じコード ( juliamatlab ) は、JIT コンパイルが非常に優れているため、非常に高速に動作します。

于 2013-05-31T00:23:30.957 に答える
0

パフォーマンスの最適化に関しては、 「for」ループと MATLAB のベクトル化で述べたように、両方のアプローチにプロファイラーを使用して @memyself の提案に従います。

教育目的で数値アルゴリズムを試すのは理にかなっていますが、それ以外の場合は、十分に実績のあるライブラリを使用します。

于 2013-05-30T22:32:52.513 に答える