Сумма параллельных блоков ArrayFire

Что я хочу сделать, так это: у меня есть «расширенный» массив в первом измерении (строки). Например, у меня есть изображение из 1080 строк и 1920 столбцов. Этот расширенный массив состоит из (8*1080) строк и 1920 столбцов, 8 означает размер «блока строк». Что я хочу сделать, так это создать новый массив размером 8x1. Этот новый массив будет содержать сумму каждого блока в i-м (i = от 0 до 7).

В приведенном выше примере первый элемент нового массива (i=0) будет суммой этих пикселей в расширенном массиве (линейные индексы по столбцам):

0, 8 (потому что 8 - ПЕРВЫЙ элемент второго блока), 16 (третий блок).....

другой пример - второй элемент:

1, 9, 17,...

Я думаю, это можно распараллелить? Я пытаюсь решить эту проблему, но не могу, я пробовал gfor, но не смог найти способ сделать это, разве это невозможно с помощью arrayfire? любая помощь приветствуется!

Я пробовал использовать gfor, но не смог решить проблему.

Вот код, который я пробовал: rx — это массив 8x1 (p_squared_1 = 8), а rx_all — расширенный (p_squared*rows, columns) массив. Примечание. Я использую оператор seq "+", потому что если я попытаюсь написать "i+p_squared_1", возникнет двусмысленность, я думаю... это ошибка с моей стороны, но я не смог найти другого способа добавить значение к объект последовательности).

af::array rx(p_squared_1, 1);
gfor(af::seq i, rows*cols*(p_squared_1-1)) {
    rx(i) = af::sum<float>(rx_all(i.operator+( (const int)p_squared_1)));
}
af::eval(rx);
cout << af::sum<float>(rx);

Я ожидаю получить массив 8x1, где каждый i-й элемент является суммой i-го элемента каждого блока в расширенном массиве.


person eikonoules    schedule 25.06.2019    source источник


Ответы (1)


Я думаю, вы можете добиться этого, выполнив af::moddims и af::sum.

array img_expanded(1080*8, 1920);

array img_expanded_reshaped = moddims(img_expanded, 8, 1920*1080);
array result = sum(img_expanded_reshaped, 1);

Вызов moddims преобразует массив в массив 8x(1920*1080), после чего выполняется суммирование по второму измерению.

Оптимизированный макет

Вы могли бы получить лучшую производительность, если бы рассматривали сторону 1920 как ведущее измерение. Это не только будет соответствовать макету изображения в памяти ЦП и позволит избежать транспонирования при передаче в ГП и из ГП, но и измененный массив будет иметь большее первое измерение, поэтому он будет лучше использовать ГП.

array img_expanded(1920, 1080*8);

array img_expanded_reshaped = moddims(img_expanded, 1920*1080, 8);
array result = sum(img_expanded_reshaped, 0);

Это потребует от вас рефакторинга не только этой части кода.

person Umar Arshad    schedule 25.06.2019
comment
большое спасибо, очень помогло, не догадался сделать с моддимами, очень удобная функция. - person eikonoules; 25.06.2019
comment
один вопрос, возможно ли, что приведенный выше код не будет суммироваться со 100% точностью? Общая сумма верна, но каждая из 8 сумм немного отличается, поэтому я не думаю, что речь идет о точности и правильности (я использую числа с плавающей запятой, но десятичной части вообще нет, числа вроде 1268,0, 650,0 и т. д.) - person eikonoules; 25.06.2019
comment
Всегда будут ошибки округления при операциях с плавающей запятой. Поскольку порядок, в котором операции выполняются на графическом процессоре, не определен, значения будут немного отличаться. Проверьте тип af::array, который выполняет суммирование. Он может работать с целочисленными значениями, а затем они преобразуются в числа с плавающей запятой. Функция печати также может усекать значения. - person Umar Arshad; 26.06.2019
comment
ок спасибо за разъяснение! У меня есть еще один вопрос относительно конструкции gfor, могу ли я создать новый пост? - person eikonoules; 27.06.2019
comment
Такие вопросы лучше решать на нашем слабом канале. join.slack.com/t/arrayfire-org/shared_invite/ - person Umar Arshad; 28.06.2019