二、反向传播
2.1 前向传播
考虑计算单个标量 的计算图:
- 假设有 个输入节点: 。它们对应的是模型的参数和输入。
- 假设 为中间节点。
- 假设 为输出节点,它对应的是模型的代价函数。
- 对于每个非输入节点 ,定义其双亲节点的集合为 。
- 假设每个非输入节点 ,操作 与其关联,并且通过对该函数求值得到: 。
通过仔细排序(有向无环图的拓扑排序算法),使得可以依次计算 。
前向传播算法:
输入:
- 计算图
- 初始化向量
输出: 的值
算法步骤:
初始化输入节点: 。
根据计算图,从前到后计算 。对于 计算过程为:
- 计算 的双亲节点集合 。
- 计算 : 。
- 输出 。
2.2 反向传播
计算 时需要构造另一张计算图 : 它的节点与 中完全相同,但是计算顺序完全相反。
计算图 如下图所示:
对于图中的任意一非输出节点 (非 ),根据链式法则:
其中 表示图 中的边 。
- 若图 中存在边 ,则在图 中存在边 ,则 为 的子节点。
- 设图 中 的子节点的集合为 ,则上式改写作:
反向传播算法:
输入:
- 计算图
- 初始化参数向量
输出:
算法步骤:
运行计算 的前向算法,获取每个节点的值。
给出一个
grad_table
表,它存储的是已经计算出来的偏导数。对应的表项存储的是偏导数 。
初始化 。
沿着计算图 计算偏导数。遍历 从 到 :
计算 。其中: 是已经存储的 , 为实时计算的。
图 中的边 定义了一个操作,而该操作的偏导只依赖于这两个变量,因此可以实时求解 。
存储 。
返回 。
反向传播算法计算所有的偏导数,计算量与 中的边的数量成正比。
其中每条边的计算包括计算偏导数,以及执行一次向量点积。
上述反向传播算法为了减少公共子表达式的计算量 ,并没有考虑存储的开销。这避免了重复子表达式的指数级的增长。
- 某些算法可以通过对计算图进行简化从而避免更多的子表达式。
- 有些算法会重新计算这些子表达式而不是存储它们,从而节省内存。
2.3 反向传播示例
对于 ,将公式拆分成 和 ,则有:
根据链式法则,有 。
假设 ,则计算图如下。其中:绿色为前向传播的值,红色为反向传播的结果。
前向传播,计算从输入到输出(绿色);反向传播,计算从尾部开始到输入(红色)。
在整个计算图中,每个单元的操作类型,以及输入是已知的。通过这两个条件可以计算出两个结果:
- 这个单元的输出值。
- 这个单元的输出值关于输入值的局部梯度比如 和 。
每个单元计算这两个结果是独立完成的,它不需要计算图中其他单元的任何细节。
但是在反向传播过程中,单元将获取整个网络的最终输出值(这里是 )在单元的输出值上的梯度,即回传的梯度。
链式法则指出:单元应该将回传的梯度乘以它对其输入的局部梯度,从而得到整个网络的输出对于该单元每个输入值的梯度。如: 。
在多数情况下,反向传播中的梯度可以被直观地解释。如:加法单元、乘法单元、最大值单元。
假设: ,前向传播的计算从输入到输出(绿色),反向传播的计算从尾部开始到输入(红色)。
加法单元 ,则 。如果 ,则有:
这表明:加法单元将回传的梯度相等的分发给它的输入。
乘法单元 ,则 。如果 ,则有:
这表明:乘法单元交换了输入数据,然后乘以回传的梯度作为每个输入的梯度。
取最大值单元 ,则:
如果 ,则有:
这表明:取最大值单元将回传的梯度分发给最大的输入。
通常如果函数 的表达式非常复杂,则当对 进行微分运算,运算结束后会得到一个巨大而复杂的表达式。
- 实际上并不需要一个明确的函数来计算梯度,只需要如何使用反向传播算法计算梯度即可。
- 可以把复杂的表达式拆解成很多个简单的表达式(这些表达式的局部梯度是简单的、已知的),然后利用链式法则来求取梯度。
- 在计算反向传播时,前向传播过程中得到的一些中间变量非常有用。实际操作中,最好对这些中间变量缓存。
2.4 深度前馈神经网络应用
给定一个样本,其定义代价函数为 ,其中 为神经网络的预测值。
考虑到正则化项,定义损失函数为: 。其中 为正则化项,而 包含了所有的参数(包括每一层的权重 和每一层的偏置 )。
这里给出的是单个样本的损失函数,而不是训练集的损失函数。
计算 的计算图为:
前向传播用于计算深度前馈神经网络的损失函数。算法为:
输入:
网络层数
每一层的权重矩阵
每一层的偏置向量
每一层的激活函数
也可以对所有的层使用同一个激活函数
输入 和对应的标记 。
隐层到输出的函数 。
输出:损失函数
算法步骤:
初始化
迭代:,计算:
- 计算 , 。
反向传播用于计算深度前馈网络的损失函数对于参数的梯度。
梯度下降算法需要更新模型参数,因此只关注损失函数对于模型参数的梯度,不关心损失函数对于输入的梯度 。
根据链式法则有: 。
考虑到 ,因此雅可比矩阵 为对角矩阵,对角线元素 。 表示 的第 个元素。
因此 ,其中 表示
Hadamard
积。因为 ,因此:
上式仅仅考虑从 传播到 中的梯度。 考虑到损失函数中的正则化项 包含了权重和偏置,因此需要增加正则化项的梯度。则有:
因为 ,因此: 。
反向传播算法:
输入:
- 网络层数
- 每一层的权重矩阵
- 每一层的偏置向量
- 每一层的激活函数
- 输入 和对应的标记
输出:梯度
算法步骤:
通过前向传播计算损失函数 以及网络的输出 。
计算输出层的导数: 。
这里等式成立的原因是:正则化项 与模型输出 无关。
计算最后一层隐单元的梯度: 。
迭代: ,迭代步骤如下:
每一轮迭代开始之前,维持不变式: 。
计算 : 。
令: 。
计算对权重和偏置的偏导数:
计算 : 。
令: 。