CUDA 内核中的中值选择

Posted

技术标签:

【中文标题】CUDA 内核中的中值选择【英文标题】:Median selection in CUDA kernel 【发布时间】:2013-09-03 12:36:23 【问题描述】:

我需要计算 CUDA 内核中大小为 p 的数组的中位数(在我的情况下,p 很小,例如 p = 10)。为了简单起见,我使用 O(p^2) 算法,但以牺牲时间性能为代价。

是否有一个“函数”可以有效地找到我可以在 CUDA 内核中调用的中位数?

我知道我可以实现一个选择算法,但我正在寻找一个函数和/或测试代码。

谢谢!

【问题讨论】:

鉴于p 的值很小,您是否考虑过使用采用最小排序网络的模板化函数? p 的小值可能表明您应该编写自己的代码,正如其他人已经建议的那样。如果你想看一些基本的示例代码,别忘了看看cuda samples和CUB中的各种排序代码。 尝试实现en.wikipedia.org/wiki/Median_of_medians 在第一本 Graphics Gems 书中,Paeth 很好地实现了 3x3 中位数,它丢弃了最小值和最大值,直到剩下中位数。 Paeth, Alan W.,3×3 网格上的中值发现,p。 171-175,代码:p。 711-712。这里的 C 代码:cudahandbook.to/1dCFCOQ @rodms 你能计算cuda中数组的中位数吗?如果是,请提供您所做的方式。 【参考方案1】:

这里有一些提示:

    使用更好的选择算法:QuickSelect 是快速排序的更快版本,用于选择数组中的第 k 个元素。对于编译时常量掩码大小,sorting networks 甚至更快,这要归功于高 TLP 和 O(log^2 n) 关键路径。如果您只有 8 位值,则可以使用基于直方图的方法。 This paper 描述了一种实现,每个像素花费恒定的时间,与掩码大小无关,这使得它对于非常大的掩码大小非常快。您可以通过使用最小启动策略(仅运行尽可能多的线程以使所有 SM 保持最大容量)、平铺图像并让同一块的线程在每个内核直方图上协作来实现并行化。 Sort in registers. 对于较小的掩码大小,您可以将整个数组保存在寄存器中,使用 sorting network 进行中值选择要快得多。对于较大的掩码尺寸,您可以使用shared memory。 首先将块使用的所有像素复制到shared memory,然后复制到也在共享内存中的线程本地缓冲区。 如果您只有几个需要非常快的掩码(例如 3x3 和 5x5),use templates 使它们成为编译时间常数。这可以大大加快速度,因为编译器可以展开循环并重新排序更多指令,可能会改进负载批处理和其他好处,从而大大提高速度。 确保您的阅读是coalesced and aligned。

您还可以进行许多其他优化。确保您通读了CUDA documents,尤其是Programming Guide 和Best Practices Guide。 当您真的想追求高性能时,别忘了好好看看 CUDA 分析器,例如 Visual Profiler。

【讨论】:

【参考方案2】:

即使在单个线程中,也可以对数组进行排序并在 O(p*log(p)) 中选择中间的值,这使得 O(p^2) 看起来过多。如果您有 p 个线程可供使用,也可以像 O(log(p)) 一样快地对数组进行排序,尽管这可能不是小 p 的最快解决方案。在此处查看最佳答案:

Which parallel sorting algorithm has the best average case performance?

【讨论】:

如果你只想要中位数,那么排序就太过分了。 同意。这里有一些比排序更快的东西:en.wikipedia.org/wiki/Selection_algorithm

以上是关于CUDA 内核中的中值选择的主要内容,如果未能解决你的问题,请参考以下文章

如何选择中值? [复制]

C和Python实现快速排序-三数中值划分选择主元(非随机)

快速排序/快速选择算法

CUDA内核中的竞争条件

访问不同 CUDA 内核中的类成员

CUDA 中的每个内核调用是不是保证唯一线程 ID?