2016-01-31 1 views
0

Я новичок в OpenCL, и у меня возникли проблемы с переносом головы вокруг обработки памяти и локальных рабочих групп.Как правильно спроектировать нормализацию вектора в opencl (размеры рабочей группы и ядра)

У меня есть четырехмерная структура данных, которая плавает [30] [100] [100] [2025]. В настоящее время я повторяю первые два измерения по нормали и передаю полученную матрицу 2025x100 в следующую функцию ЦП.

// num_columns = 100; num_rows = 2025 
for (int column = 0; column < num_cols; column++){ 
    vector = matrix[column]; 

    float min = vector[0]; 
    float max = vector[0]; 
    for (int i = 0; i < num_rows; i++){ 
     if(vector[i] < min){min = vector[i];} 
     if(vector[i] > max){max = vector[i];} 
    } 
    float diff = max-min + epsilon; 

    for(int i = 0; i < num_rows; i++){ 
     vector[i] = (vector[i]-min)/diff; //MULTI-THREAD HERE 
    } 

    float mean = 0; 
    for (int i = 0; i < num_rows; i++){ 
     mean += vector[i]; 
    } 
    mean = mean/num_rows; 

    for (int i = 0; i < num_rows; i++){ 
     vector[i] = vector[i]-mean + epsilon; //MULTI-THREAD HERE 
    } 

    float norm = 0; 
    for (int i = 0; i < num_rows; i++){ 
     norm += vector[i]*vector[i]; 
    } 
    norm = (float) sqrt(norm); 

    if (norm > 0){ 
     for (int i = 0; i < num_rows; i++){ 
      vector[i] = vector[i]/norm; //MULTI-THREAD HERE 
     } 
    } 
} 

Я прокомментировал, где, по-моему, я выиграю от использования OpenCL. Было бы дорого проходить через каждый столбец, записывать вектор буфера устройства, выполнять нормализацию, а затем читать его обратно на хост. Графический процессор (Adreno 330 на htc one m8) имеет память для одновременной буферизации всей матрицы 2025x100. Однако я должен сгладить его в 1d-массив с плавающей точкой, и я не знаю, как выполнять ядро ​​только на части буфера (одного вектора) за раз.

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

Редактирование: Я знаю, что есть встроенная функция CLnormalize, но у меня есть три различные функции нормализации, которые мне нужно реализовать, и я не знаю, будет ли кто-либо из них соответствовать встроенному. Я все же пытался проверить его, но я получил ошибку, что не нашел подходящей встроенной функции для нормализации (float * vector).

ответ

1

Вы можете легко распараллелить всю функцию на графическом процессоре, а не только те части, которые вы обозначили как «MULTI-THREAD HERE». В OpenCL ваши потоки/рабочие элементы делятся на локальные рабочие группы. В пределах одной рабочей группы потоки могут работать вместе, обмениваться данными с использованием локальной общей памяти и синхронизировать с использованием барьеров. Вы можете обрабатывать один столбец в каждой рабочей группе. Каждый столбец полностью независим, поэтому синхронизация между рабочими группами не требуется.

В каждой рабочей группе мы можем использовать каждый поток для обработки 4 или 8 элементов вектора. (Если вы будете обрабатывать только элемент на один рабочий элемент, ваша рабочая группа будет больше, чем максимальный размер рабочей группы). Трудная часть здесь заключается в том, как распараллелить вычисление max, min и суммы вектора: здесь мы можем использовать параллельное программирование примитивный, называемый «параллельной редукцией». Вот видео с хорошими слайдами, которые объясняют технику: https://www.youtube.com/watch?v=siHYfH1RQ_s

Вы можете использовать эту технику для суммирования вектора, минимума и максимума для вычисления минимума, максимума и среднего значения параллельно. Если вы будете делать все три одновременно, это будет даже немного быстрее, чем три отдельных сокращения, потому что вам нужно синхронизировать реже. Вы также можете использовать локальные переменные для хранения временных результатов вектора [i] и только считывать в векторе [i] один раз в начале и записывать обратно вектор [i] в ​​самом конце, когда все вычисления на векторе [i] выполнены , Это может сэкономить много памяти.