[英]'for' loop vs vectorization in MATLAB
我在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
我沒有查看你的代碼,但最近版本的Matlab中的JIT編譯器已經改進到你所面臨的情況非常普遍 - 循環可以比矢量化代碼更快。 事先很難知道哪個會更快,所以最好的方法是以最自然的方式編寫代碼,對其進行分析,然后如果存在瓶頸,嘗試從循環切換到矢量化(或其他方式)。
MATLAB的即時編譯器(JIT)在過去幾年中得到了顯着改善。 即使你是對的,通常也應該對代碼進行矢量化,根據我的經驗,這僅適用於某些操作和函數,還取決於函數處理的數據量。
找到最佳方法的最佳方法是使用和不使用矢量化來分析MATLAB代碼 。
也許一些元素的矩陣不是矢量化效率的良好測試。 最終,它取決於應用程序的運行情況。
此外,通常矢量化代碼看起來更好(對底層模型更真實),但在很多情況下它沒有,並且最終會損害實現。 你所做的很棒,因為現在你知道什么最適合你。
我不會稱之為矢量化。
您似乎正在進行某種過濾操作。 這種濾波器的真正矢量化版本是原始數據,乘以濾波器矩陣(即,代表整個for循環的一個矩陣)。
這些矩陣的問題在於它們非常稀疏(對角線周圍只有少數非零元素),使用它們幾乎沒有效率。 您可以使用sparse
命令,但即便如此,符號的優雅可能並不能證明所需的額外內存。
Matlab以前對for循環不好,因為即使循環計數器等仍被視為復雜矩陣,因此在每次迭代時都會對所有矩陣的檢查進行評估。 我的猜測是,在你的for循環中,每次應用濾波器系數時仍會執行所有這些檢查。
也許matlab函數filter
和filter2
在這里很有用? 您也可以閱讀這篇文章: 改進MATLAB矩陣構造代碼:或者,代碼矢量化為begginers
一種可能的解釋是啟動開銷。 如果在場景后面創建臨時矩陣,請准備好進行內存分配。 另外,我猜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-free時間長於每次計算的工作負載時,JIT可能會更快。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.