【问题标题】:cuda function application elementwise in cudacuda中的cuda函数应用程序元素
【发布时间】:2015-10-06 03:39:40
【问题描述】:

在将矩阵 A 和向量 x 相乘得到结果 y 后,我想将函数 h 逐元素应用于 y。

我想获得 z = h(Ax),其中 h 按元素应用于向量 Ax。

我知道如何在 GPU 上进行矩阵/向量乘法(使用 cublas)。现在我希望 h(这是我自己的函数,用 C++ 编码)也应用于 GPU 中的结果向量,我该怎么做?

【问题讨论】:

    标签: cuda


    【解决方案1】:

    两种可能的方法是:

    1. 编写自己的 CUDA 内核来执行操作
    2. 使用thrust(例如thrust::for_each())。

    以下是这两种方法的一个有效示例:

    $ cat t934.cu
    #include <iostream>
    #include <thrust/host_vector.h>
    #include <thrust/device_vector.h>
    #include <thrust/copy.h>
    #include <thrust/for_each.h>
    
    #define DSIZE 4
    
    #define nTPB 256
    
    template <typename T>
    __host__ __device__ T myfunc(T &d){
    
      return d + 5;  // define your own function here
    }
    
    struct mytfunc
    {
    template <typename T>
    __host__ __device__
     void operator()(T &d){
    
      d = myfunc(d);
      }
    };
    
    template <typename T>
    __global__ void mykernel(T *dvec, size_t dsize){
    
      int idx = threadIdx.x+blockDim.x*blockIdx.x;
      if (idx < dsize) dvec[idx] = myfunc(dvec[idx]);
    }
    
    int main(){
    
      // first using kernel
      float *h_data, *d_data;
      h_data = new float[DSIZE];
      cudaMalloc(&d_data, DSIZE*sizeof(float));
      for (int i = 0; i < DSIZE; i++) h_data[i] = i;
      cudaMemcpy(d_data, h_data, DSIZE*sizeof(float), cudaMemcpyHostToDevice);
      mykernel<<<(DSIZE+nTPB-1)/nTPB,nTPB>>>(d_data, DSIZE);
      cudaMemcpy(h_data, d_data, DSIZE*sizeof(float), cudaMemcpyDeviceToHost);
      for (int i = 0; i < DSIZE; i++) std::cout << h_data[i] << ",";
      std::cout << std::endl;
    
      // then using thrust
      thrust::host_vector<float>   hvec(h_data, h_data+DSIZE);
      thrust::device_vector<float> dvec = hvec;
      thrust::for_each(dvec.begin(), dvec.end(), mytfunc());
      thrust::copy_n(dvec.begin(), DSIZE, std::ostream_iterator<float>(std::cout, ","));
      std::cout << std::endl;
    }
    
    $ nvcc -o t934 t934.cu
    $ ./t934
    5,6,7,8,
    10,11,12,13,
    $
    

    请注意,为了提供一个完整的示例,我从主机内存中的向量定义开始。如果您已经在设备内存中有向量(可能是计算 y=Ax 的结果),那么您可以直接处理它,通过将该向量传递给 CUDA 内核,或直接在推力函数中使用它,使用 @987654324 @wrapper(这个方法在之前链接的thrust快速入门指南中有介绍。)

    我在这里所做的假设是您想使用一个变量的任意函数。这应该可以处理myfunc 中定义的几乎任意函数。但是,对于您可能感兴趣的某些类别的函数,您也可以通过一个或多个 CUBLAS 调用来实现它。

    【讨论】:

    • 非常感谢罗伯特。随后的两个问题:这两种方法在效率上是否存在差异(就执行速度而言,其中一种方法更可取)?并且推力用g ++编译,还是需要在.cu文件中并由nvcc编译。确实,即使是推力介绍的简单示例也无法使用 g++ (cuda 7.0.0) 为我编译
    • Thrust,针对CUDA后端时,需要用nvcc编译,你应该把这些thrust代码放在一个.cu文件中。对于我所展示的示例,两种方法之间的效率不会有太大差异。该算法将以内存访问为主,这两种方法都是一样的。
    • 谢谢罗伯特。如果我再次打扰你,比如说我的同样的问题,我想计算 y=h(A*x) 并且我必须为许多向量 x 计算它,而不改变矩阵 A,也不改变函数 h。您能否确认,一旦矩阵 A 被创建,它将在具有不同 x 数组的不同内核调用之间持续存在于 GPU 内存中?
    • 是的,它将持续存在,假设 A 矩阵在全局内存中。
    猜你喜欢
    • 2015-09-15
    • 2018-11-06
    • 2021-12-24
    • 2017-11-10
    • 1970-01-01
    • 2021-06-18
    • 2016-03-08
    • 2019-01-06
    相关资源
    最近更新 更多