Ошибка индексации при использовании AutoScheduler и GPU Schedule, но не по умолчанию для CPU - PullRequest
0 голосов
/ 29 января 2020

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

Все работает нормально, пока я не выполню вход с размерами менее 64x64. И для версий с автоматическим планированием, и для запланированных 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, et c.)

Я запутался, потому что я не получайте эту ошибку, используя расписание по умолчанию, но каким-то образом поступайте с запланированными версиями 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"};

};

1 Ответ

0 голосов
/ 29 января 2020

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

...