Ошибка индекса Halide при использовании AutoScheduler и расписания графического процессора, но не по расписанию ЦП по умолчанию

Я использую генератор для создания статической библиотеки для моего модуля Halide. Я сравниваю расписание по умолчанию, AutoScheduler и расписание GPU, использующее простую мозаику. У меня есть два входа одинакового размера («источник» и «ссылка») и один выход.

Все работает нормально, пока я не запускаю ввод с размерами менее 64x64. Как AutoScheduled, так и запланированные версии GPU выдают эту ошибку на входе 63x63:

Error: Output buffer output is accessed at -1, which is before the min (0) in dimension 0.

По мере уменьшения размера ввода ошибочный индекс также уменьшается (например, 62x62 дает output is accessed at -2, 61x61 дает -3 и т. д.)

Я сбит с толку, потому что я не получаю эту ошибку, используя расписание по умолчанию, но каким-то образом делаю это с запланированными версиями auto и GPU. Я также не знаю, почему эта проблема возникает ниже размера 64x64. Кто-нибудь может помочь, пожалуйста? Как мне заставить его работать для ввода любого размера?

# include Halide.h
using namespace Halide;

class MyGenerator : public Halide::Generator<MyGenerator> {
public:

    // Input parameters
    Input <Buffer<uint8_t>> source{"src", 2};
    Input <Buffer<uint8_t>> reference{"ref", 2};
    Output <Buffer<uint8_t>> output{"output", 2};

    Input<int> radius{"radius"};

    void generate(){
        src_clamped = BoundaryConditions::constant_exterior(source, 0);
        ref_clamped = BoundaryConditions::constant_exterior(reference, 0);
        /* snipped for brevity; this part just shows I'm using padding
           and calculating output only at (x, y) */
        output(x, y) = ... ;
    }

    void schedule() {
        if (auto_schedule) {
            source.dim(0).set_estimate(0, 3000);
            source.dim(1).set_estimate(0, 4000);
            reference.dim(0).set_estimate(0, 3000);
            reference.dim(1).set_estimate(0, 4000);

            radius.set_estimate(5);

            output.set_estimate(x, 0, 3000);
            output.set_estimate(y, 0, 4000);
        } else {
            Var xo("xo"), yo("yo"), xi("xi"), yi("yi");
            if (get_target().has_gpu_feature()){
                std::cout << "Using GPU schedule\n";

                const int EXPECTED_RADIUS = 5;
                int kernel_w = EXPECTED_RADIUS * 2 + 1;
                output.gpu_tile(x, y, xo, yo, xi, yi, kernel_w, kernel_w);

            } else {
                std::cout << "Using CPU schedule\n";

            }
        }
    }
private:
    // create variables to index our location
    Var x{"x"}, y{"y"}, dx{"dx"}, dy{"dy"};

};


person Andrew Jong    schedule 28.01.2020    source источник


Ответы (1)


В Halide директивы планирования могут накладывать ограничения на размер входных данных. Например, если вы вычисляете что-то в тайлах 64x64, то (по умолчанию) это означает, что входные данные должны иметь размер не менее 64x64. Существуют различные способы избежать этого, если вы хотите, чтобы расписание также поддерживало очень маленькие входные данные. Один из способов — использовать команду Halide, чтобы она разработала специальное расписание для небольших входных данных, используя Func::specialize. Другой способ — использовать TailStrategy::GuardWithIf в качестве последнего аргумента для gpu_tile. Это генерирует маскирующий код внутри ядра графического процессора, поэтому он может быть немного медленнее для случаев размером больше 64x64. В обоих случаях для этого требуется дополнительный размер кода, что может быть или не быть хорошим компромиссом в зависимости от вашего варианта использования (поэтому это не происходит автоматически).

person Andrew Adams    schedule 29.01.2020
comment
Спасибо за понимание, Андрей. Почему ядро ​​графического процессора создает тайлы размером 64x64? В моем коде установлено значение kernel_w, что равно 11. Разве это не делает тайлы 11x11? - person Andrew Jong; 29.01.2020
comment
Не могли бы вы опубликовать пример кода? Я пробовал следующее, что не сработало: output.gpu_tile(x, y, xo, yo, xi, yi, 16, 16); output.specialize(source.width() < 64 || source.height() < 64).gpu_tile(x, y, xo, yo, xi, yi, 4, 4); - person Andrew Jong; 29.01.2020