Cublas - Колонка / Строка мудрых операций - PullRequest
0 голосов
/ 30 августа 2018

Я ищу способ выполнения операций над столбцами. У меня есть матрица MxN, я хочу активировать функцию cublas (например, nrm2) для каждого столбца.

Результат, который я ожидаю получить: M x 1

Как я могу это сделать?

1 Ответ

0 голосов
/ 30 августа 2018

В CUBLAS нет пакетных подпрограмм уровня 1, поэтому прямого способа вычисления норм столбцов или строк в одном вызове нет. Вы можете сделать это, многократно вызывая nrm2 в цикле по всем строкам или столбцам матрицы, например:

#include <cublas_v2.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/transform.h>
#include <thrust/random.h>
#include <thrust/device_vector.h>
#include <iostream>

struct prg
{
    float a, b;

    __host__ __device__
    prg(float _a=0.f, float _b=1.f) : a(_a), b(_b) {};

    __host__ __device__
        float operator()(const unsigned int n) const
        {
            thrust::default_random_engine rng;
            thrust::uniform_real_distribution<float> dist(a, b);
            rng.discard(n);

            return dist(rng);
        }
};


int main(void)
{
    const int M = 1024, N = M;
    const int num = N * M;

    thrust::device_vector<float> matrix(num);
    thrust::device_vector<float> vector(N, -1.0f);
    thrust::counting_iterator<unsigned int> index_sequence_begin(0);

    thrust::transform(index_sequence_begin,
            index_sequence_begin + num,
            matrix.begin(),
            prg(1.f,2.f));

    float* m_d = thrust::raw_pointer_cast(matrix.data());
    float* v_d = thrust::raw_pointer_cast(vector.data());

    cudaStream_t stream; 
    cudaStreamCreate(&stream);

    cublasHandle_t handle;
    cublasCreate(&handle);
    cublasSetPointerMode(handle, CUBLAS_POINTER_MODE_DEVICE);
    cublasSetStream(handle, stream);

    for(int col=0; col < N; col++) {
        cublasSnrm2(handle, M, m_d + col*M, 1, v_d + col);
    }
    cudaDeviceSynchronize();

    for(auto x : vector) {
        float normval = x;
        std::cout << normval << std::endl;
    }

    return 0;
}

Если у вас нет очень больших строк или столбцов, мало возможностей использовать потоки для одновременного запуска ядер и сокращения общего времени выполнения, поскольку каждый вызов nrm2 будет слишком коротким. Так что при запуске большого количества отдельных ядер существует большая задержка, что отрицательно влияет на производительность.

Гораздо лучшая альтернатива - написать собственное ядро, чтобы сделать это.

...