(二十四)走近GPU


一、GPU出现的历史背景

      随着深度学习的发展,GPU一下子火了,但是其实GPU一开始是为图形计算而生,由于其架构设计的特点使得它在图形计算和深度学习领域相比CPU有很大优势。

二、图形渲染流程

      要在电脑显示器上显示出3D效果,并不是通过拍摄,而是通过多边形建模创建出来的,包括3D画面中人物的移动以及光线变化都由计算机通过渲染生成,渲染过程分为五个步骤,也被成为图形流水线

  1. 顶点处理:顶点转换通过线性代数计算完成,定点转换计算量很大且相互之间没有依赖,可以独立并行计算;
  2. 图元处理:顶点计算完成之后,需要将各个顶点连起来并进行剔除和裁剪,这就是图元操作;
  3. 栅格化:由于图形最终由很多像素点表示,因此图元计算完成后,还需要将图元栅格化
  4. 片段处理:栅格化得到像素点之后需要计算每个像素点的颜色和透明度,这步同样可以并行处理;
  5. 像素处理:最后将多边形重叠的部分进行“混合”处理,最终输出到显示设备。

 三、使用硬件进行图形运算的优势

      尽管CPU功能强大,它可以执行多达数百条指令集,但是在图形运算方面的表现不尽人意,这主要是因为使用CPU进行图形运算所需的执行指令数太过庞大。

      图形的运算实际上属于简单运算,完全可以使用特有的硬件电路完成,例如Voodoo FX就是这样的产品,使用了它,我们也不需要编程,相关逻辑写好后直接丢给硬件去跑就行(假如Java中某一段多态代码其实在运行中其类型是固定的,那么直接将其编译为机器码执行,通过放弃灵活性来换取高效率)。

四、Shader 和 可编程图形处理器

      Voodoo 显卡的渲染管线中没有顶点处理,而是要通过CPU来完成,图形渲染的效果依然受限于CPU性能。后来出现了GeForce 256 显卡,它终于也支持顶点计算,这时候全部的图形渲染都通过硬件电路来完成,程序员能操作的只有修改一些配置。因此微软第一次引入了可编程管线,它只支持顶点处理和片段处理的部分,因此也被成为着色器。

      这时的Shader按照其功能分为两种:Vertex Shader 和 Fragment Shader,它们有各自的硬件电路与不同的编程接口,但是它们却有相同的指令集,因此在一次图形渲染过程中同一时刻只有一种Shader在运行,另一半只能傻等,为了避免这种浪费,统一着色器架构终于出现了。

      也由于Shader变成了一个通用的模块,GPU也可以支持各种通用计算,也即是GOPGPU,它支持了过去十年深度学习的繁荣。

 五、现在GPU的三个核心创意

      现代GPU之所以能够在图形渲染和深度学习方面表现那么出色,是因为它主要有以下几个特点:

      电路精简:GPU上处理的运算整体似一个流式过程,没有很多的分支条件和复杂依赖关系,因此可以直接去掉相关电路,只保留“取指令”、“指令译码”、“ALU”及执行计算所需的寄存器和缓存即可。

       多核并行和SIMT由于GPU的运算是天然并行的,因此我们不需要像CPU那样去通过多线程来实现并行计算,只需在同一个GPU中集成很多组并行的GPU电路即可。

       更进一步,图形渲染的运算不论顶点进行线性变换还是像素着色,都是用相同的指令流程进行计算,因此CPU借鉴CPU的SIMD实现了自己的SIMT,且比SIMD更加灵活,SIMD中CPU每次取出固定长度的数据存放在寄存器中用一个指令去执行,而SIMT将多条数据交给不同线程去处理(单核上支持多线程),这样虽然各个线程中指令流程一样但是由于数据的不同,会走到不同的条件分支。

      在此基础之上,可以在取指令和指令译码阶段,将取出的指令分发给后面多个ALU去并行计算,一个GPU中就可以放置更多的ALU,进行更多的并行计算了。

       GPU中的超线程:GPU发展为一个通用计算架构后,它需要支持分支运算,但是分支预测相关的电路却被精简了,因此也会遇到类似“流水线停顿”的问题,GPU通过类似“超线程”的技术来解决这个问题,就是为不同的任务提供更多的执行上下文,因此一个core里面执行上下文数量多于ALU。

六、GPU支持深度学习的性能差异

      通过以上三方面优化的GPU更擅长暴力运算,也就更适合现在深度学习的使用场景,一方面作为一个通用计算框架,通过编程可以支持不同的算法。另一方面深度学习计算都是海量训练样本下的超大的向量和矩阵运算,没有那么多复杂逻辑和条件分支,因此非常适合GPU去运算。

      以NVidia 2080为例来分析一下一款显卡的计算能力:

2080 一共有46个SM(Streaming Multiprocessor 流式处理器),相当于一个46核的GPU,有46个取指令、指令译码的渲染管线。每个SM中包含64个Cuda core,近似可以看作有64个ALU或者Pixel Shader,46*64=2944个Shader,另外还有184个TMU,就是Texture Mapping Unit,是用来做纹理映射的计算单元,可以看作另一种Shader。

      2080 是为主频是1515MHz,自动超频后可以达到1700MHz,NVidia显卡依据其硬件架构设计,每个时钟周期可以执行两条指令。因此它做浮点计算的能力是:

      (2944+184)* 1700MHz * 2 = 10.06 TFLOPS

对比最新的Intel i9 9900K 其性能是不到1TFLOPS,两者价格接近,但是计算速度相差一个数量级。因此使用GPU做深度学习模型的计算更加适合。