【人工智能学习之优化为什么会失败与方案建议】
- 一、优化为什么会失败?
- 1. 局部极小值和鞍点
- 2. 梯度消失/爆炸(Vanishing/Exploding Gradients)
- 2. 病态条件(Ill-Conditioning)
- 3. 参数初始化不当
- 4. 学习率不当
- 5. 过拟合(Overfitting)
- 二、直接与间接的优化方法
- 传统方法:基于梯度下降的改进
- 1. 随机梯度下降(SGD)
- 2. 动量法(Momentum)
- 3. Nesterov加速梯度(NAG)
- 现代优化器:自适应学习率与二阶方法
- 1. AdaGrad(自适应梯度)
- 2. RMSProp
- 3. Adam(自适应矩估计)
- 4. 二阶方法(如牛顿法)
- 逃离鞍点的特殊技巧
- 1. 随机扰动(Perturbed SGD)
- 2. 负曲率利用(Negative Curvature Descent)
- Hessian矩阵与逃离方向
- 模型设计与训练策略
- 1. 批归一化(Batch Normalization)
- 2. 残差连接(ResNet)
- 3. 学习率调度(Learning Rate Scheduling)
- 三、总结与实用建议
- 1. 优先选择的优化器
- 2. 逃离鞍点的组合策略
- 3. 模型训练的技巧
- 4. 实战案例
一、优化为什么会失败?
优化失败的原因多种多样,从网络设计到模型训练,每一步都有可能造成影响,被评估优秀的模型是非常严格非常精密的。
1. 局部极小值和鞍点
- 问题:在深度学习中损失不是只在局部极小值的梯度是零,还有其他可能会让梯度是零的点,比如鞍点(saddle point)。如果损失收敛在局部极小值,我们所在的位置已经是损失最低的点了,往四周走损失都会比较高,就没有路可以走了。但实际上这里可能只是一个“小水洼”,前方还有更深的“峡谷”,模型却在“水洼”处无法进一步降低损失。模型需要采取其他策略跳出“水洼”才能继续降低损失以达到更优解甚至最优解。另外对于鞍点来说,没有这个跳出“水洼”这种问题,旁边还是有路可以让损失更低的。所以只要逃离鞍点,就有可能让损失更低。
- 例子:鞍点得名于马鞍的形状。想象你坐在马鞍上:沿着马头方向(前后)是“下坡”,而沿着马背方向(左右)是“上坡”,对于鞍中心的 x x x 点而言,垂直观察前后截面可以发现 x x x 点是极大值点,垂直观察左右截面可以发现 x x x 点是极小值点,俩个方向观察同一个点却呈现不同的极值状态。所以不难理解:鞍点是一个梯度为零的点,但某些方向是极小值,另一些方向是极大值。
- 理解:【人工智能学习之局部极小值与鞍点】
2. 梯度消失/爆炸(Vanishing/Exploding Gradients)
- 问题:深层网络中,反向传播时梯度可能指数级缩小(消失)或增大(爆炸),导致参数无法有效更新。
- 例子:假设激活函数是Sigmoid,它的导数最大0.25。经过10层后,梯度可能缩小到 0.2 5 10 ≈ 1 e − 6 0.25¹⁰≈1e-6 0.2510≈1e−6,几乎为零。
- 数学:若权重矩阵 W W W 的最大特征值 λ > 1 \lambda >1 λ>1,梯度爆炸;若 λ < 1 \lambda <1 λ<1,梯度消失。
2. 病态条件(Ill-Conditioning)
- 问题:损失函数在不同方向上的曲率差异巨大(Hessian矩阵的条件数高),导致梯度下降震荡。
- 例子:想象一个狭长的山谷,沿山谷方向梯度小,垂直方向梯度大。普通梯度下降会反复横跳。
3. 参数初始化不当
- 问题:初始权重过大或过小,导致激活值饱和(如Sigmoid输出接近0或1),梯度消失。
- 例子:若权重初始化为全0,所有神经元的输出相同,反向传播时梯度也相同,失去多样性。
4. 学习率不当
- 太大:损失函数震荡甚至发散(步子太大跳过最低点)。
- 太小:收敛极慢,可能卡在平坦区域。
5. 过拟合(Overfitting)
- 问题:模型在训练集上表现好,但泛化差。本质是优化时过度拟合噪声。
- 例子:用高阶多项式拟合几个带噪声的数据点,曲线“完美”穿过所有点但毫无规律。
二、直接与间接的优化方法
如何跳出局部最优解?如何逃离鞍点?哪些优化方法行之有效?还有哪些其他的优化角度?
传统方法:基于梯度下降的改进
1. 随机梯度下降(SGD)
- 核心思想:利用mini-batch的随机性引入噪声,帮助逃离局部极小值和鞍点。
- 数学形式:
θ t + 1 = θ t − η ∇ L batch ( θ t ) \theta_{t+1} = \theta_t - \eta \nabla L_{\text{batch}}(\theta_t) θt+1=θt−η∇Lbatch(θt)
其中 ∇ L batch \nabla L_{\text{batch}} ∇Lbatch 是随机小批量数据的梯度。 - 为什么有效:
- 噪声扰动可能将参数推离平坦区域(如鞍点)。
- 在局部极小值附近,噪声可能提供“跳出”的动力。
- 局限性:噪声可能使收敛不稳定,需要精细调整学习率。
2. 动量法(Momentum)
- 核心思想:引入“动量”积累历史梯度方向,帮助冲过平坦区域。
- 数学形式:
v t = β v t − 1 + ∇ L ( θ t ) θ t + 1 = θ t − η v t v_t = \beta v_{t-1} + \nabla L(\theta_t) \\ \theta_{t+1} = \theta_t - \eta v_t vt=βvt−1+∇L(θt)θt+1=θt−ηvt
其中 β \beta β 是动量系数(通常取0.9)。 - 为什么有效:
- 逃离鞍点:在鞍点附近,梯度为零,但动量项 v t v_t vt 可能保留之前的方向,推动参数继续移动。
- 穿越局部极小值:动量积累的“惯性”可能帮助跳过狭窄的局部极小。
- 例子:想象小球滚下山坡,遇到小坑(局部极小)时,动量可能让它滚过去。
3. Nesterov加速梯度(NAG)
- 核心思想:先根据动量方向“预览”未来位置,再计算梯度。
- 数学形式:
v t = β v t − 1 + ∇ L ( θ t − η β v t − 1 ) θ t + 1 = θ t − η v t v_t = \beta v_{t-1} + \nabla L(\theta_t - \eta \beta v_{t-1}) \\ \theta_{t+1} = \theta_t - \eta v_t vt=βvt−1+∇L(θt−ηβvt−1)θt+1=θt−ηvt - 优势:比普通动量法更“聪明”,减少震荡,更快收敛。
现代优化器:自适应学习率与二阶方法
1. AdaGrad(自适应梯度)
- 核心思想:为每个参数自适应调整学习率,适合稀疏数据。
- 数学形式:
G t = G t − 1 + ( ∇ L ( θ t ) ) 2 θ t + 1 = θ t − η G t + ϵ ∇ L ( θ t ) G_t = G_{t-1} + (\nabla L(\theta_t))^2 \\ \theta_{t+1} = \theta_t - \frac{\eta}{\sqrt{G_t + \epsilon}} \nabla L(\theta_t) Gt=Gt−1+(∇L(θt))2θt+1=θt−Gt+ϵη∇L(θt)- G t G_t Gt 是历史梯度平方的累加。
- 为什么有效:
- 频繁更新的参数学习率降低(分母大),稀疏参数学习率保持较高。
- 在鞍点附近,梯度可能突然增大,自适应学习率能快速调整。
2. RMSProp
- 核心思想:改进AdaGrad,引入指数衰减平均,防止学习率过早下降。
- 数学形式:
G t = β G t − 1 + ( 1 − β ) ( ∇ L ( θ t ) ) 2 θ t + 1 = θ t − η G t + ϵ ∇ L ( θ t ) G_t = \beta G_{t-1} + (1-\beta)(\nabla L(\theta_t))^2 \\ \theta_{t+1} = \theta_t - \frac{\eta}{\sqrt{G_t + \epsilon}} \nabla L(\theta_t) Gt=βGt−1+(1−β)(∇L(θt))2θt+1=θt−Gt+ϵη∇L(θt)- 通常 β = 0.9 \beta = 0.9 β=0.9。
3. Adam(自适应矩估计)
- 核心思想:结合动量与自适应学习率(目前最常用的优化器)。
- 数学形式:
m t = β 1 m t − 1 + ( 1 − β 1 ) ∇ L ( θ t ) (一阶矩,动量) m_t = \beta_1 m_{t-1} + (1-\beta_1)\nabla L(\theta_t) \quad \text{ (一阶矩,动量)} mt=β1mt−1+(1−β1)∇L(θt) (一阶矩,动量)
v t = β 2 v t − 1 + ( 1 − β 2 ) ( ∇ L ( θ t ) ) 2 (二阶矩,自适应学习率) v_t = \beta_2 v_{t-1} + (1-\beta_2)(\nabla L(\theta_t))^2 \quad \text{ (二阶矩,自适应学习率)} vt=β2vt−1+(1−β2)(∇L(θt))2 (二阶矩,自适应学习率)
m ^ t = m t 1 − β 1 t , v ^ t = v t 1 − β 2 t (偏差修正) \hat{m}_t = \frac{m_t}{1-\beta_1^t}, \quad \hat{v}_t = \frac{v_t}{1-\beta_2^t} \quad \text{ (偏差修正)} m^t=1−β1tmt,v^t=1−β2tvt (偏差修正)
θ t + 1 = θ t − η v ^ t + ϵ m ^ t \theta_{t+1} = \theta_t - \frac{\eta}{\sqrt{\hat{v}_t} + \epsilon} \hat{m}_t θt+1=θt−v^t+ϵηm^t- 默认参数: β 1 = 0.9 , β 2 = 0.999 , ϵ = 1 e − 8 \beta_1=0.9, \beta_2=0.999, \epsilon=1e-8 β1=0.9,β2=0.999,ϵ=1e−8。
- 为什么有效:
- 动量项帮助逃离鞍点和平坦区域。
- 自适应学习率在不同参数方向调整步长,适合病态曲率。
4. 二阶方法(如牛顿法)
- 核心思想:利用Hessian矩阵的曲率信息,直接找到下降方向。
- 数学形式:
θ t + 1 = θ t − η H − 1 ∇ L ( θ t ) \theta_{t+1} = \theta_t - \eta H^{-1} \nabla L(\theta_t) θt+1=θt−ηH−1∇L(θt)- H H H 是Hessian矩阵。
- 优势:
- 在鞍点处,Hessian矩阵的负特征值方向直接给出逃离方向。
- 收敛速度快(二次收敛)。
- 局限性:
- 计算Hessian矩阵及其逆的复杂度为 O ( D 3 ) O(D^3) O(D3),不适用于深度学习(参数维度 D D D 太大)。
- 近似方法:
- L-BFGS:有限内存BFGS,适用于中小规模问题。
- K-FAC:自然梯度法的近似,用于深度学习。
逃离鞍点的特殊技巧
1. 随机扰动(Perturbed SGD)
- 核心思想:主动向参数添加噪声,增加探索能力。
- 数学形式:
θ t + 1 = θ t − η ∇ L ( θ t ) + ϵ t , ϵ t ∼ N ( 0 , σ 2 ) \theta_{t+1} = \theta_t - \eta \nabla L(\theta_t) + \epsilon_t, \quad \epsilon_t \sim \mathcal{N}(0, \sigma^2) θt+1=θt−η∇L(θt)+ϵt,ϵt∼N(0,σ2) - 为什么有效:
- 在鞍点附近,随机扰动可能将参数推到负曲率方向,从而开始下降。
- 论文支持:Google Brain的《Adding Gradient Noise Improves Learning》证明了噪声的有效性。
2. 负曲率利用(Negative Curvature Descent)
- 核心思想:显式检测负曲率方向,并沿该方向下降。
- 步骤:
- 计算Hessian矩阵的最小特征值 λ min \lambda_{\min} λmin 和对应特征向量 v v v。
- 如果
λ
min
<
0
\lambda_{\min} < 0
λmin<0,沿
v
v
v 方向更新:
θ t + 1 = θ t − η ⋅ sign ( v T ∇ L ) ⋅ v \theta_{t+1} = \theta_t - \eta \cdot \text{sign}(v^T \nabla L) \cdot v θt+1=θt−η⋅sign(vT∇L)⋅v
- 适用场景:小规模问题或理论分析。
Hessian矩阵与逃离方向
假设在鞍点
θ
∗
\theta^*
θ∗,Hessian矩阵
H
H
H 有负特征值
λ
<
0
\lambda < 0
λ<0,对应特征向量
v
v
v。沿
v
v
v 方向的更新:
θ
=
θ
∗
+
ϵ
v
⇒
L
(
θ
)
≈
L
(
θ
∗
)
+
1
2
ϵ
2
λ
<
L
(
θ
∗
)
\theta = \theta^* + \epsilon v \quad \Rightarrow \quad L(\theta) \approx L(\theta^*) + \frac{1}{2} \epsilon^2 \lambda < L(\theta^*)
θ=θ∗+ϵv⇒L(θ)≈L(θ∗)+21ϵ2λ<L(θ∗)
此时损失函数会下降,这就是逃离鞍点的数学原理。
模型设计与训练策略
1. 批归一化(Batch Normalization)
- 核心思想:标准化每层输入,减少内部协变量偏移。
- 操作:
x ^ = x − μ σ 2 + ϵ , y = γ x ^ + β \hat{x} = \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}}, \quad y = \gamma \hat{x} + \beta x^=σ2+ϵx−μ,y=γx^+β - 为什么有效:
- 保持激活值的稳定分布,防止梯度消失/爆炸。
- 允许使用更大的学习率,间接帮助逃离局部极小。
2. 残差连接(ResNet)
- 核心思想:通过跳跃连接传递原始输入,确保梯度可以直通深层。
- 数学形式:
y = f ( x ) + x y = f(x) + x y=f(x)+x - 为什么有效:
- 即使 f ( x ) f(x) f(x) 的梯度消失, x x x 的直连路径仍能传递梯度,保证了梯度不会消失。
3. 学习率调度(Learning Rate Scheduling)
- 常用策略与为什么有效:
- 预热(Warmup):初始阶段逐步增大学习率,防止早期震荡。
- 余弦退火(Cosine Annealing):利用余弦周期,周期性地重置学习率,在某一周期以较大学习率跳出局部极小。
- 周期性重启(SGDR):类似模拟退火,周期性增加学习率。
三、总结与实用建议
具体任务中的优化困境,是需要再结合代码和实验结果分析原因的。
1. 优先选择的优化器
- Adam:适合大多数任务,尤其是初始学习阶段。
- 带动量的SGD:在精细调参后可能达到更高精度(如训练ResNet)。
2. 逃离鞍点的组合策略
- 使用Adam或带动量的优化器:逃离鞍点和局部极小。
- 添加批归一化层:防止梯度消失或爆炸,稳定训练过程。
- 引入随机扰动:如梯度噪声,增加探索能力。
- 周期性放大学习率:采用如余弦退火的训练策略跳出局部极小。
3. 模型训练的技巧
- 初始化:用Xavier/He初始化,避免激活值饱和。
- 优化器:首选Adam(自适应学习率+动量),复杂任务可试RMSprop。
- 学习率调整:使用学习率预热(Warmup)或余弦退火(Cosine Annealing)。
- 监控训练:用TensorBoard跟踪损失/梯度分布,发现异常及时调整。
- 模型设计:深层网络用残差连接,激活函数用Mish/ReLU/LeakyReLU。
4. 实战案例
例一:假设你训练一个CNN时,损失卡在某个值不再下降:
- 检查梯度是否接近零(可能是鞍点或局部极小)。
- 尝试增大学习率或添加动量(帮助冲过平坦区)。
- 插入批归一化层或改用残差结构。
- 启用余弦退火学习率调度。
例二:训练一个10层全连接网络,如果损失不降,可能是梯度消失。这时可以:
- 改用He初始化;
- 添加批归一化层;
- 将Sigmoid换成ReLU;
- 选择Adam优化器。
希望这些能帮你少走弯路!