前几节里面我们使用了小批量随机梯度下降的优化算法来训练模型。在实现中,我们只提供了模型的正向传播的(forward propagation)计算,即对于输入计算模型输出,然后通过autograd模块来调用系统自动生成的bachward函数来计算梯度。本节将使用数学和计算图(computational graph)两个方式来描述正向传播和反向传播。具体来说,我们将以带L2范数正则化的含单隐藏层感知机为样例模型解释正向和反向传播。
正向传播
正向传播是指神经网络沿着输入层到输出层的顺序,依次计算并存储模型的中间变量(包括输出)。为简单起见,假设输入是一个特征为$x∈R^的样本,且不考虑偏置项,那么中间变量 z = \boldsymbol^{(1)}x$,其中,\(\boldsymbol{W}^{(1)} ∈ R^{hxd}是隐藏层的权重参数。把其中变量z∈R^{h}输入按照元素运算的激活函数\phi\),\(将得到向量长度为h的隐藏层变量h = \phi(z)\)
隐藏层变量h也是一个中间变量。假设输出层测呢概述只有权重$\boldsymbol{(2)} ∈R$,可以得到向量长度为q的输出层变量 $$\omicron = \boldsymbol^{(2)} h $$
假设损失函数 \(l,且样本标签为y,可以计算出单个样本的损失项L =l(\omicron,y)\),根据L2范数正则化的定义,给定超参数$\lambda$,正则化项即 \(s = \frac{\lambda}{2}(\|\boldsymbol{W}^{(1)}\|_{F}^{2}+\|\boldsymbol{W}^{(2)}\|_{F}^{2})\)
其中,矩阵的forbenius范数等价于将矩阵变平为向量后计算L2范数。最终,模型在给定的数据样本带上正则化的损失为 $J = L+s 我们将J$称为有关给定数据样本的目标函数,并在以下的讨论中简称为目标函数。
反向传播
反向传播是指计算神经网络参数梯度的方法。 总的来说,反向传播依据微积分中的链式法则,沿着从输出层到输入层的顺序,一次计算并存储在有关神经网络各层的中间变量以及参数的梯度。对输入或者输出为X,Y和Z为任意形状的张量的函数Y = f(X) 和Z = g(Y) 通过链式法则,我们有
其中,pord运算符将根据两个输入的形状,在必要的操作(如转置和互换输入位置)后对两个输入做乘法)以本节的样例模型为例: 它的参数为$\boldsymbol{(1)}和\boldsymbol{(2)},因此反向传播的目标计算\frac{\partial J}{\partial W^{(1)}} 和\frac{\partial J}{\partial W^{(2)}}$。我们将应用链式法则依次计算各中间变量和参数的梯度,其计算次序与前向传播中相应的变量的计算次序正好相反。
首先,分别计算目标函数 \(J = L+s有关损失项L和正则项s的梯度\frac{\partial J}{\partial L}=1 ,\frac{\partial J}{\partial s}=1\)
其次,依据链式法则计算目标函数有关输出层变量的梯度$\frac{\partial J}{\partial \omicron} ∈ R^$ \(\frac{\partial J}{\partial \omicron} = prod(\frac{\partial J}{\partial L},\frac{\partial L}{\partial \omicron}) = \frac{\partial J}{\partial \omicron}\)
接下来,我们可以计算正则项有关的两个参数的梯度: \(\frac{\partial s}{\partial W^{(1)}} = \lambda \boldsymbol{W}^{(1)}\),\(\frac{\partial s}{\partial W^{(2)}} = \lambda \boldsymbol{W}^{(2)}\)
现在我们可以计算靠近输出层的模型参数的梯度$\frac{\partial J}{\partial W^{(2)}}∈ R^$,根据链式法则,得到 $\frac{\partial J}{\partial W^{(2)}} = prod(\frac{\partial J}{\partial \omicron},\frac{\partial \omicron}{\partial {(2)}}) + prod(\frac{\partial J}{\partial s},\frac{\partial s}{\partial {(2)}})=\frac{\partial J}{\partial \omicron}h^+1* \lambda^{(2)} $
沿着输出层想隐藏层继续反向传播,隐藏层变量的梯度$\frac{\partial J}{\partial h}∈R^$可以这样计算 \(\frac{\partial J}{\partial h}=prod(\frac{\partial J}{\partial \omicron},\frac{\partial \omicron}{\partial h})\) =\({W^{(2)}}^{T}\frac{\partial J}{\partial \omicron}\)
由于激活函数$\phi是按照元素计算的,中间变量z的梯度,\frac{\partial J}{\partial z}) ∈R^的计算也需要使用按照元素乘法符⊙$
最终,我们得到最靠近输入层的模型参数的梯度为$\frac{\partial J}{\partial W^{(1)}}∈R^$,根据链式法则,得到
训练深度学习模型
正向传播和反向传播相互依赖
一方面,正向传播的梯度计算可能依赖于各变量的当前值,而这些变量的当前值都是通过反向传播的梯度计算之后通过优化算法迭代的。比如加入正则化的目标函数的当前值是根据反向传播算出梯度迭代后得到的
另一方面,反向传播的梯度计算可能依赖于各变量的当前值,而这些变量的当前值都是正向传播计算得到的 。计算参数梯度的需要某系变量的当前值,而这些当前值是通过正向传播计算并存储得到。
在模型参数初始化完成后,我们交替的进行正向和反向传播,并根据反向传播的梯度迭代模型参数。在训练过程中,正向传播和反向传播的中的各个中间变量和梯度计算值都需要占用内存,而在预测过程中,没有反向传播计算梯度的过程,因此预测过程中内存的占用较小。
训练过程中的质检变量的个数大体上跟网络层数线性相关,每个变量的大小跟批量大小和输入个数也是线性相关的,它们是导致较深的神经网络使用较大批量训练是更容易超内存的主要原因。
小结