Как сделать производительное размытие AOT с переменным размером ядра?

Каким было бы эффективное однопоточное планирование для этого типа кода? Я пытаюсь определить размытие, но с переменным размером ядра в 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;
}

person Fran6co    schedule 19.06.2017    source источник
comment
можете ли вы написать, какое расписание вы пробовали и какова была его скорость выполнения по сравнению с отсутствием явного планирования?   -  person Ruppesh Nalwaya    schedule 20.06.2017
comment
Версия с фиксированным размером ядра работает со скоростью 6,56348e-05 с без расписания и 1,97556e-05 с с указанным расписанием. Версия с переменным ядром работает со скоростью 1,10882 с без расписания и 0,0026933 с с тем же расписанием, что и другая.   -  person Fran6co    schedule 21.06.2017


Ответы (1)


Единственный способ получить одинаковую скорость между фиксированным и переменным радиусом — это использовать директиву specialize scheduling для создания фиксированного кода для определенных радиусов. Если вы можете использовать JIT и размываете много пикселей с одинаковыми радиусами, может быть выгодно использовать JIT для определенного фильтра для заданного радиуса.

Как правило, очень быстрое размытие произвольного радиуса использует адаптивные подходы, в которых большие радиусы обрабатываются чем-то вроде итеративной блочной фильтрации, промежуточные уровни используют разделяемую свертку, а очень маленькие радиусы могут использовать неразделимую свертку. Размытие часто выполняется за несколько проходов, сочетающих несколько подходов.

person Zalman Stern    schedule 28.06.2017