Halide Jit, подборка

Я пытаюсь скомпилировать свою галоидную программу для jit, чтобы использовать ее позже в коде несколько раз на разных изображениях. Но я думаю, что делаю что-то не так, кто-нибудь может меня поправить? Сначала я создаю галоидную функцию для запуска:

void m_gammaFunctionTMOGenerate()
{
    Halide::ImageParam img(Halide::type_of<float>(), 3);
    img.set_stride(0, 4);
    img.set_stride(2, 1);
    Halide::Var x, y, c;
    Halide::Param<float> key, sat, clampMax, clampMin;
    Halide::Param<bool> cS;
    Halide::Func gamma;
    // algorytm
    //img.width() , img.height();
    if (cS.get())
    {
        float k1 = 1.6774;
        float k2 = 0.9925;
        sat.set((1 + k1) * pow(key.get(), k2) / (1 + k1 * pow(key.get(), k2)));
    }
    Halide::Expr luminance = img(x, y, 0) * 0.072186f + img(x, y, 1) * 0.715158f + img(x, y, 2) *  0.212656f;
    Halide::Expr ldr_lum = (luminance - clampMin) / (clampMax - clampMin);
    Halide::clamp(ldr_lum, 0.f, 1.f);
    ldr_lum = Halide::pow(ldr_lum, key);
    Halide::Expr imLum = img(x, y, c) / luminance;
    imLum = Halide::pow(imLum, sat) * ldr_lum;
    Halide::clamp(imLum, 0.f, 1.f);
    gamma(x, y, c) = imLum;
    // rozkład
    gamma.vectorize(x, 16).parallel(y);

    // kompilacja
    auto & obuff = gamma.output_buffer();
    obuff.set_stride(0, 4);
    obuff.set_stride(2, 1);
    obuff.set_extent(2, 3);
    std::vector<Halide::Argument> arguments = { img, key, sat, clampMax, clampMin, cS };
    m_gammaFunction = (gammafunction)(gamma.compile_jit());

}

сохранить его в указателе:

typedef int(*gammafunction)(buffer_t*, float, float, float, float, bool, buffer_t*);
gammafunction m_gammaFunction;

затем я пытаюсь запустить его:

buffer_t  output_buf = { 0 };
//// The host pointers point to the start of the image data:
buffer_t buf = { 0 };
buf.host = (uint8_t *)data; // Might also need const_cast
float * output = new float[width * height * 4];
output_buf.host = (uint8_t*)(output);
//                                // If the buffer doesn't start at (0, 0), then assign mins
output_buf.extent[0] = buf.extent[0] = width; // In elements, not bytes
output_buf.extent[1] = buf.extent[1] = height; // In elements, not bytes
output_buf.extent[2] = buf.extent[2] = 4;    // Assuming RGBA
//                 // No need to assign additional extents as they were init'ed to zero above
output_buf.stride[0] = buf.stride[0] = 4; // RGBA interleaved
output_buf.stride[1] = buf.stride[1] = width * 4; // Assuming no line padding
output_buf.stride[2] = buf.stride[2] = 1; // Channel interleaved
output_buf.elem_size = buf.elem_size = sizeof(float);

// Run the pipeline
int error = m_photoFunction(&buf, params[0], &output_buf);

Но это не работает... Ошибка:

Exception thrown at 0x000002974F552DE0 in Viewer.exe: 0xC0000005: Access violation executing location 0x000002974F552DE0.

If there is a handler for this exception, the program may be safely continued.

Редактировать:

Вот мой код для запуска функции:

buffer_t  output_buf = { 0 };
//// The host pointers point to the start of the image data:
buffer_t buf = { 0 };
buf.host = (uint8_t *)data; // Might also need const_cast
float * output = new float[width * height * 4];
output_buf.host = (uint8_t*)(output);
//                                // If the buffer doesn't start at (0, 0), then assign mins
output_buf.extent[0] = buf.extent[0] = width; // In elements, not bytes
output_buf.extent[1] = buf.extent[1] = height; // In elements, not bytes
output_buf.extent[2] = buf.extent[2] = 3;    // Assuming RGBA
                                             //                // No need to assign additional extents as they were init'ed to zero above
output_buf.stride[0] = buf.stride[0] = 4; // RGBA interleaved
output_buf.stride[1] = buf.stride[1] = width * 4; // Assuming no line padding
output_buf.stride[2] = buf.stride[2] = 1; // Channel interleaved
output_buf.elem_size = buf.elem_size = sizeof(float);

// Run the pipeline
int error = m_gammaFunction(&buf, params[0], params[1], params[2], params[3], params[4] > 0.5 ? true : false, &output_buf);

if (error) {
    printf("Halide returned an error: %d\n", error);
    return -1;
}

memcpy(output, data, size * sizeof(float));

может ли кто-нибудь помочь мне с этим?

Изменить:

Благодаря @KhouriGiordano я понял, что делаю неправильно. Действительно, я переключился с компиляции AOT на этот код. Итак, теперь мой код выглядит так:

class GammaOperator
{
public:
    GammaOperator();

    int realize(buffer_t * input, float params[], buffer_t * output, int width);
private:

    HalideFloat m_key;
    HalideFloat m_sat;
    HalideFloat m_clampMax;
    HalideFloat m_clampMin;
    HalideBool  m_cS;

    Halide::ImageParam m_img;
    Halide::Var x, y, c;
    Halide::Func m_gamma;
};


GammaOperator::GammaOperator()
    : m_img( Halide::type_of<float>(), 3)
{

    Halide::Expr w = (1.f + 1.6774f) * pow(m_key.get(), 0.9925f) / (1.f + 1.6774f * pow(m_key.get(), 0.9925f));
    Halide::Expr sat = Halide::select(m_cS, m_sat, w);

    Halide::Expr luminance = m_img(x, y, 0) * 0.072186f + m_img(x, y, 1) * 0.715158f + m_img(x, y, 2) *  0.212656f;
    Halide::Expr ldr_lum = (luminance - m_clampMin) / (m_clampMax - m_clampMin);
    ldr_lum = Halide::clamp(ldr_lum, 0.f, 1.f);
    ldr_lum = Halide::pow(ldr_lum, m_key);
    Halide::Expr imLum = m_img(x, y, c) / luminance;
    imLum = Halide::pow(imLum, sat) * ldr_lum;
    imLum = Halide::clamp(imLum, 0.f, 1.f);
    m_gamma(x, y, c) = imLum;

}

int GammaOperator::realize(buffer_t * input, float params[], buffer_t * output, int width)
{
    m_img.set(Halide::Buffer(Halide::type_of<float>(), input));
    m_img.set_stride(0, 4);
    m_img.set_stride(1, width * 4);
    m_img.set_stride(2, 4);
    // algorytm
    m_gamma.vectorize(x, 16).parallel(y);

    //params[0], params[1], params[2], params[3], params[4] > 0.5 ? true : false
    //{ img, key, sat, clampMax, clampMin, cS };
    m_key.set(params[0]);
    m_sat.set(params[1]);
    m_clampMax.set(params[2]);
    m_clampMin.set(params[3]);
    m_cS.set(params[4] > 0.5f ? true : false);
    //// kompilacja
    m_gamma.realize(Halide::Buffer(Halide::type_of<float>(), output));
    return 0;
}

и я использую это так:

buffer_t  output_buf = { 0 };
    //// The host pointers point to the start of the image data:
    buffer_t buf = { 0 };
    buf.host = (uint8_t *)data; // Might also need const_cast
    float * output = new float[width * height * 4];
    output_buf.host = (uint8_t*)(output);
    //                                // If the buffer doesn't start at (0, 0), then assign mins
    output_buf.extent[0] = buf.extent[0] = width; // In elements, not bytes
    output_buf.extent[1] = buf.extent[1] = height; // In elements, not bytes
    output_buf.extent[2] = buf.extent[2] = 4;    // Assuming RGBA
                                                 //                // No need to assign additional extents as they were init'ed to zero above
    output_buf.stride[0] = buf.stride[0] = 4; // RGBA interleaved
    output_buf.stride[1] = buf.stride[1] = width * 4; // Assuming no line padding
    output_buf.stride[2] = buf.stride[2] = 1; // Channel interleaved
    output_buf.elem_size = buf.elem_size = sizeof(float);

    // Run the pipeline

    int error = s_gamma->realize(&buf, params, &output_buf, width);

но все еще происходит сбой в функции m_gamma.realize с информацией в консоли:

Error: Constraint violated: f0.stride.0 (4) == 1 (1)

person Marcin Kołodziejski    schedule 22.08.2016    source источник
comment
Все ImageParam начинаются с неявного set_stride(0,1). Функции-члены set_min(), set_extent() и set_stride() — это ограничения, которым должен соответствовать любой передаваемый буфер. Это позволяет при генерации кода жестко закодировать эти значения. Используйте set_stride(0,4), чтобы соответствовать тому, что вы делаете, или set_stride(0,Expr()), чтобы снять ограничение.   -  person Khouri Giordano    schedule 24.08.2016
comment
Кроме того, поскольку заданные вами минимальные значения, экстент и шаг равны Expr, они могут зависеть от Param значений, таких как ширина и высота.   -  person Khouri Giordano    schedule 24.08.2016
comment
Он у меня уже есть: ' m_img.set_stride(0, 4);' и это не работает, я думаю...   -  person Marcin Kołodziejski    schedule 24.08.2016
comment
У вас есть m_img.set_stride(2, 4), который должен быть равен 1. Выходные данные также имеют ограничения. Используйте m_gamma.output_buffer() .set_extent(...) .set_stride(...).   -  person Khouri Giordano    schedule 25.08.2016
comment
Хорошо, теперь я это прекрасно понимаю. Я устанавливаю экстент и шаг изображения и output_buffer, и это работает. Однако мой процесс обработки изображений пошел не так. Все изображение обрабатывается так, как будто оно будет иметь только один цветовой канал. А в выходном буфере все каналы получили одно значение. Я поставил так: m_img.set_stride(0, 4); m_img.set_stride(1, width * 4); m_img.set_stride(2, 1); m_img.set_extent(0, width); m_img.set_extent(1, height); m_img.set_extent(2, 4); m_gamma.output_buffer().set_stride(0, 4); m_gamma.output_buffer().set_stride(1, width * 4); m_gamma.output_buffer().set_stride(2, 1);   -  person Marcin Kołodziejski    schedule 27.08.2016
comment
Я уже потерял представление о том, как выглядит ваш код. Присоединяйтесь ко мне в чате, и вы сможете опубликовать свой код на pastebin.com.   -  person Khouri Giordano    schedule 29.08.2016


Ответы (1)


Используя Halide::Param::get(), вы извлекаете значение (по умолчанию 0) из объекта Param во время вызова get(). Если вы хотите использовать значение параметра, заданное во время вызова сгенерированной функции, просто используйте его без вызова get, и оно должно быть неявно преобразовано в Expr.

Поскольку Param не может быть преобразовано в логическое значение, способ Halide сделать if - это Halide::select().

Вы не используете фиксированное возвращаемое значение Halide::clamp().

Я не вижу, чтобы cS использовался кодом Halide, только код C.

Теперь к вашей проблеме с JIT. Похоже, вы начали компиляцию AOT и перешли на JIT.

Вы делаете std::vector<Halide::Argument>, но никуда его не передаете. Откуда Halide может знать, какой Param вы хотите использовать? Он просматривает Func и находит ссылки на объекты ImageParam и Param.

Откуда вы знаете, в каком порядке он ожидает Param? У вас нет контроля над этим. Я смог сбросить биткод, определив HL_GENBITCODE=1, а затем просмотреть его с помощью llvm-dis, чтобы увидеть вашу функцию:

int gamma
    ( buffer_t *img
    , float clampMax
    , float key
    , float clampMin
    , float sat
    , void *user_context
    , buffer_t *result
    );
  • Используйте gamma.realize(Halide::Buffer(Halide::type_of<float>(), &output_buf)) вместо gamma.compile_jit() и попытайтесь правильно вызвать сгенерированную функцию.

Для одноразового использования:

  • Используйте Image вместо ImageParam.
  • Используйте Expr вместо Param.

Для многократного использования с одной компиляцией JIT:

  • Держите ImageParam и Param под рукой и установите их, прежде чем реализовать Func.
person Khouri Giordano    schedule 22.08.2016
comment
Да, извините, я вставил неверный код во второй, я отредактирую первый пост с правильным - person Marcin Kołodziejski; 23.08.2016