【问题标题】:HOG optimization with using SIMD使用 SIMD 进行 HOG 优化
【发布时间】:2017-04-10 06:43:50
【问题描述】:

有几种尝试使用 SIMD 指令优化 HOG 描述符的计算:OpenCVDlibSimd。它们都使用标量代码将结果幅度添加到 HOG 直方图:

float histogram[height/8][width/8][18];
float ky[height], kx[width];
int idx[size];
float val[size]; 

for(size_t i = 0; i < size; ++i)
{
    histogram[y/8][x/8][idx[i]] += val[i]*ky[y]*kx[x];
    histogram[y/8][x/8 + 1][idx[i]] += val[i]*ky[y]*kx[x + 1];
    histogram[y/8 + 1][x/8][idx[i]] += val[i]*ky[y + 1]*kx[x];
    histogram[y/8 + 1][x/8 + 1][idx[i]] += val[i]*ky[y + 1]*kx[x + 1];
}

size 的值取决于实现,但通常含义相同。

我知道histogram calculation with using of SIMD的问题没有简单有效的解决方案。但在这种情况下,我们有小尺寸(18)的直方图。它可以帮助 SIMD 优化吗?

【问题讨论】:

标签: c++ opencv simd dlib simd-library


【解决方案1】:

我找到了解决方案。它是一个时间缓冲区。首先,我们将直方图求和到临时缓冲区(并且此操作可以向量化)。然后我们将缓冲区的总和添加到输出直方图(这个操作也可以向量化):

float histogram[height/8][width/8][18];
float ky[height], kx[width];
int idx[size];
float val[size]; 
float buf[18][4];

for(size_t i = 0; i < size; ++i)
{
    buf[idx[i]][0] += val[i]*ky[y]*kx[x];
    buf[idx[i]][1] += val[i]*ky[y]*kx[x + 1];
    buf[idx[i]][2] += val[i]*ky[y + 1]*kx[x];
    buf[idx[i]][3] += val[i]*ky[y + 1]*kx[x + 1];
}

for(size_t i = 0; i < 18; ++i)
{
    histogram[y/8][x/8][i] += buf[i][0];
    histogram[y/8][x/8 + 1][i] += buf[i][1];
    histogram[y/8 + 1][x/8][i] += buf[i][2];
    histogram[y/8 + 1][x/8 + 1][i] += buf[i][3];
}

【讨论】:

    【解决方案2】:

    您可以通过使用 SIMD 计算所有(展平的)直方图索引和 bin 增量来进行部分优化。然后在标量循环中处理这些。您可能还想剥离它,以便一次处理一行,以便将临时 bin 索引和增量保留在缓存中。由于使用了临时中间缓冲区,这可能看起来效率低下,但在实践中,我在类似的情况下看到了有用的整体收益。

    uint32_t i = 0;
    
    for (y = 0; y < height; ++y)   // for each row
    {
        uint32_t inds[width * 4];  // flattened histogram indices for this row
        float vals[width * 4];     // histogram bin increments for this row
    
        // SIMD loop for this row - calculate flattened histogram indices and bin
        // increments (scalar code shown for reference - converting this loop to
        // SIMD is left as an exercise for the reader...)
    
        for (x = 0; x < width; ++x, ++i)
        {
            indices[4*x]   = (y/8)*(width/8)*18+(x/8)*18+idx[i];
            indices[4*x+1] = (y/8)*(width/8)*18+(x/8 + 1)*18+idx[i];
            indices[4*x+2] = (y/8+1)*(width/8)*18+(x/8)*18+idx[i];
            indices[4*x+3] = (y/8+1)*(width/8)*18+(x/8 + 1)*18+idx[i];
    
            vals[4*x]   = val[i]*ky[y]*kx[x];
            vals[4*x+1] = val[i]*ky[y]*kx[x+1];
            vals[4*x+2] = val[i]*ky[y+1]*kx[x];
            vals[4*x+3] = val[i]*ky[y+1]*kx[x+1];
        }
    
        // scalar loop for this row
    
        float * const histogram_base = &histogram[0][0][0]; // pointer to flattened histogram
    
        for (x = 0; x < width * 4; ++x) // for each set of 4 indices/increments in this row
        {
            histogram_base[indices[x]] += vals[x];  // update the (flattened) histogram
        }
    
    }
    

    【讨论】:

    • 谢谢。 Dlib 中有类似的优化。但最后他们使用标量在直方图中添加值。因此,您的解决方案与它根本没有区别。
    • 哦,好吧 - 我不熟悉 Dlib。我会把这个答案留在这里,以防它对将来寻找直方图优化想法的其他人有用。
    • 部分原因是我的错。因为我没有在我的问题中写下所有条件。谢谢你的好回答!
    猜你喜欢
    • 1970-01-01
    • 2014-09-18
    • 2019-05-29
    • 2020-12-05
    • 1970-01-01
    • 2012-11-08
    • 1970-01-01
    • 2012-06-07
    • 2015-08-17
    相关资源
    最近更新 更多