【问题标题】:How to vectorize the 'for' loop in Matlab如何在 Matlab 中矢量化“for”循环
【发布时间】:2014-02-11 23:02:31
【问题描述】:

我正在编写一个计算某种矩阵的 Matlab 应用程序。我正在尝试用基于向量的计算替换程序中的 for 循环,但是,我被卡住了。

到目前为止,我已经想到了这个简单的示例代码部分:

kernel = zeros(5,5,5);
offset = 3;
sig=1;

for x=-2:2
    for y=-2:2
        for z=-2:2
            IN = x.^2/(sig^2) + y.^2/(sig^2) + z.^2/(sig^2); 
            kernel(offset+x, offset+y, offset+z) = exp(-IN/2);
        end
    end
end

可以用这样的结构代替:

[x,y,z] = ndgrid(-2:2,-2:2,-2:2);
IN = x.^2/(sig^2) + y.^2/(sig^2) + z.^2/(sig^2); 
kernel = exp(-IN/2);

并给出相同的结果。 但是如果我需要做一些小改动怎么办:

kernel = zeros(5,5,5);
offset = 3;   
sig=1;

%sample 3x3 matrix
R=magic(3)/10; 

for x=-2:2
    for y=-2:2
        for z=-2:2

            % calculation of new x, y, z
            point = [x,y,z]*R;   

            IN = (point(1)^2 )/(sig^2) + (point(2)^2)/(sig^2) + (point(3)^2)/(sig^2);
            kernel(offset+x, offset+y, offset+z) = exp(-IN/2);
        end
    end
end

如何加快构建速度?它可以很容易地矢量化吗?我对 Matlab 很陌生,所以我将不胜感激。非常感谢!

【问题讨论】:

    标签: performance matlab vector vectorization


    【解决方案1】:

    一种选择是使用arrayfun

    sig=1;
    
    %sample 3x3 matrix
    R=magic(3)/10;
    
    [x,y,z] = ndgrid(-2:2,-2:2,-2:2);
    kernel = arrayfun(@(x, y, z) exp(-(norm([x,y,z]*R/sig)^2)/2), x,y,z);
    

    解释:

    arrayfun 采用一个函数,该函数作用于标量输入以产生标量输出,以及传递给函数的输入数组。然后它遍历输入数组,在每个数组上运行你的函数,并将每个数组的输出放在输出矩阵(-es)的相应条目中。所以arrayfun 基本上是嵌套循环,这会减慢你的速度。

    在此示例中,我还使用了anonymous function(也称为 lambda 函数)来完成最内层循环中的工作。由于 lambda 函数需要是 Matlab 中的单个表达式,我不得不稍微重写内部循环(使用简单的代数操作)。如果您需要将 arrayfun 与不容易表示为 lambda 的函数一起使用,您始终可以将该函数编写在单独的 .m 文件中并将其传递给 arrayfun

    编辑:请注意,您不必再预先分配kernel,也不需要offset

    【讨论】:

    • 很好的答案,谢谢!奇迹般有效。奇怪的是,在这种情况下,循环的运行速度要快几倍......显然 arrayfun 没有优化得很好。
    • @user3299285 对我来说,arrayfun 版本要快得多。很大程度上取决于你有多少次循环迭代,以及你在每次迭代中做了多少工作。对于这样一个小循环(总共 27 次迭代),从绝对值开始非常快,因此没有太多收获。此外,norm 取平方根(与其他算术运算相比速度​​较慢)只是为了在之后立即返回并平方结果。如果您想更好地比较循环与 arrayfun 的速度,请将循环的主体替换为 arrayfun 使用的相同函数。
    • 恐怕我不能同意。即使用相同的功能替换主体,我得到的结果也比使用 arrayfun 更好。看来arrayfun确实不是太快了:stackoverflow.com/questions/12522888/…
    • @user3299285 哇,我猜arrayfun毕竟不是一个好的解决方案。
    猜你喜欢
    • 2015-02-03
    • 2014-09-25
    • 2011-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-25
    相关资源
    最近更新 更多