2011-09-27 12 views
7

私はMATLABで何かをプログラミングしていましたが、推奨されるように、私は常にベクトル化を使用しようとしています。しかし結局、プログラムはかなり遅かった。だから、ある場所では、ループを使用するとコードが大幅に高速になることがわかった(下記の例)。'for'ループとMATLABのベクトル化

この場合パフォーマンスが重要であるため、何かを間違って解釈したかどうかを知りたいのですが、ベクトル化やループが速くなるかどうか推測したくありません。

% data initialization 

k = 8; 
n = 2^k+1; 
h = 1/(n-1); 
cw = 0.1; 

iter = 10000; 

uloc = zeros(n); 
fploc = uloc; 
uloc(2:end-1,2:end-1) = 1; 
vloc = uloc; 
ploc = ones(n); 

uloc2 = zeros(n); 
fploc2 = uloc2; 
uloc2(2:end-1,2:end-1) = 1; 
vloc2 = uloc2; 
ploc2 = ones(n); 

%%%%%%%%%%%%%%%%%%%%%% 
% vectorized version % 
%%%%%%%%%%%%%%%%%%%%%% 
tic 
for it=1:iter 
    il=2:4; 
    jl=2:4; 
    fploc(il,jl) = h/6*(-uloc(il-1,jl-1) + uloc(il-1,jl)... 
     -2*uloc(il,jl-1)+2*uloc(il,jl+1)... 
     -uloc(il+1,jl) + uloc(il+1,jl+1)... 
     ... 
     -vloc(il-1,jl-1) - 2*vloc(il-1,jl)... 
     +vloc(il,jl-1) - vloc(il,jl+1)... 
     + 2*vloc(il+1,jl) + vloc(il+1,jl+1))... 
     ... 
     +cw*h^2*(-ploc(il-1,jl)-ploc(il,jl-1)+4*ploc(il,jl)... 
     -ploc(il+1,jl)-ploc(il,jl+1)); 
end 
toc 


%%%%%%%%%%%%%%%%%%%%%% 
% loop version % 
%%%%%%%%%%%%%%%%%%%%%% 
tic 
for it=1:iter 
    for il=2:4 
     for jl=2:4 
      fploc2(il,jl) = h/6*(-uloc2(il-1,jl-1) + uloc2(il-1,jl)... 
       -2*uloc2(il,jl-1)+2*uloc2(il,jl+1)... 
       -uloc2(il+1,jl) + uloc2(il+1,jl+1)... 
       ... 
       -vloc2(il-1,jl-1) - 2*vloc2(il-1,jl)... 
       +vloc2(il,jl-1) - vloc2(il,jl+1)... 
       + 2*vloc2(il+1,jl) + vloc2(il+1,jl+1))... 
       ... 
       +cw*h^2*(-ploc2(il-1,jl)-ploc2(il,jl-1)+4*ploc2(il,jl)... 
       -ploc2(il+1,jl)-ploc2(il,jl+1)); 
     end 
    end 
end 
toc 

答えて

6

私はあなたのコードを通過しませんでしたが、Matlabの最近のバージョンでのJITコンパイラは、あなたが直面している状況は非常に一般的ですポイントに改善されている - ループはベクトル化されたコードよりも高速になります。あらかじめ高速化されていることを知るのは難しいので、最も自然な方法でコードを書いてプロファイリングし、ボトルネックがあれば、ループからベクトル化(または他の方法)に切り替えてみてください。

2

おそらく、いくつかの要素からなる行列はベクトル化効率の良いテストではありません。最終的には、うまくいくかどうかはアプリケーションに依存します。

また、通常はベクトル化されたコードがよく見えますが、多くの場合、コード化されていないため、実装が傷ついてしまいます。あなたがしたことは、あなたのために何が最もうまくいくかを知っているので、素晴らしいことです。

6

MATLABのジャストインタイムコンパイラ(JIT)は、過去2年間で大幅に改善されています。そして、あなたが一般的にコードをベクトル化するのが正しいとはいえ、私の経験からすると、これは特定の演算と関数にのみ当てはまり、関数が扱うデータの量にも依存します。

最も効果的な方法を見つけるには、profile your MATLAB codeにベクトル化を使用する方法と使用しない方法があります。

+0

「あなたが持っているデータの量に依存しています」と言ったとき、あなたが意味することについてもう少し具体的になりますか?ループが通常より大きいデータセットで悪化することを意味しましたか? –

0

私はこのベクター化を呼びません。

あなたは何らかのフィルタ操作を行っているようです。そのようなフィルタの真にベクトル化されたバージョンは、元のデータであり、フィルタ行列(すなわち、forループ全体を表す1つの行列)が乗算されている。

これらの行列の問題は、これらの行列が非常に疎である(対角線の周りに数個の非ゼロ要素しかない)ので、それらを使用することはほとんど不可能であるということです。 sparseコマンドを使用することはできますが、その場合でも、表記の優雅さはおそらく余分なメモリを必要としません。

ループカウンタなどはまだ複雑な行列として扱われていたので、Matlabはforループでよく使用されていました。そのような行列のチェックはすべての繰り返しで評価されていました。私の推測では、あなたのforループの中で、フィルター係数を適用するたびにこれらのチェックはすべて実行されます。

おそらくmatlab関数filterfilter2はここで便利ですか? あなたはこのポストを読んでもいいかもしれません:Improving MATLAB Matrix Construction Code : Or, code Vectorization for begginers

0

起動時のオーバーヘッドが考えられます。一時的な行列がシーンの背後に作成された場合は、メモリの割り当てに備えてください。また、MATLABはあなたの行列が小さいので、ループオーバーヘッドがあると推論することはできません。だからあなたのベクトル化バージョンは、操作の既知の数にこれを比較し

double* tmp=(double*)malloc(n*sizeof(double)); 
for(size_t k=0;k<N;++k) 
    { 
// Do stuff with elements 
    } 
free(tmp); 

のようなコードで終わる可能性があります

double temp[2]; 
temp[0]=...; 
temp[1]=...; 

のmalloc-loopcounterフリー時間が長いときにJITが速いかもしれ各計算のワークロードと比較します。

関連する問題