在深度神经网络训练过程中,有四个关键组件直接影响模型的学习能力和收敛速度。这些组件协同工作,共同决定了模型从数据中提取特征和更新权重的效率。理解它们的运作机制和相互关系,是调参和模型优化的基础。
激活函数决定了神经元的输出特性,为网络引入非线性因素;优化器控制着参数更新的策略和方向;学习率作为超参数调节着每次更新的步长;而梯度则反映了参数对损失函数的敏感程度。这四个要素构成了深度学习训练过程的核心闭环系统。
Sigmoid函数(σ(x) = 1/(1+e^-x))曾经是神经网络的首选激活函数,它将输入压缩到(0,1)区间,适合表示概率。但在实践中发现存在两个主要问题:一是容易导致梯度消失(当输入绝对值较大时梯度接近0),二是输出不以0为中心会影响权重更新效率。
Tanh函数(tanh(x) = (e^x - e^-x)/(e^x + e^-x))解决了输出不以0为中心的问题,将输出范围扩展到(-1,1),但梯度消失问题依然存在。这两个函数在深层网络中表现不佳,现在主要用于特定的输出层场景。
ReLU(Rectified Linear Unit,f(x)=max(0,x))因其简单有效成为当前最常用的激活函数。它在正区间的梯度恒为1,有效缓解了梯度消失问题,计算也非常高效。但ReLU存在"神经元死亡"问题——当输入为负时梯度为0,这些神经元可能永远无法被激活。
针对ReLU的缺点,研究者提出了多种改进版本:
实际经验:在深层网络中,Swish和Mish激活函数往往能取得比ReLU更好的效果,但计算成本略高。对于大多数常规任务,ReLU及其变体仍然是性价比最高的选择。
选择激活函数需要考虑以下因素:
常见搭配方案:
最基础的批量梯度下降(BGD)每次使用全部数据计算梯度,虽然方向准确但计算成本高且容易陷入局部最优。随机梯度下降(SGD)每次随机选择一个样本,虽然计算高效但更新方向波动大。
小批量梯度下降(Mini-batch GD)折衷了前两者的优缺点,成为实际应用中的标准做法。但传统SGD存在几个问题:学习率难以选择、所有参数使用相同学习率、容易陷入鞍点等。
Momentum(动量法)引入了物理中的动量概念,使更新方向具有惯性,有助于加速收敛并减少震荡。其更新公式为:
v_t = γv_{t-1} + η∇J(θ)
θ = θ - v_t
其中γ通常取0.9,控制历史梯度的衰减程度。
RMSprop通过调整学习率来解决不同参数尺度差异问题,对频繁更新的参数使用较小的学习率,反之亦然。其核心思想是对梯度平方进行指数移动平均。
Adam(Adaptive Moment Estimation)结合了Momentum和RMSprop的优点,同时计算梯度的一阶矩估计和二阶矩估计,并进行偏差校正。其更新步骤如下:
其中β1通常取0.9,β2取0.999,ε为防止除零的小常数(如1e-8)。
| 优化器 | 收敛速度 | 内存占用 | 超参数敏感度 | 适用场景 |
|---|---|---|---|---|
| SGD | 慢 | 低 | 高 | 凸优化 |
| SGD+Momentum | 中等 | 低 | 中 | 需要稳定收敛 |
| Adagrad | 初期快 | 高 | 低 | 稀疏数据 |
| RMSprop | 快 | 中 | 中 | RNN网络 |
| Adam | 很快 | 中 | 低 | 大多数DL任务 |
| AdamW | 快 | 中 | 低 | 需要更好泛化 |
实际经验:Adam虽然通常表现良好,但在某些任务上可能导致泛化性能下降。近期研究表明,使用带动量的SGD配合适当的学习率调度,有时能获得更好的最终性能。对于新任务,建议先尝试Adam,再考虑SGD+Momentum。
学习率η决定了每次参数更新的步长大小。过大的学习率会导致震荡甚至发散,过小的学习率则会使训练缓慢甚至停滞。理想的学习率应该能够快速下降同时又不引起震荡。
学习率与梯度下降的关系可以通过泰勒展开理解。假设损失函数J(θ)在当前参数θ处可微,则更新后的损失为:
J(θ-η∇J) ≈ J(θ) - η||∇J||² + O(η²)
要使损失下降,需要η||∇J||²占主导,这意味着η不能太大。但η太小会导致进展缓慢。
固定学习率是最简单的方式,但难以适应训练不同阶段的需求。常见的学习率调度方法包括:
阶梯下降:在预设的epoch将学习率乘以衰减系数
python复制scheduler = StepLR(optimizer, step_size=30, gamma=0.1)
指数衰减:学习率按指数规律连续下降
python复制scheduler = ExponentialLR(optimizer, gamma=0.95)
余弦退火:学习率按余弦函数从初始值降到0
python复制scheduler = CosineAnnealingLR(optimizer, T_max=100)
带重启的余弦退火:周期性重置学习率
python复制scheduler = CosineAnnealingWarmRestarts(optimizer, T_0=50)
单周期策略:先线性增加再余弦下降
python复制scheduler = OneCycleLR(optimizer, max_lr=0.1, total_steps=100)
对于训练初期,学习率预热(Learning Rate Warmup)可以避免梯度不稳定。常见做法是在前几个epoch或steps内线性增加学习率。
自适应方法如Adam已经包含了学习率的自动调整,但全局学习率仍然需要设置。一个经验法则是:
调参技巧:使用学习率范围测试(LR Range Test)可以快速找到合适的学习率范围。方法是进行短时间训练,将学习率从很小值线性增加到很大值,观察损失变化曲线,选择损失下降最快的区间。
梯度∇J(θ)表示损失函数J对参数θ的变化率,指向J增长最快的方向。反向传播算法通过链式法则高效计算深层网络中所有参数的梯度。
考虑一个简单网络:输入x,隐藏层h=σ(W1x+b1),输出ŷ=W2h+b2,损失J=1/2(y-ŷ)²。其梯度计算过程为:
其中⊙表示逐元素相乘,σ'是激活函数的导数。
梯度消失:在深层网络中,梯度通过多个小于1的导数连乘会变得极小,导致底层参数几乎不更新。解决方案包括:
梯度爆炸:梯度值过大导致更新步长过大。解决方案包括:
除了基于梯度的一阶优化方法,还有利用Hessian矩阵(二阶导数)的优化方法如:
这些方法收敛更快但计算成本高,适合参数较少的情况。近年来出现了适合深度学习的二阶优化方法如K-FAC,但仍不如一阶方法普及。
这四个核心组件之间存在复杂的相互作用:
问题:训练损失不下降
可能原因:
问题:训练损失震荡大
可能原因:
问题:验证集表现差
可能原因:
近期研究趋势包括:
对于实践者的建议: