多个小卷积:图像处理



我正在编写一个CUDA程序,该程序将尝试在一个基本图像中定位大约35个子图像或图案。每个子图像(图案)只能存在于基础图像的一个小区域(比如10x10像素的窗口)中。子图像的大小从1000到10000像素不等。基本图像为640x480像素。

我通过将子图像与基础图像的子部分进行卷积来实现这一点,如果卷积结果小于阈值,则将其视为匹配。我必须对每个子图像进行大约100次卷积(因为我只检查允许位置的10x10窗口)。

第一个问题:这已经实现了吗?它在开源中可用吗?

第二个问题:哪个是更好的实施战略?

  1. 粗粒度:每个CUDA线程对基础图像中的子图像进行完全卷积。每个子图像和位置都有一个CUDA线程
  2. 细粒度:每个CUDA线程计算卷积的一个分量(像素):因此,CUDA线程将子图像的一个像素乘以基础图像的适当像素。然后,使用syncblock()对这些倍数求和

更新:我两种方法都有。我认为最好的方法是方法一的变体,将较大的子图像划分为较小的子图像。现在,所有子图像的大小大致相同(例如1024个像素)。然后,每个CUDA线程对单个位置进行完全卷积。完成后,我将所有结果发送给主机,主机负责将中间部分重新组合在一起(用于分割成更小部分的子图像)。优点是所有CUDA线程都执行相同的工作量。这似乎是第二种方法的两倍,这是有问题的,因为子图像的大小不同。

我建议您为每个子图像和位置使用1个cuda线程块(包含多个cuda螺纹)。

由于子图像的大小各不相同,在1个内核中批量处理所有子图像可能不是一个好选择。您可以设计一个内核来对子图像和基本图像进行一次完整的卷积,并对每个子图像调用35次。

在内核中,网格包含多个线程块,其数量等于允许位置的数量。然后,每个线程块计算子图像和基础图像的给定位置之间的像素倍数的总和。

这与您的策略2类似。主要区别在于,每个线程可以计算多个像素,而内核只使用一个线程块来进行求和,这不需要通过全局内存在线程块之间进行同步。

假设你的子图像有2000个像素,允许的位置是10x10。您可以创建一个包含100个块的内核,每个块包含256个线程。一个块内的256个线程将对2000倍像素进行并行求和。

更新

您提出的方法可能有2个问题,

  1. 每个内核的线程太少。正如您所描述的,对于允许的位置,您的内核可能有10x10=100个线程,每个线程加起来大约是1024倍像素。通常,内核中至少需要32个线程块和每个块64~256个线程才能充分利用GPU
  2. 更多的内核启动通常意味着更多的启动开销和更低的速度,所以将子映像划分为更小的映像不是一个好的选择

类似二叉树的并行约简实际上比线性约简更快。你可以在这里找到并行还原示例代码

http://docs.nvidia.com/cuda/cuda-samples/index.html#cuda-平行还原

还有一份很好的白皮书

http://docs.nvidia.com/cuda/samples/6_Advanced/reduction/doc/reduction.pdf

最新更新