【问题标题】:very slow matlab jacket if statement非常慢的matlab夹克if语句
【发布时间】:2012-08-03 17:21:28
【问题描述】:

我在 matlab 中使用 cuda\jacket 时遇到了一个非常缓慢的 if 语句响应。 (对于找到局部最大值的相同代码,使用简单的 for 循环和 if 条件,5 秒对 0.02 秒)

作为 GPU 编程的新手,我去阅读了,当我看到之前的 matlab if statements with CUDA SO 讨论时,我觉得缺少了一些东西。 您无需使用 cuda 即可知道对代码进行矢量化会更好。但是,在某些情况下,无论如何您都需要使用 if 语句。 例如,我想找出 2D 图像的像素(比如 m(a,b))是否是其 8 个最近邻居的局部最大值。在 matlab 中,一个简单的方法是在 if 语句中使用 8 个逻辑条件:

如果 m(a,b)>m(a-1,b-1) & m(a,b)>(a,b-1) & m(a,b)>(a+1,b -1) & ... 等所有最近的邻居

如果您知道如何解决(或矢量化)这个问题,我将不胜感激...

【问题讨论】:

  • 我不完全确定你想在这里矢量化什么 - 你已经在 matlab 中拥有局部最大值函数,它本质上是你正在寻找的矢量化版本......或者你只是想将 8 个if 布尔条件向量化为 1?在那种情况下,请参阅我的答案...

标签: performance matlab if-statement cuda jacket


【解决方案1】:

使用多个“if”语句(或任何其他条件语句)的问题在于,对于每个语句,结果都会从 gpu 复制到主机,这可能会很昂贵。

最简单的方法是按以下方式进行矢量化。

window = m(a-1:a+1, b-1:b+1);
if all(window(:) <= m(a,b))
% do something
end

如果您可以显示 if / else 条件的作用,则可以进一步优化。即,请发布 if/else 代码以查看是否有其他优化可用(即查看完全删除 if 条件的可能方法)。

编辑

有了新信息,可以做以下事情。

for j = 1:length(y)
 a = x(j);
 b = y(j);
 window = d(a-1:a+1, b-1:b+1);
 condition = all(window(:) <= d(a,b));
 M(a, b) = condition + ~condition * M(a,b);
end

您可以使用 gfor 循环使其更快。

gfor j = 1:length(y)
 a = x(j);
 b = y(j);
 window = d(a-1:a+1, b-1:b+1);
 condition = all(window(:) <= d(a,b));
 M(a, b) = condition + ~condition * M(a,b);
gend

【讨论】:

  • 这里是我使用的代码:'for j=1:length(y) if (d(x(j),y(j))>d(x(j)-1,y (j))) &&... (d(x(j),y(j))>d(x(j),y(j)-1)) &&... (d(x(j), y(j))>=d(x(j)+1,y(j))) &&... (d(x(j),y(j))>=d(x(j),y( j)+1)) && ... (d(x(j),y(j))>d(x(j)-1,yy(j)-1)) && ... (d(x( j),y(j))>d(x(j)-1,y(j)+1)) && ... (d(x(j),y(j))>=d(x(j )+1,y(j)-1)) && ... (d(x(j),y(j))>=d(x(j)+1,y(j)+1)); M(x(j),y(j))=1;结束结束'
  • 谢谢,我试过 gfor,但让 matlab 崩溃了……我发现转换回 cpu 变量(即单变量)是迄今为止最快的方法。在该代码段之前,我将 gpu 用于 medfilt2 和 filter2,在转换为 single 之后,我使用 find 和 for 循环。另一方面,我希望 gfor 支持 find...(应该有一种快速查找非零矩阵元素的方法)
  • 我设法让 gfor 开始工作。显然,'window=d(a-1:a+1, b-1:b+1)' 行导致 Matlab 崩溃。相反,我只是明确地编写了 window(:),但我没有对 cpu 代码进行任何改进。我想是因为 d 是一个稀疏的 1024x1024 矩阵?
  • @nate 稀疏矩阵索引的支持有限。这可能是您看到崩溃的原因。
【解决方案2】:

使用内置函数

最简单的已经优化的方法可能是使用imregionalmax函数,

maxinI = imregionalmax(I, CONN); 

其中CONN 是所需的连接性(在您的情况下为 8)。

但请注意,imregionalmax 是图像处理工具箱的一部分。

使用max函数

如果你想看看是否只有一个像素是它的邻居的局部最大值,你可能会做类似的事情

if  m(a,b) == max(max(m( (a-1) : (a+1), (b-1) : (b+1))))

或者也许不是采取两个max,在某些情况下重塑可能会更快,

if  m(a,b) == max(reshape (m( (a-1) : (a+1), (b-1) : (b+1)), 9,1)  )

没有max 函数

最后,如果您想完全避免 max 函数,也可以采用比目前更矢量化的形式,即

if  all(reshape( m(a,b) >= m( (a-1) : (a+1), (b-1) : (b+1)), 9,1))

【讨论】:

  • 感谢您的回复。 Matlab 方面,虽然您建议的代码更优雅,但我发现在单个 if 行中编写完整的 8 个条件总是更快(乘以 1.8 到 2.6 倍)我的问题是任何大小大于 ~ 1e4 的 for 循环会将代码减慢到我无法使用的水平。所以我想我问是否可以在没有 for 循环的情况下完成局部最大值搜索...
  • @wavepacket:我更新了答案以包含 Matlab 的内置区域最大值函数。
  • 谢谢!!我不知道 imregionalmax ......不幸的是,它比带有 if 条件的 for 循环慢 6 倍。我将研究它的机器,看看它如何与 cuda 一起使用。再次感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-23
  • 1970-01-01
  • 1970-01-01
  • 2012-02-21
  • 1970-01-01
  • 2015-10-25
  • 1970-01-01
相关资源
最近更新 更多