[英]'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.