Так что это вполне может быть что-то, что вам нужно реализовать самостоятельно, потому что библиотека не сделает этого за вас. (Вероятно, есть какой-то способ реализовать некоторые из них в терминах процедур уровня 3 BLAS - конечно, возведение элементов матрицы в квадрат - но это потребует дорогостоящих и ненужных в других отношениях умножений матрицы на вектор. И я до сих пор не знаю, как вы » d выполнить операцию квадратного корня). Причина в том, что эти операции на самом деле не являются процедурами линейной алгебры; извлечение квадратного корня из каждого матричного элемента на самом деле не соответствует какой-либо фундаментальной операции линейной алгебры.
Хорошая новость в том, что эти поэлементные операции очень просто реализовать в CUDA. Опять же, есть много вариантов настройки, с которыми можно поиграть для лучшей производительности, но начать можно довольно легко.
Как и в случае с операциями сложения матриц, здесь вы будете обрабатывать матрицы NxM как векторы длины (N * M); структура матрицы не имеет значения для этих поэлементных операций. Таким образом, вы передадите указатель на первый элемент матрицы и будете рассматривать его как единый список из 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.
person
Jonathan Dursi
schedule
27.03.2011