2011-09-27 88 views
7

我正在用MATLAB編程,並且按照建議,我總是嘗試使用矢量化。但最終該計劃相當緩慢。所以我發現在一個地方使用循環時代碼顯着更快(下面的例子)。'for'loop vs在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)已顯著在過去幾年改善。即使你是正確的,通常應該對代碼進行矢量化處理,但從我的經驗來看,這僅適用於某些操作和功能,也取決於你的函數處理多少數據。

爲你找出最有效,最好的辦法,就是profile your MATLAB code有和沒有量化。

+0

當你說「這取決於你有多少數據」時,你介意對你的意思做一些更具體的描述嗎?你的意思是說循環通常在更大的數據集上表現更差嗎? –

0

我不會稱之爲矢量化。

您似乎在做某種過濾操作。這種濾波器的真正矢量化版本是原始數據,乘以濾波器矩陣(即代表整個for-loop的一個矩陣)。

問題與這些矩陣的是,他們是如此的稀少(大約只有對角線幾個非零元素),它是幾乎沒有有效地使用它們。您可以使用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]=...; 

所以JIT可能更快當的malloc-循環計數器自由時間長與每次計算的工作量相比。