我想在OpenCV中制作SIFT算法的并行版本。OpenMP:并行for不会做任何事
特别地,在sift.cpp
:
static void calcDescriptors(const std::vector<Mat>& gpyr, const std::vector<KeyPoint>& keypoints,
Mat& descriptors, int nOctaveLayers, int firstOctave)
{
...
#pragma omp parallel for
for(size_t i = 0; i < keypoints.size(); i++)
{
...
calcSIFTDescriptor(img, ptf, angle, size*0.5f, d, n, descriptors.ptr<float>((int)i));
...
}
已经给出了从84ms
一加速到52ms
四核的机器上。它并没有太大的扩展,但对于添加1行代码已经是一个很好的结果。
无论如何,循环内的大部分计算是由执行的,但无论如何它平均需要100us
。所以大部分的计算时间是由真的很高被称为(数千次)的次数。因此,将所有这些100us
结果填入若干ms
。
无论如何,我正试图优化的表现。尤其是代码为平均60us
devide两者之间for
和下面的一个观点:
for(k = 0; k < len; k++)
{
float rbin = RBin[k], cbin = CBin[k];
float obin = (Ori[k] - ori)*bins_per_rad;
float mag = Mag[k]*W[k];
int r0 = cvFloor(rbin);
int c0 = cvFloor(cbin);
int o0 = cvFloor(obin);
rbin -= r0;
cbin -= c0;
obin -= o0;
if(o0 < 0)
o0 += n;
if(o0 >= n)
o0 -= n;
// histogram update using tri-linear interpolation
float v_r1 = mag*rbin, v_r0 = mag - v_r1;
float v_rc11 = v_r1*cbin, v_rc10 = v_r1 - v_rc11;
float v_rc01 = v_r0*cbin, v_rc00 = v_r0 - v_rc01;
float v_rco111 = v_rc11*obin, v_rco110 = v_rc11 - v_rco111;
float v_rco101 = v_rc10*obin, v_rco100 = v_rc10 - v_rco101;
float v_rco011 = v_rc01*obin, v_rco010 = v_rc01 - v_rco011;
float v_rco001 = v_rc00*obin, v_rco000 = v_rc00 - v_rco001;
int idx = ((r0+1)*(d+2) + c0+1)*(n+2) + o0;
hist[idx] += v_rco000;
hist[idx+1] += v_rco001;
hist[idx+(n+2)] += v_rco010;
hist[idx+(n+3)] += v_rco011;
hist[idx+(d+2)*(n+2)] += v_rco100;
hist[idx+(d+2)*(n+2)+1] += v_rco101;
hist[idx+(d+3)*(n+2)] += v_rco110;
hist[idx+(d+3)*(n+2)+1] += v_rco111;
}
所以我尝试过它添加#pragma omp parallel for private(k)
,和奇怪的事情发生了:没有任何反应!
介绍这个parallel for
使码平均计算53ms
(对52ms
之前)。我本来期望的结果如下一种或多种:通过在由parallel for
parallel for
<52ms
开销给出
- 以
>52ms
结果,因为您可以看到共享矢量hist
被同时更新。没有发生这种情况:结果仍然正确,并且没有使用atomic
或critical
。
我是OpenMP的新手,但是从我看到的就像是这样的内在parllel for
就好像被忽略了一样。为什么会发生?
注意:所有报告的时间是相同输入的平均时间为10.000次。
UPDATE: 我试图删除第一parallel for
,留下一个在calcSIFTDescriptor
和它发生在我所期待的:不一致已经观察到,由于缺乏任何线程安全机制。在更新之前引入#pragma omp critical(dataupdate)
hist
再次给出一致性但现在的表现是可怕的:245ms
平均。
我认为这是因为parallel for
在calcSIFTDescriptor
给出的开销,这不值得并行化30us
。
但问题依然存在:为什么第一个版本(有两个parallel for
)没有产生任何变化(无论是在性能和一致性)?
因此,你正在并行地执行外部循环,使每个核心都得到自己的'calcSIFTDescriptor'来执行,然后你想把内部循环分配到...什么?所有内核都已经很忙。 –
感谢您的评论,您在我的** UPDATE **之前仅发布了一秒钟(请查看)。无论如何,正如我所说我是OpenMP的新手,但内在的“并行”是一种常见的做法。实际上'#pragma omp parallel for collapse(2)'正好引入了两个内部'for'指令(如[在此解释](http://bisqwit.iki.fi/story/howto/openmp/#Abstract)) “崩溃条款”部分) – justHelloWorld
(@Revolver_Ocelot顺便说一句我必须这样说:Snake?SNAAAAAAAKE) – justHelloWorld