Галид с макетами C NumPy массивов

Я начинаю использовать Halide и использовать его из среды Python. В этой среде Python данные передаются в виде массивов Numpy, которые фактически являются псевдонимами для массива C++, определенного в другом месте.

Однако, когда я использую функцию Halide, я получаю ошибку:

Нарушено ограничение: img.stride.0 (520) == 1 (1)
Прервано (ядро сброшено)

которая может быть "решена" путем копирования пустых массивов в массивы компоновки Fortran:

img=np.copy(img,order="F")
res=np.copy(res,order="F")

с img и res мои входные и выходные изображения. Однако обратите внимание, что это включает в себя дополнительные операции копирования, что очень плохо для общего доступа к глобальной памяти.

Как я могу обойти эту проблему? Я подумал о том, чтобы на самом деле сказать Python, что мои массивы имеют разметку Fortran и правильно переключены индексы.... Однако в настоящее время я использую PyArray_SimpleNewFromData для получения массивов Python (без фактического копирования данных), и это приводит к Массивы в стиле C.

2 ответа

Решение

Проблема в том, что PyArray_SimpleNewFromData сделал из данных ndarray в стиле C, где в коде хоста C++ массивы выполнены в стиле Fortran. Решение состоит в том, чтобы преобразовать ndarrays сразу после их создания, что можно сделать с помощью следующего кода:

def swap(img):
    (sh1,sh2)=img.shape
    (st1,st2)=img.strides
    img.shape=(sh2,sh1)
    img.strides=(st2,st1)

После этого в Halide мы обычно можем векторизовать в нулевой (x) размерности.

Изначально Halide ожидает хранения на уровне строки, но индексирует такие вещи: im(col, row)... и это выглядит очень похоже на хранилище на уровне столбца для того, кто привык обрабатывать изображения как матрицы или использовать двумерные массивы в C.

Таким образом, вы можете изменить индексирование в соответствии с понятием Halide или сказать Halide, что ваш макет памяти работает наоборот (шаг (0) велик).

Здесь есть учебник, который охватывает тесно связанную тему: http://halide-lang.org/tutorials/tutorial_lesson_16_rgb_generate.html

Краткая версия для 2D входов и функций:

image_param.set_stride(0, Expr()).set_stride(1, 1);
output_func.output_buffer().set_stride(0, Expr()).set_stride(1, 1);

Первый вызов set_stride освобождает шаг в измерении 0, а второй сообщает Halide, что он может предполагать, что шаг в измерении 1 равен 1. Если вы сделаете это, вы захотите векторизовать ваши функции Halide во втором измерении, потому что это тот это плотно в памяти:

f(i, j) = ...
f.vectorize(j, 4)
Другие вопросы по тегам