寻找有效的方法来执行计算 - Matlab

时间:2014-12-19 09:25:18

标签: performance matlab cell-array

我有一个标量函数f([x,y],[i,j])= exp(-norm([x,y] - [i,j])^ 2 / sigma ^ 2)它接收两个二维向量作为输入(这里的规范实现了欧几里德范数)。 x,i的值在1:w范围内,值y,j在1:h范围内。我想创建一个单元阵列X,使得X {x,y}将包含一个w x h矩阵,使得X {x,y}(i,j)= f([x,y],[i,j])。显然可以使用4个嵌套循环来完成:

for x=1:w;
for y=1:h;
    X{x,y}=zeros(w,h);
    for i=1:w
        for j=1:h
            X{x,y}(i,j)=f([x,y],[i,j])
        end 
    end
end
end
然而,这是非常低效的。我非常感谢创建X的有效方法。

3 个答案:

答案 0 :(得分:1)

执行此操作的一种方法是删除2个最里面的循环,然后用矢量化版本替换。通过f函数的外观,这不应该太糟糕

首先我们需要构造两个矩阵,每行包含1到w,每列包含1到h,

wMat=repmat(1:w,h,1);
hMat=repmat(1:h,w,1)';

这将代表内部的两个循环,转置将允许我们获得所有组合。现在我们可以矢量化计算(f([x,y],[i,j])= exp(-norm([x,y] - [i,j])^ 2 / sigma ^ 2)):

for x=1:w;
    for y=1:h;
        temp1=sqrt((x-wMat).^2+(y-hMat).^2);
        X{x,y}=exp(temp1/(sigma^2));
    end
end

我们一次为内环中的所有节点对计算了欧几里德范数。

答案 1 :(得分:1)

一些讨论和代码

这里的技巧是使用数字数组执行norm-calculations并尽可能晚地将结果保存到单元格数组中。要执行norm-calculations,您可以获取ndgridbsxfun和某些permute + reshape的帮助,以便根据最终单元格版本的需要为其提供“形状”。所以,这是执行这些任务的矢量化方法 -

%// Create x-y/i-j values to be used for calculation of function values
[xi,yi] = ndgrid(1:w,1:h);

%// Get the norm values
normvals = sqrt(bsxfun(@minus,xi(:),xi(:).').^2 + ...
                                bsxfun(@minus,yi(:),yi(:).').^2);
%// Get the actual function values
vals = exp(-normvals.^2/sigma^2); 

%// Get the values into blocks of a 4D array and then re-arrange to match
%// with the shape of numeric array version of X
blks = reshape(permute(reshape(vals, w*h, h, []), [2 1 3]), h, w, h, w);
arranged_blks = reshape(permute(blks,[2 3 1 4]),w,h,w,h);

%// Finally get the cell array version
X = squeeze(mat2cell(arranged_blks,w,h,ones(1,w),ones(1,h)));

基准测试和运行时

在通过预分配X和函数内联f改进原始循​​环代码后,runtime-benchmarks针对提议的矢量化方法执行,数据大小为{{1}由此获得的运行时结果是 -

w, h = 60

这表明使用提议的解决方案接近----------- With Improved loopy code Elapsed time is 41.227797 seconds. ----------- With Vectorized code Elapsed time is 2.116782 seconds. 加速!


对于非常大的数据

如果您正在处理大量数据,那么基本上您没有为20x提供足够的内存,而bsxfun已知耗尽大量内存以提高性能矢量化解决方案。因此,对于此类大型数据化案例,您可以使用以下循环方法替换先前基于bsxfun的解决方案中列出的normvals计算 -

bsxfun

答案 2 :(得分:0)

在我看来,当您浏览x=w, y=h的周期时,您正在计算一次所需的所有值。所以你不需要重新计算它们。一旦你有了这个:

for i=1:w
    for j=1:h
        temp(i,j)=f([x,y],[i,j])
    end 
end

然后,例如X{1,1}仅为temp(1,1)X{2,2}仅为temp(1:2,1:2),依此类推。如果你可以矢量化f的计算(norm这里只是该向量的欧几里德范数?)那么它会变得更简单。