有人能提供示例代码来演示cuda中16位浮点的使用吗?

有人能提供示例代码来演示cuda中16位浮点的使用吗?,cuda,Cuda,Cuda 7.5支持16位浮点变量。 有人能提供示例代码来演示它的使用吗 有几件事需要事先注意: 参考半精度 请注意,大多数或所有这些内部函数仅在设备代码中受支持。(但是,@njuffa创建了一组主机可用的转换函数) 请注意,compute capability 5.2及以下版本的设备本机不支持半精度算法。这意味着任何要执行的算术运算都必须在某些支持的类型上执行,例如float。计算能力为5.3(目前为Tegra TX1)的设备和可能的未来设备将支持“本机”半精度算术运算,但这些运算目前通过\u

Cuda 7.5支持16位浮点变量。
有人能提供示例代码来演示它的使用吗

有几件事需要事先注意:

  • 参考半精度
  • 请注意,大多数或所有这些内部函数仅在设备代码中受支持。(但是,@njuffa创建了一组主机可用的转换函数)
  • 请注意,compute capability 5.2及以下版本的设备本机不支持半精度算法。这意味着任何要执行的算术运算都必须在某些支持的类型上执行,例如
    float
    。计算能力为5.3(目前为Tegra TX1)的设备和可能的未来设备将支持“本机”半精度算术运算,但这些运算目前通过
    \uuu hmul
    等内部函数公开。在不支持本机操作的设备中,类似于
    \uuuuhmul
    的内部代码将是未定义的
  • 您应该将
    cuda_fp16.h
    包含在任何文件中,以便在设备代码中使用这些类型和内部函数
  • 考虑到以上几点,下面是一个简单的代码,它获取一组
    浮点
    数量,将其转换为
    数量,并按比例因子进行缩放:

    $ cat t924.cu
    #include <stdio.h>
    #include <cuda_fp16.h>
    #define DSIZE 4
    #define SCF 0.5f
    #define nTPB 256
    __global__ void half_scale_kernel(float *din, float *dout, int dsize){
    
      int idx = threadIdx.x+blockDim.x*blockIdx.x;
      if (idx < dsize){
        half scf = __float2half(SCF);
        half kin = __float2half(din[idx]);
        half kout;
    #if __CUDA_ARCH__ >= 530
        kout = __hmul(kin, scf);
    #else
        kout = __float2half(__half2float(kin)*__half2float(scf));
    #endif
        dout[idx] = __half2float(kout);
        }
    }
    
    int main(){
    
      float *hin, *hout, *din, *dout;
      hin  = (float *)malloc(DSIZE*sizeof(float));
      hout = (float *)malloc(DSIZE*sizeof(float));
      for (int i = 0; i < DSIZE; i++) hin[i] = i;
      cudaMalloc(&din,  DSIZE*sizeof(float));
      cudaMalloc(&dout, DSIZE*sizeof(float));
      cudaMemcpy(din, hin, DSIZE*sizeof(float), cudaMemcpyHostToDevice);
      half_scale_kernel<<<(DSIZE+nTPB-1)/nTPB,nTPB>>>(din, dout, DSIZE);
      cudaMemcpy(hout, dout, DSIZE*sizeof(float), cudaMemcpyDeviceToHost);
      for (int i = 0; i < DSIZE; i++) printf("%f\n", hout[i]);
      return 0;
    }
    
    $ nvcc -o t924 t924.cu
    $ cuda-memcheck ./t924
    ========= CUDA-MEMCHECK
    0.000000
    0.500000
    1.000000
    1.500000
    ========= ERROR SUMMARY: 0 errors
    $
    
    $cat t924.cu
    #包括
    #包括
    #定义DSIZE 4
    #定义SCF 0.5f
    #定义nTPB 256
    __全局无效半刻度内核(float*din、float*dout、int-dsize){
    int idx=threadIdx.x+blockDim.x*blockIdx.x;
    if(idx=530
    kout=uuhmul(亲属,scf);
    #否则
    kout=uuuu2float2half(uuu2float(kin)*uu2float(scf));
    #恩迪夫
    dout[idx]=\uuuu2半浮(kout);
    }
    }
    int main(){
    浮动*欣、*霍特、*丁、*杜特;
    hin=(浮动*)malloc(DSIZE*sizeof(浮动));
    hout=(float*)malloc(DSIZE*sizeof(float));
    对于(inti=0;i
    如果您研究上述代码,您会注意到,除了cc5.3和更高版本的设备外,该算法是作为常规的
    浮点操作进行的。这与上文注3一致

    收获如下:

  • 在cc5.2及以下的设备上,
    half
    数据类型可能仍然有用,但主要是作为存储优化(以及相关的内存带宽优化,因为例如,给定的128位向量负载可以一次加载8
    half
    数量)。例如,如果您有一个大型神经网络,并且您已经确定权重可以作为半精度量存储(从而使存储密度增加一倍,或者使可在GPU存储空间中表示的神经网络的大小大约增加一倍),然后可以将神经网络权重存储为半精度。然后,当您需要执行向前传球(推断)或向后传球(训练)时,您可以从内存中加载权重,动态地(使用内部函数)将它们转换为
    float
    数量,执行必要的操作(可能包括因训练而调整权重),然后(如有必要)将重量再次存储为
    数量的一半
  • 对于cc5.3和未来的设备,如果算法允许,则可以执行与上述类似的操作,但无需转换为
    浮点
    (或者返回到
    half
    ),而是将所有数据保留在
    half
    表示中,并直接执行必要的算法(例如使用
    \uu hmul
    \uu hadd
    内部函数)
  • 虽然我没有在这里演示,但是
    half
    数据类型在主机代码中是“可用”的。我的意思是,您可以为该类型的项分配存储,并对其执行例如
    cudaMemcpy
    操作。但是主机代码对
    half
    数据类型一无所知(例如,如何对其进行算术运算、打印或进行类型转换)并且内部函数在主机代码中不可用。因此,如果需要,您当然可以为大量
    half
    数据类型分配存储(可能存储一组神经网络权重),但您只能通过设备代码而不是主机代码轻松地直接操作该数据

    还有几点意见:

  • CUBLAS库设计用于直接处理
    一半
    数据。上面的描述应该可以让我们了解不同设备类型(即计算能力)的“机箱下”可能发生的情况

  • 有关在推力中使用
    half
    的相关问题如下


  • 有几件事需要提前注意:

  • 参考半精度
  • 请注意,大多数或所有这些内部函数仅在设备代码中受支持。(但是,@njuffa创建了一组主机可用的转换函数)
  • 请注意,计算能力为5.2及以下的设备本机不支持半精度算术。这意味着任何要执行的算术运算都必须在某些支持的类型上完成,例如
    float
    。计算能力为5.3(当前为Tegra TX1)的设备和可能的未来设备将支持“本机”半精度算术运算,但这些运算目前是通过诸如
    \uuuuhmul
    之类的内部函数公开的