如何使用可变内核大小进行高性能AOT模糊?

时间:2017-06-19 10:49:25

标签: halide

这种类型的代码有效的单线程调度是什么? 我正在尝试定义模糊,但在AOT中使用可变内核大小。我尝试了https://github.com/halide/Halide/issues/180解决方案,但是我无法想出一个好的方法来安排它,这会让我获得与使用GeneratorParam并使用不同值编译内核大小相同的性能。

以下是GeneratorParam的代码段:

// GeneratorParam<int32_t> kernelSize{"kernelOffset", 1};
int32_t kernelSize = 2*kernelOffset + 1;
{
   Halide::Expr sum = input(x, y);
   for (int i=1;i<kernelSize;i++) {
      sum = sum + Halide::cast<uint16_t>(input(x, y+i));
   }
   blur_y(x, y) = sum/kernelSize;
}
{
   Halide::Expr sum = blur_y(x, y);
   for (int i=1;i<kernelSize;i++) {
      sum = sum + blur_y(x+i, y);
   }
   blur_x(x, y) = sum/kernelSize;
}

...

// And the schedule


blur_x.compute_root();
blur_y.compute_at(blur_x, y);
output.vectorize(x, 16);

并使用https://github.com/halide/Halide/issues/180解决方案

Halide::RDom box (0, kernelSize, "box");
blur_y(x, y) = Halide::undef<uint16_t>();
{
    Halide::RDom ry (yMin+1, yMax-yMin, "ry");
    blur_y(x, yMin) = Halide::cast<uint16_t>(0);
    blur_y(x, yMin) += Halide::cast<uint16_t>(input(x, yMin+box))/kernelSize;
    blur_y(x, ry) = blur_y(x, ry-1) + input_uint16(x, ry+kernelOffset-1)/kernelSize - input_uint16(x, ry-1-kernelOffset)/kernelSize;
}

blur_x(x, y) = Halide::undef<uint16_t>();
{
    Halide::RDom rx (xMin+1, xMax-xMin, "rx");
    blur_x(xMin, y) = Halide::cast<uint16_t>(0);
    blur_x(xMin, y) += blur_y(xMin+box, y)/kernelSize;
    blur_x(rx, y) = blur_x(rx-1, y) + blur_y(rx+kernelOffset, y)/kernelSize - blur_y(rx-1-kernelOffset, y)/kernelSize;
}

1 个答案:

答案 0 :(得分:2)

在固定半径和可变半径之间获得相同速度的唯一方法是使用specialize调度指令为特定半径生成固定代码。如果你可以JIT并且在相同的半径上模糊很多像素,那么对于给定半径的JIT特定滤波器可能是有利可图的。

通常非常快,任意半径,模糊使用自适应方法,其中大半径由迭代盒滤波处理,中间级别使用可分离卷积和非常小的半径可以使用不可分离卷积。模糊通常在结合多种方法的多次通过中完成。