极市导读
从前向传递、后向传递和优化器参数更新的浮点数计算次数入手,详解向传递的耗时为啥几乎是前向传递的两倍。 >>加入极市CV技术交流群,走在计算机视觉的最前沿
1. 前言
训练神经网络的一次迭代分为三步:(1)前向传递计算损失函数;(2)后向传递计算梯度;(3)优化器更新模型参数。在实验中,我们观察到一个现象:后向传递的耗时几乎是前向传递的两倍,相比之下,优化器更新的耗时几乎可以忽略。要解释这个现象,我们要从前向传递、后向传递和优化器参数更新的浮点数计算次数入手。
上图表示一次训练迭代中各个环节(前向传递、后向传递、通信环节、优化器更新)的耗时占比,来自于《PyTorch Distributed: Experiences on Accelerating Data Parallel Training》。上图中,纵轴表示耗时占比,FWD表示一次训练迭代中前向传递的耗时占比,BWD则表示一次训练迭代中后向传递的耗时占比,OPT表示一次训练迭代中优化器更新模型参数的耗时占比。从上图中可以看到,一次训练迭代中,后向传递的耗时几乎是前向传递的两倍,相比之下,优化器更新的耗时占比很小,几乎可以忽略。
上图表示GPipe流水线并行的调度策略,来自于《Efficient large-scale language model training on gpu clusters using megatron-lm》。上图中,横轴表示耗时,一个蓝色小块表示一个微批次的前向传递,一个绿色小块表示一个微批次的后向传递,黑色竖线表示一次流水线刷新,也就是优化器更新模型参数。从上图中可以看到,一个绿色小块的宽度大约是蓝色小块的二倍,一次训练迭代中,后向传递的耗时几乎是前向传递的两倍,相比之下,优化器更新的耗时占比很小,几乎可以忽略。
2. 反向传播算法是怎么工作的
反向传播算法已经是训练神经网络模型不可缺少的一部分。训练神经网络模型时,用梯度下降算法来学习和更新模型参数(包含权重weights和偏置bias),问题是如何计算损失函数关于模型参数的梯度呢?这就要用到反向传播(backpropagation)算法。
反向传播算法的核心是计算损失函数 关于神经网络权重 或偏置 的偏微分 或 ,这两个偏微分表达式就是梯度。梯度的物理意义是:我们改变网络权重和偏置可以在多大程度上影响损失函数 。
2.1 前向传递:计算神经网络的输出
在讨论反向传播算法之前,我们先以多层前馈神经网络为例,用基于矩阵的方法来计算神经网络的输出。在此过程中,先定义一些数学符号。
首先明确地定义神经网络中的权重参数,用 表示第 层第 个神经元到第 层第 个神经元的连接。例如,下图中的权重 表示第2层第4个神经元到第3层第2个神经元的连接。这个定义看起来有些麻烦,一个迷惑之处是 的顺序,应该用 表示输入神经元,用 表示输出神经元,而不是相反。但之后的计算中,你会看到这个定义是自然而然的。
类似地,我们定义网络中的偏置和激活。用 表示网络中第 层第 个神经元的偏置,用 表示网络中第 层第 个神经元的激活。下图给出了示例。
有了以上定义,我们就可以把网络第 层第 个神经元的激活 与第 层的激活联系起来。单个神经元的计算公式(逐点形式):
其中,求和是对第 层上所有神经元 的求和, 是激活函数。
为了以矩阵形式重写上式,我们为第 层定义一个权重矩阵 (weight matrix) ,表示连接到第 层的权重,矩阵第 行第 列的元素为 。设第 层的输入维度为 ,输出维度为 。则该权重矩阵 的形状为 。
同样地,我们定义一个偏置向量 (bias vector) ,它的元素是 ,形状是 。定义一个激活向量 (activation vector) ,它的元素是 ,形状是 。
重写上式需要的最后一个要素是向量化 (vectorization) 函数。核心是函数逐点应用到向量中的每个元素。
有了以上定义,我们就可以将上式改写为矩阵形式:
下标表示了矩阵或者向量的形状。这个公式给出一个更全局的视角来观察一层神经元的激活是如何与上一层神经元的激活联系起来的:先将权重矩阵应用到上一层的激活,再加上偏置向量,最后过激活函数。
我们引入中间变量 ,我们将 称为第 层神经元的加权输入 (weighted input)。其元素为:
2.2 反向传播的四个基本等式
右边的第一项表示第 个输出激活多大程度上影响了损失函数。如果损失函数不太依赖于第 个神经元激活,那么 会是一个比较小的值。第二项表示激活函数在 上的改变程度。
将上式改写为矩阵形式:
证明:
从定义出发,应用多元微积分的链式法则:
2.2.2 误差与下一层误差的关联
上式中, 是第 层权重矩阵 的转置。这个式子乍一看是很复杂的,但每一项都有优美的解释。假设我们已经知道第 层的误差 ,乘以转置的权重矩阵 ,可以理解为将误差通过网络反向传播,这衡量了第 层输出激活的误差;再乘以阿达玛乘积 ,将误差通过第 层的激活函数反向传播,这衡量了第 层加权输入的误差。
这个式子是很优雅的。有了公式(BP1)和(BP2),就可以计算出所有层对加权输入的误差了。 。这也就是称之为梯度反向传播算法的原因。
证明:
从定义出发,应用多元微积分的链式法则: 有 , 以及 。
要评估等式右边的第一项,注意到:
取微分,得到:
带入上上式中,得到:
重写为矩阵形式,即:
2.2.3 偏置的梯度
第 层偏置的梯度就等于第 层加权输入的误差 。改写为矩阵形式:
证明:
由定义出发,用多元微积分的链式法则:
注意到: ,故 。带入上式中,得到:
2.2.4 权重的梯度
第 层权重的梯度就等于第 层加权输入的误差 与 上一层神经元输出激活 的乘积。将上式改写为:
假设权重 连接了两个神经元, 是神经元输入给权重的激活, 是权重输出给神经元的误差。
证明:
由定义出发,应用多元微积分的链式法则:
注意到: ,故 。带入上式中,得到:
2.2.5 四个基本等式
综上,梯度反向传播的四个基本等式是:
有了这四个基本等式,我们就基本理解了梯度的计算过程。
3. 后向传递与前向传递的FLOPs比率
3.1 定义
FLOPS:全大写,floating point operations per second,每秒钟浮点数计算次数,理解为运算速度,是衡量硬件性能的指标。例如:A100的float32运算速度是9.7TFLOPS,V100的float32运算速度是7.8TFLOPS。
FLOPs:s为小写,floating point operations,表示浮点数运算次数,理解为计算量,衡量模型或算法的复杂度。
如何计算矩阵乘法的FLOPs呢? 对于 ,计算 需要进行 次乘法运算和 次加法运算,共计 次浮点数运算,需要 FLOPs。对于 ,浮点数运算次数为 。
backward-forward FLOP ratio:后向传递与前向传递的FLOPs比率,表示一次后向传递的浮点数计算次数与一次前向传递的浮点数计算次数的比率。衡量了一次后向传递要比一次前向传递多进行的浮点数运算。
3.2 前向传递与后向传递的浮点数操作次数的理论分析
为了理解后向传递的浮点数运算为什么要比前向传递多?我们就要从反向传播算法的四个基本等式入手。
我们从一个有2层隐藏层的神经网络入手:
我们假设线性层采用ReLU激活函数,采用随机梯度下降优化器。下表中h1和h2分别表示第1层和第2层隐藏层的神经元个数。有2层隐藏层的神经网络一次训练迭代的计算过程如下表所示:
从上表中,我们可以观察到,对于多层前馈神经网络模型,有以下结论:
1. 相比于线性层,激活函数ReLU和损失函数的浮点数运算量可以忽略。
2. 对于第一层,后向传递-前向传递的FLOPs比率是1:1。
3. 对于其他层,后向传递-前向传递的FLOPs比率是2:1。
4. 采用随机梯度下降作为优化器,权重更新的FLOPs是模型参数规模的2倍。
3.2.1 第一层与其他层的区别
对于多层前馈神经网络模型,采用随机梯度下降作为优化器。
第一层的后向传递-前向传递的FLOPs比率是1:1,其他层的后向传递-前向传递的FLOPs比率是2:1。模型参数更新的FLOPs是模型参数规模的2倍。
3.2.2 batch_size的影响
前向传递和后向传递的计算量FLOPs与batch_size成正比,即随着batch_size增大而线性增长。
优化器更新模型参数的FLOPs与batch_size无关,只与模型参数规模和优化器类型有关。
随着batch_size增大,前向传递和后向传递的FLOPs线性增长,而权重更新的FLOPs保持不变,这使得权重更新的FLOPs变得逐渐可以忽略不计了。
3.2.3 网络深度的影响
神经网络层数对后向传递-前向传递FLOPs比率有着间接的影响。由于第一层的后向-前向FLOPs比率是1:1,而其他层后向-前向FLOPs比率是2:1。层数的影响实际上是第一层与其他层的比较。
定义一个CNN神经网络,中间层的数量由0到100,可以看到后向-前向FLOPs比率由1.5提高到了接近2的水平。当层数逐渐变深的时候,第一层对模型整体的FLOPs影响就变小了,模型整体的后向-前向FLOPs比率就很接近2。
4. 总结
随着batch_size的增大,前向传递和后向传递的FLOPs线性增长,而权重更新的FLOPs保持不变,参数更新的FLOPs变得可以忽略不计了。这体现为:当batch_size足够大时,在训练神经网络的一次迭代中,前向传递和后向传递是主要的耗时环节,而参数更新的耗时变得几乎可以忽略不计。
由于第一层的后向-前向FLOPs比率是1:1,而其他层后向-前向FLOPs比率是2:1。随着网络层数的加深,第一层对整体FLOPs的影响变得可以忽略不计了。这体现为:当网络层数足够深时,后向传递的耗时几乎是前向传递耗时的2倍。
总的来说,对于用大batch_size的深层神经网络来说,后向传递-前向传递的FLOPs比率接近于2:1,换句话说,后向传递的计算量大约是前向传递的两倍。
参考链接
1.Li S, Zhao Y, Varma R, et al. Pytorch distributed: Experiences on accelerating data parallel training[J]. arXiv preprint arXiv:2006.15704, 2020.
2.Narayanan D, Shoeybi M, Casper J, et al. Efficient large-scale language model training on gpu clusters using megatron-lm[C]//Proceedings of the International Conference for High Performance Computing, Networking, Storage and Analysis. 2021: 1-15.
3.How the backpropagation algorithm works–Michael Nielsen(http//neuralnetworksanddeeplearning.com/chap2.html)
4.What’s the backward-forward FLOP ratio for Neural Networks?(https//www.alignmentforum.org/posts/fnjKpBoWJXcSDwhZk/what-s-the-backward-forward-flop-ratio-for-neural-networks)
公众号后台回复“数据集”获取100+深度学习各方向资源整理
极市干货
点击阅读原文进入CV社区
收获更多技术干货