2

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

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

第一个问题:这是否已实施,是否在开源中可用?

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

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

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

4

1 回答 1

1

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

由于您的子图像大小不同,因此在 1 个内核中批量处理所有子图像可能不是一个好的选择。您可以设计一个内核来将子图像与基础图像进行一次完全卷积,并为每个子图像调用 35 次。

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

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

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

更新

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

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

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

http://docs.nvidia.com/cuda/cuda-samples/index.html#cuda-parallel-reduction

和一个很好的白皮书在这里

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

于 2013-08-21T04:31:58.673 回答