【问题标题】:Fast Algorithm for Multiple Projections in MatlabMatlab中多重投影的快速算法
【发布时间】:2015-07-22 16:36:05
【问题描述】:

我的问题是在 Matlab 中快速执行许多低维投影。我有一个数组z,其尺寸为(n,L,d);这些参数如下获得。我取一个大小为 N 的输入数组,例如 N = [200, 200]n = prod(N) = 200*200 = 40,000d = numel(N) = 2;也就是说,n 是我的离散化网格中的点数,d 是输入数组的维度(例如,图像或高度图中的平面)。然后我用 L 点离散可能的高度(我的程序将输出 - 注意上面提到的高度图),比如L = 32

对于每个i = 1:nj = 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 所需的时间大约是第一种情况下进行投影的两倍半!

奇怪的是,如果我将 sum(z(i,j,:).^2) 更改为 z(i,j,1)^2 + z(i,j,2)^2(在使用 d = 2 的情况下),那么它实际上比第一种(幼稚)方法要快一些......如果有人也可以向我解释这一点,那么那太好了!

如果有人对如何加快速度有任何建议,我将不胜感激!目前我的程序大约 90% 的运行时间都花在了这上面!


*实际上,我想将它投影到 lambda 乘以单位球上,其中 lambda 是另一个参数,但这不太可能对算法产生影响 - 只需将 z 除以 lambda,进行投影,然后乘以 lambda, 例如

【问题讨论】:

    标签: algorithm matlab time-complexity projection


    【解决方案1】:

    当您可以使用 bsxfun 重写双 for 循环以“矢量化”操作时,无需使用 parfor

    z = bsxfun(@rdivide,z,max(1,z_norms))
    

    max 函数对 n×L z_norms 矩阵的阈值进行矢量化处理,以使所有值都小于或等于 1。 z 是一个 3 维 n×L×d 数组。 bsxfunz 的第三维上几乎复制了较低维度z_norms 矩阵d 次,以便可以执行两者的逐元素除法(rdivide)。结果是一个 n×L×d 数组。

    profiling 您的代码之后,重写循环以利用 Matlab 的vectorization 功能应该是您尝试improve performance 的第一件事。

    【讨论】:

    • 谢谢。是的,这就是我通常所做的。我倾向于首先以幼稚的格式编写代码,只是确保一切正常,然后返回矢量化 for 循环。例如,我有“for j=1:L, sum = sum + Gamma(j)*u(:,j), end”,所以我把它改成了 u*Gamma'(Gamma 是 (1,L)) .
    • 你能解释一下“bsxfun”函数的作用吗?我之前已经看到它用于其他一些事情 - 我认为它是将矩阵的列与向量分量的乘法向量化,或者类似的东西。
    • 另外,我认为您的意思是“@rdivide”,而不是“@ldivide”。 bsxfun 的 Matlab 文档在这个问题上最不清楚,但我用 l 尝试过,但没有用,但用 r 可以。奇怪的是,使用 bsxfun 并没有给出与使用循环相同的结果完全,只是一个非常相似的结果......
    • @SmileySam:是的,rdivide - 我已经更新了我的答案(bsxfun 不在乎你传递了什么函数,所以文档当然会告诉你任何事情)。当矢量化 - 不同的算法和排序 - 这就是浮点的工作方式时,您可能会得到在数值意义上略有不同的结果,这并不奇怪。
    • 解释 bsxfun 所做的一切可能超出了这里的答案范围 - 这就是文档的用途,并且有一个完整的 StackOverflow tag dedicated to the function。但我会尝试添加一些关于这种情况下发生的小细节。
    【解决方案2】:

    您可以尝试用parfor 循环替换您的内部for 循环。 parfor 允许您在多核处理器上同时运行多个迭代。

    http://nl.mathworks.com/help/distcomp/parfor.html

    【讨论】:

    • 好的,谢谢。我有一个四核处理器(所以如果我能把它加速八倍,那就太棒了!)。你的说法给了我一个想法:因为我每次都在做同样的,相当简单的处理,这对我的 GPU 来说是一个很好的操作吗?目前我只使用笔记本电脑(GeForece 750M 专用),但我家里有一张 5 年前的游戏卡(ATi 4900,2GBs GDDR5 RAM)。你认为这会带来很大的不同吗?
    • 另外,没有特别需要循环的顺序。交换顺序以便我可以并行运行 n 长度 (n >> L) 会更好,还是并行运行 L 长度更好?
    • @SmileySam parfor 是 CPU。 GPU 计算需要不同的算法结构和更多的学习才能使其工作。如果你在parpool 中运行这个东西,for 循环甚至不会按顺序发生。一般来说,你希望只有 1 个 for 循环,所以如果你可以将嵌套压缩成 1 个,那就更好了(提示:你可以)。
    • 我尝试用两个循环运行它:一个 for 循环,然后一个 parfor 循环。只是“正常”(即for-for),程序运行大约需要20 秒。经过五分钟或工作后,它仍然没有完成使用 parfor...
    • 为了组合循环,我假设我只是将 (n,L,d) 重塑为 (nL,d),然后运行 ​​(par)for 循环 k=1:nL,然后重新整形回 (n,L,d)? (实际上,我最终输出为向量,所以我只是直接整形为(nL,d),然后进行操作,然后输出为(nL*d,1)。 )
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-03
    相关资源
    最近更新 更多