动手学深度学习 3.14 正向传播、反向传播和计算图
前言
从零开始学习ai文章系列计划是个人在《动手学深度学习》和《磨菇书》两本书的学习中的个人笔记,文章也会以课本中的章节分开,即每个章节一片笔记。我会尽量的把主要内容以及遇到的难点进行记录与解决,如果哪里有错误的欢迎指正。或者不清晰的可以直接查看原文部分。
《动手学深度学习》原文(课本):https://tangshusen.me/Dive-into-DL-PyTorch/#/
《动手学深度学习》代码:https://github.com/ShusenTang/Dive-into-DL-PyTorch
(由于有时候公式太多,可能会直接贴图片)
前面几节里我们使用了小批量随机梯度下降的优化算法来训练模型。
在实现中,我们只提供了模型的正向传播(forward propagation)的计算,即对输入计算模型输出,
然后通过autograd模块来调用系统自动生成的backward函数计算梯度。
本节我们将使用数学和计算图(computational graph)两个方式来描述正向传播和反向传播。
1. 正向传播
正向传播是指对神经网络沿着从输入层到输出层的顺序,依次计算并存储模型的中间变量(包括输出)。
假设输入是一个特征为 \(x\)(d * 1) 且不考虑偏差项,那么中间变量 \[ z = W^{(1)}x \] 其中 \(W^{(1)}\)(m * d) 是隐藏层的权重参数。把中间变量 \(z\) (m * 1)输入按元素运算的激活函数 \(ϕ\) 后,将得到向量长度为m的隐藏层变量 \[ h=ϕ(z) \] 隐藏层变量h (m * 1) 也是一个中间变量。假设输出层参数只有权重 \(W^{(2)}\)(q * m) 可以得到向量长度为q的输出层变量 \[ o=W^{(2)}h \] \(o\) 对 \(W^{(2)}\) 的求导结果为 \(h\) 的转置即 \(h^T\) 并复制与 \(o\) 相同n行。(即求导结果为n行的 \(h^T\) )
假设 \(o_i\) 为 o 的第i行元素(o为列向量,即大小为n*1), \(W_i\) 为W的第i行元素。每行元素有m列。变量h有m行 \[ o_i=W_ih=w_{i1}h_1+w_{i2}h_2+...+w_{im}h_m \] 那么\(oi\)对\(w_{i1}\)的偏导为\(h_1\),对\(w_{i2}\)的偏导为\(h_2\) ,同理可得\(o_i\)对\(W_i\)的求导结果为横向量 {\(h_1,h_2,...,h_m\)} 即\(h^T\) 。
一共n个\(o_i\) ,因此一共n行 \(h^T\)
假设损失函数为ℓ,且样本标签为y,可以计算出单个数据样本的损失项(其实这里的o是一个元素,并非列向量) \[ L=ℓ(o,y) \] 根据L2范数正则化的定义,给定超参数λ,正则化项即

其中矩阵的Frobenius范数等价于将矩阵变平为向量后计算L2范数。最终,模型在给定的数据样本上带正则化的损失为 \[ J = L + s \] 也就是之前说的

我们将J称为有关给定数据样本的目标函数,并在以下的讨论中简称目标函数。
2. 正向传播的计算图
我们通常绘制计算图来可视化运算符和变量在计算中的依赖关系。图3.6绘制了本节中样例模型正向传播的计算图,其中左下角是输入,右上角是输出。

接下来我会按照之前正向传播顺序逐个框出来所做的操作






3. 反向传播
反向传播指的是计算 神经网络参数梯度 的方法。
总的来说,反向传播依据微积分中的链式法则,沿着从输出层到输入层的顺序,依次计算并存储目标函数有关神经网络各层的中间变量以及参数的梯度。
对输入或输出X,Y,Z为任意形状张量的函数Y=f(X)和Z=g(Y),通过链式法则,我们有

其中prod运算符将根据两个输入的形状,在必要的操作(如转置和互换输入位置)后对两个输入做乘法。
回顾一下本节中样例模型,它的参数是 \(W^{(1)}\) 和 \(W^{(2)}\) ,因此反向传播的目标是计算 \(\frac{∂J}{∂W^{(1)}}\) 和\(\frac{∂J}{∂W^{(2)}}\)。asd
我们将应用链式法则依次计算各中间变量和参数的梯度,其计算次序与前向传播中相应中间变量的计算次序恰恰相反。首先,分别计算目标函数J=L+s有关损失项L和正则项s的梯度

其次,依据链式法则计算目标函数有关输出层变量o的梯度

其结果指的是loss函数对o的求导.
接下来,计算正则项有关两个参数的梯度:

现在,我们可以计算最靠近输出层的模型参数的梯度(之前说过o是单个样本的输出,因此导数是一个横向量)

沿着输出层向隐藏层继续反向传播,隐藏层变量的梯度

由于激活函数ϕ是按元素运算的,中间变量z的梯度的计算需要使用按元素乘法符⊙:

最终,我们可以得到最靠近输入层的模型参数的梯度。依据链式法则,得到

4. 训练深度学习模型
一方面,正向传播的计算可能依赖于模型参数的当前值。而这些模型参数是在反向传播的梯度计算后通过优化算法迭代的。
例如,计算正则化项
依赖模型参数 \(W^{(1)}\) 和 \(W^{(2)}\)
的当前值,,而这些当前值是优化算法最近一次根据反向传播算出梯度后迭代得到的。
另一方面,反向传播的梯度计算可能依赖于各变量的当前值,而这些变量的当前值是通过正向传播计算得到的。
举例来说,参数梯度
的计算需要依赖隐藏层变量的当前值h。这个当前值是通过从输入层到输出层的正向传播计算并存储得到的。

因此,在模型参数初始化完成后,我们交替地进行正向传播和反向传播,并根据反向传播计算的梯度迭代模型参数。
既然我们在反向传播中使用了正向传播中计算得到的中间变量来避免重复计算,那么这个复用也导致正向传播结束后不能立即释放中间变量内存。这也是训练要比预测占用更多内存的一个重要原因。
另外需要指出的是,这些中间变量的个数大体上与网络层数线性相关,每个变量的大小跟批量大小和输入个数也是线性相关的,它们是导致较深的神经网络使用较大批量训练时更容易超内存的主要原因。
小结
这部分要点内容在于,理解正向传播与反向传播是什么
正向传播就是通过网络求值。
反向传播就是通过网络求导。
正向传播相当于 y=wx, L=(y'-y)² (平方差)
通过 初始化 或 反向传播 获取w的值,计算出y
反向传播相当于 ∂L/∂y=-2y'+y , ∂y/∂w=x ⇒ ∂L/∂w=(-2y'+y)x ⇒ w=w-∂L/∂w
通过正向传播中的计算值y,获得w的偏导,更新w