在BLAS中添加标量向量(cuBLAS / CUDA)

时间:2012-12-27 07:31:01

标签: c cuda add blas cublas

我不知道我是否只是忽略了一些显而易见的东西,但是尽管我在谷歌周围进行搜索,但我认为没有办法简单地使用BLAS操作将一个标量添加到矢量(或矩阵)。我试图在cuBLAS / CUDA中这样做,所以我将采取任何方式在该框架内完成此任务。 BLAS对于标量乘法(<t>scal)有cublas<t>scal但是在哪里是加法的模拟?!即与GSL gsl_vector_add_constant类似的东西。我错过了什么?

2 个答案:

答案 0 :(得分:3)

执行所要求的唯一方法可能就是将axpy与您想要添加的常量缩放的相同大小的单位向量应用。

因此操作变为X <- X + alpha * I,这相当于将alpha添加到X中的每个条目。


编辑:

从评论中,您似乎预见到为SAXPY调用创建单位向量会有一些困难。一种方法是使用memset调用在设备上设置单位向量的值,如下所示:

#include "cuda.h"
#include "cuda_runtime_api.h"
#include "cublas_v2.h"
#include <iostream>

int main(void)
{

    const int N = 10;
    const size_t sz = sizeof(float) * size_t(N);
    float *A, *I;

    float Ah[N] = { 0., 1., 2., 3., 4., 5., 6., 7., 8., 9. };

    cudaMalloc((void **)&A, sz);
    cudaMemcpy(A, &Ah[0], sz, cudaMemcpyHostToDevice);

    // this creates a bit pattern for a single precision unity value
    // and uses 32-bit memset from the driver API to set the values in the
    // vector.
    const float one = 1.0f;
    const int* one_bits = reinterpret_cast<const int*>(&one);
    cudaMalloc((void **)&I, sz);
    cuMemsetD32(CUdeviceptr(I), *one_bits, N);

    cublasHandle_t h;
    cublasCreate(&h);

    const float alpha = 5.0f;
    cublasSaxpy(h, N, &alpha, I, 1, A, 1);

    cudaMemcpy(&Ah[0], A, sz, cudaMemcpyDeviceToHost);

    for(int i=0; i<N; i++) {
        std::cout << i << " " << Ah[i] << std::endl;
    }

    cublasDestroy(h);
    cudaDeviceReset();

    return 0;
}

请注意,我已经直接使用CUDA运行时API为CUBLAS向量分配和复制了内存,而不是使用CUBLAS助手函数(它们只是围绕运行时API调用的非常薄的包装器)。 “棘手”部分是制作一个位模式,并使用驱动程序API memset函数来设置数组的每个32位字。

你可以使用推力库中的几行模板代码完成整个过程,或者只编写自己的内核,这可能就像

一样简单。
template<typename T>
__global__
void vector_add_constant( T * vector, const T scalar, int N)
{
    int tidx = threadIdx.x + blockIdx.x*blockDim.x;
    int stride = blockDim.x * gridDim.x;

    for(; tidx < N; tidx += stride) {
        vector[tidx] += scalar;
    }
}

[免责声明:此内核是在浏览器中编写的,未经测试。使用自己的风险]

答案 1 :(得分:2)

四个选项,从最佳到最差排名:

  • 在不同的库中找到所需的功能
  • 实现您自己需要的功能
  • 分配并初始化常量向量,将其与*axpy一起使用。
  • 虽然BLAS正式不支持零步,但是某些实现将带有步幅0的向量视为您想要的“标量”。也许cuBLAS会。但是,取决于这是一个非常糟糕的主意(非常糟糕,以至于我强烈考虑不提及它),因为这种行为不受BLAS的支持;您的代码将无法移植,甚至可能被库的未来版本破坏,除非nvidia提供比BLAS更强的API保证。
相关问题