- 深度序列模型与自然语言处理:基于TensorFlow 2实践
- 阮翀
- 2025字
- 2024-12-27 22:34:47
1.2.2 深度学习框架
如同1.2.1节中所提到的,深度学习的工具箱主要是深层神经网络,其中涉及的计算主要是求导和矩阵运算。手动求导烦琐且容易出错,手写矩阵运算麻烦而又效率低下,因此,深度学习框架应运而生。
1.求导方法
现阶段通常有三类求导(13)方法:数值求导(Numerical Differentiation),符号求导(Symbolic Differentiation),自动求导(Automatic Differentiation)。
(1)数值求导
数值求导是用差分近似代替导数,给自变量一个小的增量(在第i个坐标轴上增加一个小量,其他坐标轴上的分量都为零),然后检查函数值的变化量,用割线斜率代替切线斜率,即:
上式被称作前向差分(Forward Difference),由泰勒展开易知其近似误差为量级(14)。为了减小误差,实践中另一个经常使用的公式是中心差分(Central Difference),误差为量级:
假如有N个自变量需要求导,那么数值求导需要在N个方向上分别进行微扰,需要进行O(N)次函数求值,计算量过大从而不实用。不过假如需要对手动求导的结果进行合理性检查(Sanity Check),则可以随机挑选少数几个分量计算数值导数并和手工推导的结果作对比。
(2)符号求导
符号求导则是求出表达式的解析导数。这听上去似乎很美好,但是实践中会出现表达式爆炸(Expression Swell)的问题:对复合函数求导后,导数的数学表达式越来越长,不便于使用。
(3)自动求导
深度学习框架一般使用的都是自动求导。这是一种介于符号求导和数值求导之间的方法:它在局部使用符号求导,但不把导数中的某个子节点完全展开成表达式,而是直接用子节点的值填进去。在构建前向计算的计算流图时,框架同时也会产生一张用于后向计算的计算流图,来得到各个参数的梯度。也正因如此,深度学习框架需要缓存很多中间变量(例如反向传播算法中需要缓存的z(l)),这些变量占据的存储空间甚至可能会超过参数及其梯度本身所占据的空间。
2.矩阵运算
至于矩阵运算就更简单了。在CPU的时代,就已经有了Eigen、OpenBLAS[32]、Intel MKL[33]等优秀的线性代数运算库,各种框架的CPU版本通常会链接到这些库。更常用的模型训练平台则是显卡,因为显卡天生适合并行计算。NVIDIA为此专门开发了神经网络加速库cuDNN[34],内部封装了大量深度学习中常用模块的高效实现。除了cuDNN生态不成熟时的极少数早期框架外,现在流行的框架都支持cuDNN。此外,深度学习框架也慢慢开始接入TPU[35]或其他AI芯片。深度学习框架中将标量、向量、矩阵和更高维的数组统一抽象为张量(Tensor)数据类型。
3.深度学习框架类型
从使用的角度,深度学习框架分为静态图(Static Graph)框架和动态图(Dynamic Graph)框架两种。静态图框架的特点是声明计算图后才能使用(Define-and-Run)。由于不能随意查看计算图中节点的值,一旦出了问题将很难调试(15);同时,也很难对不同的数据执行不同的计算过程,在实现一些结构复杂的新模型时,往往显得力不从心。这类框架最早的是Theano[36],于2007年问世;谷歌出品的TensorFlow[37]则继承了Theano,从设计到开发都有很大的相似性,于2015年开源。在计算机视觉方面,华人学者贾扬清开发的Caffe[38]是最早流行的框架,大量的开源配置文件和预训练模型对行业发展起到了巨大的推动作用,但对循环神经网络支持欠佳。动态图框架则是边计算边构建计算图(Define-by-Run),灵活性很高,但在运行速度和显存优化上则略逊一筹。Chainer[39]和DyNet[40]是较早期的动态图框架,现在PyTorch[41]后来居上,成为各大学术会议的宠儿。一方面,动态图框架的上手难度较低,更适合初学者;另一方面,动态图框架中易于实现让人目不暇接的新模型,对于研究人员来说是一大利好——这也是近年来PyTorch爆发式增长的重要原因。
除了上述框架外,Keras和MXNet[42]也很流行。一开始Keras是一个上层框架,建立在Theano或TensorFlow两个可选后端之上;而如今Theano式微,TensorFlow官方正式推动Keras的API成为TensorFlow顶层设计的一部分——TensorFlow 1.x的高层API十分混乱,常常同一个功能有多种不同的实现,让人很难搞清楚该用哪个;现在谷歌官方推动使用Keras作为统一的高层API,大大改善了这种混乱的状况。MXNet最初是一个静态图框架,以高效的分布式训练支持而闻名,现在也支持了静态图和动态图两种模式,同时建立了GluonCV、GluonNLP[43]等工具包来降低使用门槛。国产深度学习框架也层出不穷:百度出品的PaddlePaddle[44]、旷视科技的MegEngine、华为开发的MindSpore……华人学者在深度学习方面成就喜人。
从市场占有率来看,最流行的深度学习框架当属TensorFlow和PyTorch。前者历史更悠久,对移动端和服务端的支持也更完善;后者在研究人员中的份额在不断扩大,也在慢慢建立属于自己的生态。同时,各个框架也在互相渗透、互相影响:TensorFlow正拖着沉重的历史包袱向动态图框架转型,TensorFlow 2中已经默认开启Eager Mode(动态图模式);而PyTorch则将TensorFlow的训练监控工具TensorBoard移植过来为己所用。目前各大框架的前端设计已经高度趋同,实践给出了深度学习API设计的最佳答案。
PyTorch对深度学习做出了优雅的三层抽象:张量(Tensor)—变量(Variable)—模块(Module)。张量就是多维数组,可以在GPU上高效运算;变量是对张量的一层封装,指计算图中的节点,可以用于在反向传播中找到某个张量对应的梯度张量,也可以不断修改其内部状态来实现模型参数的更新;模块则是把多个相关的变量及计算步骤打包放在一起的高层结构,例如权重和偏置一起进行乘加运算,组成一个全连接层(Fully Connected Layer)。在TensorFlow 2中,以上三层抽象分别对应tf.Tensor,tf.Variable和tf.keras.Model。