2011-09-27 84 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-循环计数器自由时间长与每次计算的工作量相比。