产品中心

联系我们

  


GPU计算的优势与应用

发布人: Srcsh 日期:2018-11-18 浏览:300人次

1.  GPU计算的优势

     复杂的人工智能算法训练与计算经常涉及上亿的参数,这些参数的计算需要大量的计算能力,目前在深度学习领域,GPU计算已经成为主流,使用GPU运算的优势如下:

目前,主流的GPU具有强大的计算能力和内存带宽,如下图所示,无论性能还是内存带宽,均远大于同代的CPU。 同时,GPU的thousands of cores的并行计算能力也是一大优势。

      理解 GPU 和 CPU 之间区别的一种简单方式是比较它们如何处理任务。CPU 由专为顺序串行处理而优化的几个核心组成,而 GPU 则拥有一个由数以千计的更小、更高效的核心(专为同时处理多重任务而设计)组成的大规模并行计算架构。同时CPU相当的一部分时间在执行外设的中断、进程的切换等任务,而GPU有更多的时间并行计算。

2.  GPU计算的原理

     那么,CPU与GPU如何协同工作?下图展示了CPU与GPU的并存体系模式。

      在需要GPU进行运算时,以NVIDIA推出的CUDA(Compute Unified Device Architecture)为例,整体的原理如下:

 整体分为4步:

  • 从主机内存将需要处理的数据copy到GPU的内存
  • CPU发送数据处理执行给GPU
  • GPU执行并行数据处理
  • 将结果从GPU内存copy到主机内存

     CUDA提供了对于一般性通用需求的大规模并发编程模型,使用户可以对NVIDIA GPU方便的对于 GPU进行并发性编程。如果进行编译优化会在特定操作系统里面把计算并行化分配到GPU的多个core里面,由于GPU有多个core(上千个),所以并发度大大提高,运算效率会比CPU高。下面用代码表明了如何通过GPU进行计算:

    有三个数组int a[10], b[10], c[10];我们要计算a和b的向量之和存放到c中。

    一般C语言:

[Bash shell] 纯文本查看 复制代码
1
2
3
for(int i=0; i<10; i++)
 
c[i] = a[i] + b[i];


CUDA编程做法:

GPU中的每个线程(核)有一个独立序号叫index,那么只要序号从0到9的线程执行c[index] = a[index] + b[index];就可以实现以上的for循环。以下为代码示例:

[Bash shell] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
#include  
 
#include  
 
  
 
define N 10;/* 定义10个GPU运算线程 */ 
 
define SIZE N*sizeof(int);
 
  
 
/* 运行在GPU端的程序 */ 
 
__global__ void vectorADD(int* a, int* b, int* c) 
 
 
     int index = threadIdx.x;//获得当前线程的序号 
 
     if(index < blockDim.x) 
 
         c[index] = a[index] + b[index]; 
 
 
   
 
int main () 
 
 
        /* 本地开辟三个数组存放我们要计算的内容 */ 
 
        int* a = (int*) malloc (SIZE); 
 
        int* b = (int*) malloc (SIZE); 
 
        int* c = (int*) malloc (SIZE); 
 
        /* 初始化数组A, B和C */ 
 
        for(int i=0; i<N; i++) 
 
        
 
                h_a[i] = i; 
 
                h_b[i] = i; 
 
        
 
             
 
        /* 在GPU上分配同样大小的三个数组 */ 
 
        int* d_a; 
 
        int* d_b; 
 
        int* d_c; 
 
        cudaMalloc((void**)&d_a, SIZE); 
 
        cudaMalloc((void**)&d_b, SIZE); 
 
        cudaMalloc((void**)&d_c, SIZE); 
 
   
 
        /* 把本地的数组拷贝进GPU内存 */ 
 
        cudaMemcpy(d_a, a, SIZE, cudaMemcpyHostToDevice); 
 
        cudaMemcpy(d_b, b, SIZE, cudaMemcpyHostToDevice); 
 
      
 
        /* 定义一个GPU运算块 由 10个运算线程组成 */ 
 
        dim3 DimBlock = N; 
 
        /* 通知GPU用10个线程执行函数vectorADD */ 
 
        vectorADD<<<1 dimblock="">>>(d_a, d_b, d_c); 
 
        /* 将GPU运算完的结果复制回本地 */ 
 
        cudaMemcpy(c, d_c, SIZE, cudaMemcpyDeviceToHost); 
 
           
 
        /* 释放GPU的内存 */ 
 
        cudaFree(d_a); 
 
        cudaFree(d_b); 
 
        cudaFree(d_c); 
 
   
 
        /* 验证计算结果 */ 
 
        for(int j=0; j<N; j++) 
 
                printf(“%d “, c[j]); 
 
        printf(“\n”); 
 
}


3.  GPU并行计算的原理

      由于每台服务器有多个CPU,多个GPU,同时为了进一步提高并行机器学习效率,我们的目标是为了多台服务器(每台服务器包含多块GPU卡)采取分布式计算的形式进行,那么要完成目标,在硬件层面需要进行服务器集群的构建,同时需要在深度学习框架层面也支持分布式,下面介绍GPU计算的分布式原理,深度学习分布式原理在下一个章节介绍。

首先简单介绍下单主机内GPU并行计算的基本原理:

单GPU并行计算:

      针对每次训练数据,模型内计算通过多次GPU 内核的调用完成计算。权重W值一直存在GPU内存中,直到所有训练数据计算完毕之后回传到系统内存中。

多GPU并行计算之数据并行:

      数据并行是指不同的GPU计算不同的训练数据,即把训练数据划分给不同的GPU进行分别计算,由于训练是逐步训练的,后一个训练数据的计算需要前一个训练数据更新的W(W通常是指模型训练变化了的数据),数据并行改变了这个计算顺序,多GPU计算需要进行W的互相通信,满足训练的特点,使训练可以收敛。数据并行如上图所示,多GPU训练不同的数据,每训练一次需要同步W,使得后面的训练始终为最新的W。该模型的缺点是当模型较大时,GPU内存无法满足存储要求,无法完成计算。

多GPU并行计算之模型并行:

     模型并行是指多个GPU同时计算同一个训练数据,多个GPU对模型内的数据进行划分,在一次训练数据多层计算过程中,每个GPU内核计算之后需要互相交换数据才能进行下一次的计算。

    可以看出,模型并行需要更频繁的通信,增加通信压力,且实现难度较大

多GPU并行计算之集群计算:

GPU集群并行模式即为多GPU并行中各种并行模式的扩展,如上图所示。节点间采用InfiniBand通信,节点间的GPU通过RMDA通信,节点内多GPU之间采用基于infiniband的通信。

Copyright © 2009-2018:上海研算;服务热线:400-888-9971;网址: http://www.srcsh.com/

 备案/许可证编号:沪ICP备2022008517号-1   技术支持:冰雪网络