4、深度学习基础(下):反向传播、梯度下降、优化器(SGD、Adam)、正则化与Dropout

上一讲我们把前向传播和损失函数聊透了。这一讲,咱们聊聊网络到底是怎么“学”东西的——说白了,就是怎么调整那些成千上万的权重,让损失降下来。

我刚开始做AI ISP的时候,总觉得训练网络是个黑盒子。后来亲手调了几次梯度消失和爆炸,才真正理解这些基础模块有多重要。你想想看,如果反向传播算出来的梯度是错的,那后面再怎么调优化器都是白搭。

4.1 反向传播:误差从输出层“流”回输入层

反向传播的核心思想,就是链式法则。损失函数对某一层权重的梯度,等于损失对该层输出的导数,乘以该层输出对权重的导数。一层一层往回传。

举个例子,一个简单的三层网络:输入层 → 隐藏层(ReLU) → 输出层(Sigmoid)。前向传播算出一个预测值,和真实标签算交叉熵损失。反向传播时,先算输出层的梯度,再往隐藏层传。

关键公式(链式法则):

∂L/∂w = (∂L/∂a) * (∂a/∂z) * (∂z/∂w)

其中 L 是损失,a 是激活输出,z 是线性加权和,w 是权重。

我在项目中遇到过一个问题:训练一个HDR融合网络,发现前几层的权重几乎不更新。排查了半天,原来是激活函数用了Sigmoid,梯度在深层已经饱和了。换成ReLU之后,问题立刻解决。

注意:反向传播的梯度会随着层数增加而指数级衰减或爆炸。这就是“梯度消失/爆炸”问题。Batch Normalization和残差连接(ResNet)就是用来缓解这个问题的。

4.2 梯度下降:沿着最陡的方向下山

梯度下降,说白了就是“下山”。你站在山顶(随机初始化的权重),环顾四周,找到最陡的下坡方向(负梯度方向),迈一步(更新权重),然后重复。

数学上就是:

w_new = w_old - learning_rate * gradient

学习率(learning rate)决定了每一步迈多大。步子太大,可能直接跨过最低点,甚至发散;步子太小,训练慢得像蜗牛爬。

我建议刚开始调参时,先把学习率设小一点(比如1e-3),观察损失曲线。如果下降太慢,再逐步增大。如果损失震荡或发散,立刻减小。

变体 更新方式 特点
Batch GD 用全部样本算梯度 稳定但慢,内存占用大
Stochastic GD 每次用一个样本 快但震荡大,不收敛
Mini-batch GD 每次用一个小批量 折中方案,最常用

4.3 优化器:从SGD到Adam

普通的SGD有个问题:所有参数都用同一个学习率。但实际训练中,有些参数可能需要更大的步长,有些需要更小的。这就引出了自适应优化器。

SGD + Momentum

Momentum模拟了物理中的惯性。更新时不仅考虑当前梯度,还考虑上一次的更新方向。这样能加速收敛,同时抑制震荡。

v = momentum * v - learning_rate * gradient
w = w + v

我习惯把momentum设成0.9。这个值在大部分任务上都表现不错。

Adam:自适应学习率 + Momentum

Adam是目前最常用的优化器之一。它结合了Momentum和RMSProp的优点:既考虑了梯度的一阶矩(均值),也考虑了二阶矩(方差)。

Adam的核心思想:

  • 对每个参数单独调整学习率
  • 梯度大的参数,学习率自动变小
  • 梯度小的参数,学习率自动变大
  • 加上动量,加速收敛

Adam的默认参数(lr=0.001, betas=(0.9, 0.999))在大多数任务上都能直接工作。我曾经在色彩重建任务中,直接用默认参数就收敛了,省了不少调参时间。

优化器 优点 缺点 适用场景
SGD 简单,泛化性好 收敛慢,需精细调参 大数据集,有调参经验
SGD+Momentum 加速收敛,抑制震荡 仍需要调学习率 大部分CV任务
Adam 自适应,几乎不用调参 可能泛化性略差 快速实验,新手友好
AdamW 改进了权重衰减 比Adam多一个参数 Transformer等大模型

我的建议:刚开始做实验时,先用Adam快速验证想法。等模型结构稳定了,再换成SGD+Momentum精调,往往能得到更好的泛化性能。

4.4 正则化:防止网络“死记硬背”

网络太深、参数太多,就容易过拟合——在训练集上表现很好,但在测试集上一塌糊涂。正则化就是用来防止这种情况的。

L1和L2正则化

在损失函数后面加一个惩罚项,限制权重的大小。

L2正则化:Loss_new = Loss_old + λ * Σ(w²)
L1正则化:Loss_new = Loss_old + λ * Σ|w|

L2会让权重趋向于小值,但不为零。L1会让部分权重变成0,起到特征选择的作用。

我曾经在ISP的色调映射网络中用L1正则化,发现很多卷积核的权重变成了0,网络变得非常稀疏,推理速度也快了不少。

Dropout:随机“丢弃”神经元

Dropout的原理很简单:训练时,每次前向传播都随机让一部分神经元失活(输出置0)。这样网络就不能依赖某个特定的神经元,必须学会冗余表示。

Dropout的关键参数:

  • keep_prob:保留神经元的概率。常用0.5(全连接层)或0.8(卷积层)
  • 测试时:所有神经元都参与,但输出要乘以keep_prob(或使用inverted dropout自动缩放)

嗯,这里要注意:Dropout一般只用在全连接层,卷积层后面用得少。因为卷积层的参数共享特性,本身就有一定的正则化效果。

4.5 知识结构图:深度学习训练流程

下面这张图把整个训练流程串起来了。从输入数据到前向传播,算损失,反向传播算梯度,优化器更新权重,再加上正则化防止过拟合——这就是一个完整的训练闭环。

深度学习训练流程(反向传播 + 梯度下降 + 优化器 + 正则化) 输入数据 (X, y) 前向传播 → 预测值 ŷ 计算损失 L(ŷ, y) 反向传播 → 梯度 ∂L/∂w 优化器更新权重 w 迭代直到收敛 正则化 (L1/L2/Dropout) 说明: 1. 前向传播 → 损失 → 反向传播 → 优化器更新,构成一个完整的训练迭代。 2. 正则化在损失计算时加入惩罚项(L1/L2),或在网络结构中随机丢弃神经元(Dropout)。

4.6 避坑指南:我踩过的那些坑

最后分享几个实战中容易踩的坑,都是我亲身经历过的。

  • 学习率太大导致损失NaN:我曾经把学习率设成0.1,结果训练到第10步损失就变成了NaN。后来改成1e-3,一切正常。
  • Dropout在测试时忘了缩放:有一次测试集准确率比训练集还高,我高兴了半天。后来发现是Dropout在测试时没关,输出被随机丢弃了。嗯,尴尬。
  • L2正则化系数太大:设成0.1,结果所有权重都趋近于0,网络直接“躺平”了。一般从1e-4开始调比较稳妥。
  • Adam + 权重衰减的坑:直接用Adam做L2正则化效果不好,因为Adam的自适应学习率会干扰权重衰减。建议用AdamW,它把权重衰减和自适应学习率分开了。

总结一下:反向传播是训练的基础,梯度下降是优化的手段,优化器决定了收敛速度和稳定性,正则化防止过拟合。这四个模块配合好了,你的网络才能又快又好地收敛。