Page 37 - 《软件学报》2020年第9期
P. 37
2658 Journal of Software 软件学报 Vol.31, No.9, September 2020
度.LSTM 是一种特殊的 RNN,用来解决 RNN 存在的长期依赖问题,即相关信息与预测位置的间隔很大而导致
RNN 无法学习连接信息.LSTM 的隐藏层比传统 RNN 复杂,是一种拥有 3 种“门”的特殊网络结构,从而更有效地
保存长期记忆.其中:“遗忘门”的作用是让循环神经网络“忘记”之前没有用的信息,“输入门”决定哪些部分记忆
进入当前时刻的状态,“输出门”决定当前时刻的输出.
当前主流的 DNN 开发及运行框架包括 TensorFlow(Google) [31] ,PyTorch(Facebook) [32] ,Caffe(Berkeley 大
学) [33] ,其他 DNN 框架如 Theano(Montreal 大学),Keras(Keras-Team),MXNet(Amazon),CNTK(Microsoft)的用户基
础远比不上前 3 种.DNN 框架的运行原理(以 TensorFlow 为例 [34] ):首先,将用户基于应用层 API 编写的、以神经
网络算法为代表训练或推理过程表达为数据流图计算;在运行时,把数据流图转换成 C++核心层的细粒度、抽
象化运行时状态,进而在计算设备(CPU 或 GPU)上以一致而有效的方式调度执行.主流的 DNN 框架能够支持在
个人电脑、大型数据中心的服务器、嵌入式设备等多种平台上运行.
1.3 嵌入式GPU
图像处理器(graphics processing unit,简称 GPU)最初是计算机系统中加速图形图像运算的专用芯片,如今
的 GPU 因集成了大量的处理器核心,具有了非常强大的并行处理能力,并且已经被广泛应用于通用计算领域,
例如游戏开发、图像处理、视频处理、科学计算、大数据、深度学习等领域.当前,国际主流的 GPU 厂商主要
有通用计算领域的 NVIDIA,AMD(ATI),Intel(CPU 内置显示核心)以及移动计算领域的 ARM,Qualcomm,
PowerVR 等.本节选择最为广泛的 NVIDIA GPU 系列,先介绍普通 PC 平台 GPU,了解 GPU 的一般架构和工作
原理.在此基础上,再介绍嵌入式 GPU 的架构和工作特点.
PC 平台的 GPU 计算卡一般通过高速的 PCI-E(peripheral communications interconnect express)总线与主板
上的北桥芯片相连.PCI-E 是连接 GPU 卡与 CPU 的全双工高速总线.PCI-E 2.0 的传输速率为 5GB/s,PCI-E 3.0
提升到了 8GB/s.PCI-E 总线能够为每块 GPU 卡提供确定的读写带宽,而不受所挂载的 GPU 卡数量的影响.图 2
显示了一块 NVIDIA GPU 芯片的架构模块示意图,包括 3 种关键模块 [35] :流处理器簇(streaming multiprocessor,
简称 SM)、流处理器(streaming processor,简称 SP)、(全局、常量、共享)内存.“流”是一个 GPU 操作队列,该队
列中的操作(可能由多个主机线程发出)将以添加到流中的先后顺序而依次执行.可以将一个流看作是 GPU 上
的一个任务,不同流里的任务可以并行执行.所以一个流对应于并发的概念,多个流对应并行的概念.GPU 是由
多个 SM 组成的 SM 阵列,每个 SM 包含 8N 个 SP(SP 也称 CUDA(compute unified device architecture)
核,G80/GT200 中有 8 个 SP,RTX2080 中有 64 个 SP),每个 SP 都是一个设计简单的处理器.全局内存(global
memory)就是 GPU 卡的显存.纹理内存(texture memory)和常量内存(constant memory)都是针对全局内存的一个
特殊视图.其中,纹理内存是在显示 2D 或 3D 图像时存储插值计算所需要的数据,常量内存用于存储只读数据.
每个 SM 通过总线可以独立访问 3 种内存.每个 SM 内部都有共享内存(shared memory).与 CPU 不同,它没有自
动完成数据替换的硬件逻辑,而是完全由程序员控制,所以它是一种程序可控的高速缓存.
主流的 GPU 通用编程接口包括 NVIDIA 公司开发的 CUDA 运算平台、苹果公司持有但是保持开放的
OpenCL(open computing language)标准、微软公司开发的 Direct(direct compute)标准.CUDA [36] 是 C 语言的一种
扩展,支持基于 PTX(parallel thread execution)虚拟指令集的运行时编译,即 CUDA 代码先被编译成并行线程执
行(parallel thread execution,简称 PTX)这种中间形式,然后再次编译为原生的 GPU 微码;并且向前兼容(forwards
compatibility),即无论 GPU 的硬件结构如何改变,为早期 CUDA 设备编写的程序依然能够运行在最新的 CUDA
设备上.CUDA 编程模型是一种异构模型.CUDA 程序可以在 CPU 和 GPU 上并行运行,在 CPU 上运行的代码段
叫 Host code,在 GPU 上运行的代码段叫 Device code,其中包含若干 kernel 函数.每一个 kernel 在 GPU 上执行时
会启动很多线程运行同样的代码指令,即单指令多线程(single-instruction multiple-thread,简称 SIMT)的并行计
算模型.Kernel 线程的数量取决于程序员为 kernel 函数指定的参数 num_blocks(线程块数)和 num_threads(每个
线程块内执行 kernel 函数的线程数).这两个参数的配置会影响 kernel 函数的执行性能.每个 SM 最多能处理的
线程数是有上界,也就间接影响每个 SM 最多能容纳的线程块(thread block)的数量.另外,每 32 个线程组成一个
线程束(wrap),线程束是 GPU 调度和执行的基本单元.一个线程块所管理的线程束等于 num_threads 除以 32 并