我的问题是在Matlab中快速执行许多低维投影 。我有一个数组z
,其维度为(n,L,d)
;这些参数如下获得。我接受一个大小为N的输入数组,比如说N = [200, 200]
,n = prod(N) = 200*200 = 40,000
和d = numel(N) = 2
;也就是说,n是我的离散网格中的点数,d是输入数组的维数(例如图像,或来自高度图的平面)。然后,我将可能的高度(我的程序将输出 - 注意上面的高度图)与L点分开,比如说L = 32
。
对于每个i = 1:n
和j = 1:L
,我想将向量z(i,j,:)
投影到单位球上。*目前,我有以下天真的代码:
z = reshape(z,[n,L,d]); z_norms = norms(z,2,3);
for i = 1:n
for j = 1:L
z(i,j,:) = z(i,j,:)/max(1,z_norms(i,j));
end
end
函数norms(v,p,dim)
沿着维度dim取得矩阵v的p范数(在这种情况下输出(n,L)
矩阵)。
我对如何改进这一点有各种各样的想法。一个想法如下:
for i = 1:n
for j = 1:L
normsquared = sum(z(i,j,:).^2)
if normsquared > 1
z(i,j,:) = z(i,j,:)/sqrt(normsquared)
end
end
end
请注意,每次都会覆盖normsquared,因此它不会占用我的空间。当我在另一个问题上使用它时,它加快了这个过程;但是,我刚刚对这个问题进行了测试,实际情况要差得多 - 大约慢三倍;事实上,计算normsquared
需要大约2.5倍的时间,就像在第一种情况下做预测一样!
奇怪的是,如果我将sum(z(i,j,:).^2)
更改为z(i,j,1)^2 + z(i,j,2)^2
(在使用d = 2的情况下),那么它实际上比第一种(天真)方法稍快一些......如果有人也可以向我解释这一点,那就太棒了!
如果有人对如何提高速度有任何建议,那么我会非常感激!目前大约90%的程序运行时间用于此!
*实际上,我想把它投射到lambda乘以lambda是另一个参数的单位球,但这不太可能在算法上产生差异 - 只需将z除以lambda,做投影然后乘以lambda, 例如。
答案 0 :(得分:2)
当您可以使用bsxfun
重写双parfor
循环来“向量化”操作时,无需使用for
:
z = bsxfun(@rdivide,z,max(1,z_norms))
max
函数对n-by-L z_norms
矩阵的阈值进行矢量化,使得所有值都小于或等于1。 z
是一个3维n-by-L-by-d数组。 bsxfun
在z_norms
的第三个维度上d
实际上复制了较低维z
矩阵NoClassDefFoundError
次,这样两者的元素划分(rdivide
)就可以了执行。结果是n-by-L-by-d数组。
在您的代码profiling之后,重写循环以利用Matlab的vectorization功能应该是您尝试improve performance的第一件事。
答案 1 :(得分:1)
您可以尝试使用for
循环替换内部parfor
循环。 parfor
允许您在多核处理器上同时运行多次迭代。