Neural Networks & Backpropagation
本文不会介绍神经网络的基本概念和结构,假设读者已经具备一定的基础知识,熟悉神经网络的基本组成部分,如神经元、层次结构、激活函数等。我们将使用向量微积分的视角来推导反向传播算法。
反向传播算法推导
我们以一个最简单的,只具有一层隐藏层的前馈神经网络为例来推导反向传播算法。前向传播的过程可以表示为以下几个步骤:
为了后续计算过程中我们不被导数与微分的维度搞得晕头转向,我们先明确定义好每个变量的形状:
根据前置知识部分的内容,我们可以逐步计算各个变量的梯度。为了表示的方便,我们可以定义以下几个中间变量:
我们也可以将对角阵表示为逐元素相乘的向量形式,也就是
接下来我们可以计算各个参数的梯度11 这里就全部采用了分母布局,因为梯度形式方便进行梯度下降:
我们现在推广到具有任意层数的前馈神经网络,并采用分子布局作为中间量(这样运用链式法则时维度永远正确),在最终计算梯度时再转换为分母布局。
假设第 层到第 层的前向传播过程如下:
其中 是激活函数(如 ReLU 或 Sigmoid)。为了避免维度混淆,我们明确定义变量形状(注意:这里所有向量默认为列向量):
在这个体系下,我们将误差项定义为损失函数相对于线性输出 的梯度向量(列向量):
根据链式法则,我们可以推导出误差项从后一层向当前层的反向传播公式。 我们需要计算 ,即第 层的误差:
展开其中的偏导数项, 代入后利用矩阵转置性质 ,得到递归公式:
写成逐元素相乘(Hadamard Product)的向量形式,即为核心公式:
最后,我们利用计算好的 来求当前层参数 和 的梯度。 利用外积(列向量乘行向量),我们可以一次性得到与参数矩阵形状一致的梯度矩阵:
反向传播算法
基于以上的推导,我们可以总结出反向传播算法的步骤如下:
- 初始化:进行一次前向传播,计算出所有层的线性输出 和激活输出 ,以及最终的损失 。
- 计算输出层误差:根据损失函数,计算输出层的误差项 。
- 反向传播误差:对于每一层 从 到 ,利用反向传播公式计算误差项
- 计算梯度:对于每一层 从 到 ,计算参数 和 的梯度。
- 参数更新:利用计算得到的梯度,采用梯度下降或其变种算法更新网络参数。
在这个过程中,反向传播算法有效地利用了链式法则和矩阵微分的性质,使得梯度计算的复杂度大大降低。然而这个过程中还存在许多实际的问题与可以做文章22 或者说写文章?的空间。
正则化(Regularization)
在训练神经网络时,过拟合是一个常见的问题。为了缓解过拟合,我们通常会在损失函数中加入正则化项。常见的正则化方法包括 L2 正则化(权重衰减)和 L1 正则化。以 L2 正则化为例,假设我们在损失函数中加入了正则化项:
这里 是正则化强度的超参数, 是 Frobenius 范数33 定义为。加入正则化项后,梯度计算需要相应调整:
这样,在参数更新时,正则化项会促使权重向零收缩,从而减少过拟合的风险。
注意
直观理解:为什么权重变小能防止过拟合?
上述推导说明了正则化会使权重 的数值减小,但这背后的深层逻辑在于限制了模型的灵敏度。考虑神经元的线性运算 ,如果权重 很大,输入数据中极微小的噪声扰动 就会被放大(),导致输出产生剧烈波动。这使得模型能够通过极其扭曲的函数曲线去“强行记忆”训练集中的噪声点。
引入正则化项后,权重被限制在较小的范围内,模型对输入微扰的反应变得迟钝(即 变小)。这意味着模型自动忽略了高频噪声,转而关注数据中更显著的全局趋势。从几何上看,正则化迫使决策边界变得更加平滑(Smooth),而根据奥卡姆剃刀原则,一个更平滑、简单的模型往往比复杂的震荡模型拥有更强的泛化能力。
Dropout
Dropout 是一种针对深度神经网络的正则化技术,其核心目的是通过在训练过程中随机“丢弃”(即置零)一部分神经元,打破神经元之间复杂的共适应(Co-adaptation)关系,从而显著降低模型的过拟合风险。 从宏观角度看,Dropout 等效于以极低的计算成本,同时训练了指数级数量共享权重的“稀疏网络”集合,并在测试阶段对这些网络进行近似平均。
假设神经网络中第 层的输入向量为 ,权重矩阵为 ,偏置向量为 。在标准的非线性激活函数 作用下,该层的输出为 。 引入 Dropout 后,我们在激活值输出之后应用一个二值掩码(Binary Mask)。设 为神经元的保留概率(Keep Probability,即 )。
我们可以定义一个服从伯努利分布(Bernoulli Distribution)的随机变量向量 :
该向量中的每个元素 以概率 取值为 1,以概率 取值为 0。经过 Dropout 处理后的输出 为原始输出与掩码的哈达玛积(Hadamard Product,即逐元素相乘):
随后,该稀疏化的向量将作为下一层的输入:
Dropout 的作用可以从多个层面进行理解:
注意
-
由于每次迭代都会随机生成不同的掩码 ,对于一个包含 个神经元的网络,总共存在 种可能的子网络结构。Dropout 的训练过程可以看作是在这 个共享权重的子网络上进行随机采样训练。测试过程则近似于对这些子网络的预测结果进行几何平均。
-
在普通网络中,某个神经元可能会依赖其他特定神经元的输出来纠正错误。Dropout 使得任何神经元都有可能缺席,迫使每个神经元必须在各种随机的上下文中独立提取鲁棒的特征,而不是依赖于特定的邻居节点。
训练机制
Dropout 引入了一个关键的数值缩放问题:训练时的输出是稀疏的,而测试时是稠密的。为了保证下一层神经元接收到的信号期望值在两个阶段保持一致,需要进行数值校准。根据校准发生的时间点,存在两种主流实现方式:
- 标准 Dropout
这是原始论文中提出的方法:训练时不缩放,测试时缩放。
- 训练阶段:以概率 保留神经元。此时下一层接收到的激活值期望为 。
- 测试/推断阶段:使用全连接网络,不丢弃任何神经元。为了匹配训练时的期望,必须显式地将所有权重(或输出)乘以 。
这样一来,需要在模型部署和预测时修改网络参数或计算逻辑,不够灵活。
- 反向 Dropout
这是现代深度学习框架(如 PyTorch, TensorFlow)通用的实现方式:训练时缩放,测试时不缩放。
- 训练阶段:在应用掩码后,立即将保留下来的神经元数值除以 。
- 测试/推断阶段:直接使用完整的网络结构,无需数值调整。这保持了推断代码的简洁性,模型训练完成后,参数即为最终参数,无需在部署时进行转换。
优化器:以 Adam 为例
对于一个标准的随机梯度下降(SGD)算法,其参数更新规则应当类似于
其中 是学习率,这是一个十分敏感的超参数,但是其调整往往依赖于经验和反复试验。为了缓解这个问题,研究人员提出了多种自适应学习率优化算法,其中 Adam(Adaptive Moment Estimation)是目前应用最广泛的一种。Adam 结合了动量法和 RMSProp 的优点,通过计算梯度的一阶矩估计(均值)和二阶矩估计(未中心化的方差)来动态调整每个参数的学习率。
动量(Momentum)
动量法通过引入一个动量变量 来累积过去梯度的指数加权平均,从而在更新参数时考虑了历史梯度信息。具体更新规则如下:
其中 是动量衰减系数,通常取值接近于 1(如 0.9)。动量法能够帮助参数在陡峭的梯度方向上加速收敛,同时在平坦区域减少震荡。
注意
变量 是历史梯度的指数加权移动平均值,它能够平滑掉小批量(minibatch)计算中产生的随机噪声和剧烈波动。通过利用历史梯度的惯性,各个方向上的震荡相互抵消,而主要下降方向上的梯度被加强,从而减少了更新步骤的方差。这种低方差有助于学习,因为它防止了优化路径在错误方向上过度“之字形”摆动(Zig-Zag),使模型能够沿着更加平稳、一致的路径更快地收敛到最小值。
自适应学习率 (RMSProp)
自适应学习率部分通过计算梯度的二阶矩估计 来调整每个参数的学习率。具体更新规则如下44 这里的平方操作是逐元素平方,也就是 :
这里的 代表了梯度平方的指数加权移动平均,这是一个类似于方差的量度,捕捉了梯度的变化幅度。这种二阶矩引入更新过程使得带来对不同种类参数的自适应调整:
-
如果某个参数的梯度历史值一直很大( 很大),说明它在损失平面上处于非常陡峭的方向,Adam 会通过除以一个大的值来“压低”它的步长,防止错过最小值。
-
如果某个参数的梯度历史值一直很小( 很小),说明它处于非常平坦的方向或者很少被激活,Adam 会通过除以一个极小值来“放大”它的步长,让它学得更快。
二者结合起来,动量部分确保了更新方向的稳定性和一致性,而自适应学习率部分则根据每个参数的梯度变化动态调整步长。这种组合使得 Adam 能够在各种复杂的损失平面上表现出色,既能快速收敛,又能有效避免局部最优和鞍点问题。