2016-05-04 25 views
3

MATLABコードを最適化する必要があります。コードはシンプルですが、計算ユニットの一部です。これは〜8000回(冗長なし)です(この計算単位は実際には10〜20K回使用されます)。 MATLABコード全体はかなり長くて複雑です(私のような物理学者にとって)、MATLABプロファイラでは、次のセグメントが実行時間のほぼ半分(!)を占めると主張しています。MATLAB行列要素の賢明な乗算の最適化

コードは基本的に3つのグループ(A、B、C)からの3つの行列のすべての置換を要素ごとに掛け合わせて、それをある重み付けで合計します。グループAには1つの行列があり、グループBには4つの行列があり、グループCには7があります。

私はいくつかのベクトル化手法を試みましたが、同じ実行時間が得られました。

MATLABプロファイラを使用して、各行で費やされた合計時間(8000回の呼び出しすべて)を確認しました。コメントに記述しました。

for idx_b = 1:4 

B_MAT=B_Container_Cell{idx_b}; 

for idx_c = 1:7 

    C_MAT = C_Container_Cell{idx_b}(:,:,idx_c); % 60 sec 

    ACB=A_MAT.*C_MAT.*B_MAT; % 20 sec 

    Coeff_x = Coeff_x_Cell{idx_b}(p1,p2,idx_c,p3); 
    Coeff_y = Coeff_y_Cell{idx_b}(p1,p2,idx_c,p3); 
    Coeff_z = Coeff_z_Cell{idx_b}(p1,p2,idx_c,p3); 

    Sum_x = Sum_x+Coeff_x.*ACB; % 15 sec 
    Sum_y = Sum_y+Coeff_y.*ACB; % 15 sec 
    Sum_z = Sum_z+Coeff_z.*ACB; % 15 sec 

end 

いくつかの事前の知識 -
A_MATループ
B_MAT ouside定義された1024×1024複雑な二重定数行列であるが、1024×1024二重マトリックス、本質的に疎(のみ0と1の値、のものであるである〜5
C_MAT)全元素のうち%が1024×1024の複雑な二重

SUM_X/Sum_y/Sum_zが適切に開始されたある
Coeff_X/Coeff_y/Coeff_zダブルスカラー
P1、P2、P3は、パラメータ(このコード・セグメントの定数)は、ほとんどの消費操作は変数の割り当てである理由

誰もが知っていますしていますか? は(私が割り当てをスキップして、直接の表現でC_MATを交換しようとした、まだそれはパフォーマンス悪化)3を作成するための


ベクトル化私が試しtechiqueは猫を使用することです
は、再構築しようとrepmatを巨大な2次元行列は、要素ごとにそれらを乗算し、すべての要素を(変形して)お互いの上に置き、関連する次元を介して合計します。第1の行列は、Aが4×7 = 28回繰り返され、第2の行列が7回反復され、第3の行列は全てC行列(= 28行列)であった。


サンプル入力以下link
のコードは、サンプル入力ファイルを生成します。これらの変数の実行時間は〜0.38秒です(元のコード+変数〜0.42、実際のCセルコンテナは非常に大きいので、抽出に時間がかかります)

+4

は、 '*'の動作は、(*'行列乗算 'とは異なり)可換です。 –

+0

@BenVoigtそれはあまりパフォーマンスを変更しません。 – Alexander

+0

あなたの質問のベクトル化手法を参照してください。何を試しましたか? – BillBokeey

答えて

2

入力セル配列の配列が同じサイズである場合、MATLABのベクトル化手法を活用するために、入力をセル配列の代わりに多次元配列として格納することをお勧めします。この場合、具体的な抽出にはindexing要素と合計削減のためのmatrix-multiplication。したがって、入力を形成するとき、入力に対応する多次元配列を形成することができる。B_Container_Cell,C_Container_Cell,Coeff_x_Cell,Coeff_y_CellおよびCoeff_z_Cell。今、これらはB_Container_Cell2Dの配列を含む1Dのセル配列であり、残りは3D配列を持ちます。したがって、多次元配列を使用する場合、それらを1つの追加の次元、すなわちそれぞれ3Dおよび4D配列とすることになる。これらの多次元配列を使用する最後

Bm = cat(3,B_Container_Cell{:}); 
Cm = cat(4,C_Container_Cell{:}); 

Cx = cat(4,Coeff_x_Cell{:}); 
Cy = cat(4,Coeff_y_Cell{:}); 
Cz = cat(4,Coeff_z_Cell{:}); 

、ベクトル化溶液 -

だがそうように、それらの last+1寸法に沿って catを用いて連結して所定のセル配列を変換させ、それらの多次元アレイフォーマットをシミュレートしますそして所望の出力を得る -

%// Get ACB across all iterations and reshaped into (Nx28) shaped array 
Ar = reshape(bsxfun(@times,bsxfun(@times,Cm,permute(Bm,[1,2,4,3])),A_MAT),[],28); 

%// Use matrix-multiplication to sum reduce sliced versions of Cx, Cy and 
%// Cz, to get respectived summed outputs 
sz = size(A_MAT); %// Output array size 
Sum_x_out = reshape(Ar*reshape(Cx(p1,p2,:,:),[],1),sz); 
Sum_y_out = reshape(Ar*reshape(Cy(p1,p2,:,:),[],1),sz); 
Sum_z_out = reshape(Ar*reshape(Cz(p1,p2,:,:),[],1),sz); 

それが使用されたパラメータp3ようには見えませんのでご注意ください。 (列挙されたサンプル入力用)

ランタイム試験結果 - 。あなたは、内側ループの外側 `A_MAT * B_MAT`を実行できるように

--------------------------------- With Original Approach 
Elapsed time is 2.412417 seconds. 
--------------------------------- With Proposed Approach 
Elapsed time is 1.572035 seconds. 
+0

多次元配列に行列を格納すると、(ダブルループ構造の場合でも)時間が大幅に節約されました。あなたは賞金を正当に獲得したにもかかわらず、ベクトル化も試してみます(賞金を設定してから24時間前までには、私はそれをまだ授与できません)。 – Alexander

+0

@Alexanderありがとうございます。それが動作し、十分に効率的であることを確認してください。また、二重ルーピー構造に対するベクトル化アプローチのランタイム数について知りたいです。 – Divakar

+0

ベクトル化されたバージョンは常に少なくとも20%遅くなっています。 bsxfunのメモリ使用を最適化するために変数の構造をさらに変更した後でさえ、それはまだ遅かったです。このコードは二重ループを意図していました。 – Alexander

関連する問題