КУБЛАС - возможно ли возведение в степень матричных элементов? - PullRequest
5 голосов
/ 27 марта 2011

Я использую CUBLAS (библиотеки Cuda Blas) для матричных операций.

Можно ли использовать CUBLAS для достижения возведения в степень / среднеквадратичного значения элементов матрицы?

Я имею в виду, имея матрицу 2x2

1 4
9 16

То, что я хочу, это функция для повышения до заданного значения, например, 2

1 16
81 256

и вычисление среднеквадратичного значения, например

1 2
3 4

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

1 Ответ

9 голосов
/ 27 марта 2011

Так что это может быть то, что вы делаете должны реализовать сами, потому что библиотека не сделает это за вас.(Вероятно, есть какой-то способ реализовать это с точки зрения процедур уровня 3 BLAS - конечно, возведения в квадрат матричных элементов - но это потребовало бы дорогостоящих и в противном случае ненужных умножений матрицы на вектор. И я до сих пор не знаю, как вы »буду делать операцию квадратного корня).Причина в том, что эти операции на самом деле не являются процедурами линейной алгебры;получение квадратного корня каждого элемента матрицы на самом деле не соответствует какой-либо фундаментальной операции линейной алгебры.

Хорошая новость заключается в том, что эти поэлементные операции очень просто реализовать в CUDA.Опять же, есть много опций настройки, с которыми можно поиграть для достижения максимальной производительности, но можно начать довольно легко.

Как и в случае с операциями сложения матриц, здесь вы будете рассматривать матрицы NxM как (N *М) длина векторов;структура матрицы не имеет значения для этих поэлементных операций.Таким образом, вы будете передавать указатель на первый элемент матрицы и рассматривать его как единый список из N * M чисел.(Я предполагаю, что вы используете float s здесь, как вы говорили о SGEMM и SAXPY ранее.)

Ядро, фактический бит кода CUDA, который реализуетоперация довольно проста.На данный момент каждый поток будет вычислять квадрат (или квадратный корень) одного элемента массива.(Является ли это оптимальным или нет для производительности - это то, что вы можете проверить).Таким образом, ядра будут выглядеть следующим образом.Я предполагаю, что вы делаете что-то вроде B_ij = (A_ij) ^ 2;если вы хотите выполнить операцию на месте, например, A_ij = (A_ij) ^ 2, вы также можете сделать это:

__global__ void squareElements(float *a, float *b, int N) {
    /* which element does this compute? */
    int tid = blockDim.x * blockIdx.x + threadIdx.x;

    /* if valid, squre the array element */
    if (tid < N) 
            b[tid] = (a[tid]*a[tid]);
}

__global__ void sqrtElements(float *a, float *b, int N) {
    /* which element does this compute? */
    int tid = blockDim.x * blockIdx.x + threadIdx.x;

    /* if valid, sqrt the array element */
    if (tid < N) 
            b[tid] = sqrt(a[tid]);   /* or sqrtf() */
}

Обратите внимание, что если вы в порядке с очень незначительным увеличением ошибки, то 'sqrtf() 'функция с максимальной ошибкой в ​​3 ulp (единицы на последнем месте) значительно быстрее.

То, как вы будете называть эти ядра, будет зависеть от порядка, в котором вы делаете вещи.Если вы уже сделали несколько вызовов CUBLAS для этих матриц, вы можете использовать их для массивов, которые уже находятся в памяти GPU.

...