我有一个标量函数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的有效方法。
答案 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
,您可以获取ndgrid
,bsxfun
和某些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
这里只是该向量的欧几里德范数?)那么它会变得更简单。