GPU

时间:2016-10-07 15:25:32

标签: c++ performance opencv

我正在运行以下代码:

cv::Ptr<cv::FastFeatureDetector> fastDetector = cv::FastFeatureDetector::create(100, true, 2);
cv::Ptr<cv::cuda::FastFeatureDetector> gpuFastDetector = cv::cuda::FastFeatureDetector::create(100, true, 2);

std::vector<cv::KeyPoint> keypoints;
std::vector<cv::KeyPoint> gpuKeypoints;

cv::Mat frame;
cv::cuda::GpuMat gFrame;

frame = cv::imread("image1.jpg"); // 4608 x 3456
cv::cvtColor(frame, frame, CV_BGR2GRAY);
gFrame.upload(frame);

gpuFastDetector->detect(gFrame, gpuKeypoints);
std::cout << "FAST GPU " << gpuKeypoints.size() << std::endl;
fastDetector->detect(frame, keypoints);
std::cout << "FAST " << keypoints.size() << std::endl;

输出是:

FAST GPU 2210
FAST 3209

问题1

为什么同一算法应用于具有相同参数的同一图像会导致检测到不同数量的关键点?

问题2

我在Visual Studio中的Windows上运行它。使用调试配置时,GPU检测执行速度更快。

但是当使用发布时,普通(CPU)快速检测器的执行速度更快。此外,无论使用何种配置类型,探测器在GPU上的性能都保持不变。但是,与Debug配置相比,在Release下执行检测时,CPU的性能会急剧上升。

(我没有对我在这里提供的代码进行测量。我知道由于上下文初始化,第一次调用某些OpenCV函数可能需要更长的时间。)

这很可能与我原来的question about the FAST detector有关。 BHawk给出了关于CPU的SIMD优化的合理解释。

所以,第二个问题是:

SIMD优化CPU是否有可能比GPU更快地执行FAST功能检测?这似乎不太可能。

1 个答案:

答案 0 :(得分:2)

初始化冗长的回答:)

问题1:

调试编译不使用发行版本使用的代码优化。调试版本将执行诸如保留临时变量数据之类的操作,以便您可以读取调试器中的数据。这通常意味着临时存在于CPU寄存器中的数据将溢出并在调试版本中复制到RAM中。在优化的发行版本中不再需要时,将丢弃相同的数据。如果在编译设置中禁用代码优化,这种差异可能会消失;我不确定我以前从未尝试过编译而没有进行优化。

问题2:

在确定图像处理在GPU或CPU上的表现是否更好时,有几个因素在起作用。

1:内存管理

GPU处理的主要瓶颈是将数据加载到GPU上并从GPU中检索它。对于非常大的图像(在您的情况下为16兆像素),这个瓶颈可能成为一个重大障碍。将图像加载到GPU上然后将图像留在那里以通过OpenGL上下文进行操作和显示(如在3D游戏引擎中所见),GPU最有效。

2:串行与并行

GPU由数千个并行运行的小型处理核心组成。因此,他们能够同时执行许多小任务。另一方面,CPU经过优化,可以串行执行复杂的任务。这意味着一些任务(大图像上下文,复杂计算,多步骤过程)可能在CPU上比在GPU上表现更好。另一方面,使用小图像上下文的简单任务,并且不需要多个处理步骤,在GPU上执行速度要快得多。更复杂的是,CPU可以根据可用的计算内核数量进行并行运行。最重要的是,SIMD优化的CPU可以进一步并行化其处理。因此,具有4个内核和8个SIMD ALU的单个CPU可以同时处理32个数据。这仍然与GPU中存在的1000个内核相差甚远,但CPU内核通常处理速度更快,因此具有8个SIMD的4个内核可能在某些任务上执行得更快。当然,如果你进入具有更多核心或更多ALU的系统,CPU速度也会缩放,如果减少数量,则速度会降低。

<强>结论

由于内存瓶颈,有些图像处理任务不适合GPU。数据IO否定了大规模并行化的任何速度增益。在您拥有高度优化的并行化SIMD CPU算法的情况下,由于算法的性质和/或GPU上和下的数据IO,CPU版本的执行速度肯定可能比GPU快。您可能还会发现,在小图像上,GPU版本仍然稍微快一些。

我必须仔细阅读源代码,看看这个特定函数在CPU上运行速度和GPU运行速度的确切方式和原因,但我并不感到惊讶。关于为什么你在一个实现与另一个实现中获得不同数量的特性,这也需要通读,但它可能是为了内存分配或优化目的而改变每个实现的功能。

很抱歉答案很长,但这是一个复杂的讨论话题。