梯度与梯度下降
首先,梯度是一个向量,指向函数在某点上增长最快的方向,那么梯度的负方向,也就是负梯度,指向函数值下降最快的方向
在模型训练中,我们会定义一个损失函数$L(\theta)$,等于模型输出与真实标签之间的差异,我们希望找到一组参数$\theta$,使得损失最小,这就变成了一个最优化问题minimize $L(\theta)$,于是我们用梯度下降法$\theta \leftarrow \theta - \alpha \cdot \nabla L(\theta)$,意义就是每次沿着负梯度方向走一点,逐步让损失减少,逼近局部极小值或者鞍点
方法 | BGD(Batch Gradient Descent) | SGD(Stochastic Gradient Descent) | Mini-batch Gradient Descent |
---|---|---|---|
每次更新用数据量 | 全部样本 | 一个样本 | 一部分样本(如 32、64) |
梯度估计 | 精确,无噪声 | 噪声大,变化剧烈 | 有一定噪声,平衡两者 |
更新频率 | 每轮 1 次 | 每轮 $n$ 次($n$ 为样本数) | 每轮 $n / b$ 次($b$ 为 batch 大小) |
收敛路径 | 平滑、稳定 | 抖动、震荡明显 | 相对平滑,偶有波动 |
收敛速度 | 慢(每步贵) | 快(每步便宜) | 快速而稳定 |
最终精度 | 高,容易收敛到最优点 | 较低,常震荡于最优点附近 | 高,可精确收敛 |
是否能跳出局部最优 | 难(因无噪声) | 容易(噪声大可扰动) | 适中(适度噪声) |
资源占用 | 高(需一次加载所有数据) | 低(单样本) | 中等(小批量) |
实现复杂度 | 简单 | 简单 | 稍复杂(需划分 batch) |
实用性(深度学习) | 差(不常用) | 中(用于在线学习或高频任务) | 高(主流方法,适合 GPU 并行) |
学习率及其影响
上述公式中的$\alpha$也就是学习率,控制步长,影响收敛的速度,稳定性和最终性能
过大:参数更新步长过大,可能导致模型在损失函数极小值附近震荡(来回跳跃,无法收敛);更严重时会导致训练过程发散(不断越过最优解,甚至Loss越来越大)
过小:虽然模型在理论上可以收敛,但是收敛速度极慢,训练迭代次数大大增加,耗时耗资源;再者因为步子小,难以跳出陷阱,所以更容易陷入局部极小值或鞍点,对于非凸函数而言,陷入局部极小值或鞍点就意味着提前停止优化,导致模型性能不佳(言外之意,如果是凸函数梯度降到0后,停止了也无所谓,因为不存在鞍点,已经达到了全局极小值)
AdaGrad
AdaGrad 是最早提出的自适应学习率算法,思想是:历史梯度大 → 降低学习率,避免震荡;历史梯度小 → 保持学习率,继续优化。
更新公式:
- 累积梯度平方:
$$ G_t = G_{t-1} + g_t^2 $$ - 参数更新:
$$ \theta_{t+1} = \theta_t - \frac{\alpha}{\sqrt{G_t + \epsilon}} \cdot g_t $$
其中:
- $g_t$:当前梯度
- $G_t$:历史梯度平方累积
- $\epsilon$:防止除以 0 的小常数
优点:
- 自适应调整每个参数的学习率
- 稀疏特征效果好(如 NLP)
缺点:
- 学习率会一直减小,后期可能“停止学习”
RMSProp
RMSProp 是对 AdaGrad 的改进,用滑动平均代替累积和,避免学习率过早衰减。
更新公式:
- 指数加权平均梯度平方:
$$ r_t = \rho \cdot r_{t-1} + (1 - \rho) \cdot g_t^2 $$ - 参数更新:
$$ \theta_{t+1} = \theta_t - \frac{\alpha}{\sqrt{r_t + \epsilon}} \cdot g_t $$
其中:
- $\rho$:衰减系数(通常设为 0.9)
- $r_t$:当前梯度平方的平滑值
优点:
- 始终维持较稳定的局部学习率
- 适用于非凸优化(如深度神经网络)
本质: RMSProp 解决了 AdaGrad 学习率“衰减太快”的问题,让参数能持续更新。
动量法
Momentum 是为了解决震荡与收敛慢问题,引入“惯性”概念:当前更新方向受过去梯度影响。
更新公式:
- 累积梯度动量:
$$ v_t = \beta \cdot v_{t-1} + (1 - \beta) \cdot g_t $$ - 参数更新:
$$ \theta_{t+1} = \theta_t - \alpha \cdot v_t $$
其中:
- $v_t$:当前动量(方向)
- $\beta$:动量因子(一般为 0.9)
优点:
- 加速收敛(方向一致时)
如果当前和历史梯度方向一致,$v_t$ 趋于加大(增强“信号”);如果方向反复变化,$v_t$ 被抵消,趋于减小(抑制“噪声”);所以 Momentum 在方向稳定的平滑区域加速收敛,而在不稳定区域自适应减速。
- 可减缓梯度震荡(如锯齿函数、鞍点处)
当梯度方向频繁来回变动(如锯齿函数的左右跳动),Momentum 会平滑更新方向,当前 $g_t$ 与历史 $v_{t-1}$ 方向相反时,它们在 $v_t$ 中部分抵消,这让更新方向更加稳定,不跟着瞬时梯度乱跳
例如:梯度一会儿是 +1,一会儿是 -1,GD 就会左右大幅震荡,Momentum 会自动平滑成趋近 0 的小更新,使路径更“直”
- 突破鞍点(局部平缓区)
在鞍点或者局部极小值点区域(梯度为 0,但不是最小值),GD 因当前梯度接近 0,更新几乎停止,Momentum 因历史梯度仍有积累,$v_t$ 不为 0,能继续滑出困境
Adam
Adam 是目前最常用的优化器,结合了:
- Momentum: 提供稳定方向
- RMSProp: 提供自适应步长
一阶矩估计(First Moment Estimate)
一阶矩是指 梯度的期望,即动量的思想:记录梯度的“平均方向”。
Adam 中的表示方式为:
$$
m_t = \beta_1 \cdot m_{t-1} + (1 - \beta_1) \cdot g_t
$$
- $m_t$ 是当前时刻的动量(类似 Momentum);
- $\beta_1$ 是动量衰减系数,通常取 0.9;
- 本质是梯度的 指数加权平均(Exponential Moving Average);
- 目的:平滑震荡梯度,指引更新方向。
加速收敛:通过动量机制保留历史梯度方向,减少震荡,使参数更新更稳定;
捕捉梯度趋势:在非凸优化问题中,帮助模型避开局部最小值,向全局最优方向移动
二阶矩估计(Second Moment Estimate)
二阶矩是指 梯度平方的期望,即对梯度的尺度做估计,用来调整学习率。
Adam 中的表示方式为:
$$
v_t = \beta_2 \cdot v_{t-1} + (1 - \beta_2) \cdot g_t^2
$$
- $v_t$ 是当前时刻的平方梯度平均(来自 RMSProp);
- $\beta_2$ 是衰减系数,通常取 0.999;
- 目的:估计梯度的“波动程度”,调整每个参数的自适应学习率。
自适应学习率:根据梯度方差调整步长,梯度变大时,学习率自动变小,防止震荡;梯度变小时,学习率增大,加快收敛
处理稀疏梯度:对稀疏数据(NLP任务)中的低频参数分配更大更新步长,提升训练效率
偏差修正(Bias Correction)
Adam 初始化时,$m_0 = 0$ 和 $v_0 = 0$,所以在前几步迭代中:
- $m_t$ 和 $v_t$ 被低估,尤其是在 $t$ 很小时;
- 为了纠正这个初始偏小的问题,引入了偏差修正项:
修正后的动量和平方项为:
$$
\hat{m}_t = \frac{m_t}{1 - \beta_1^t}, \quad \hat{v}_t = \frac{v_t}{1 - \beta_2^t}
$$
- 当 $t$ 较小时,$\beta_1^t$ 接近 0,修正效果显著;
- 当 $t$ 较大时,$\beta_1^t$ 接近 1,修正趋于无效。
整合三者后,Adam 的参数更新为:
$$
\theta_{t+1} = \theta_t - \alpha \cdot \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon}
$$
- 分子是平滑方向(动量);
- 分母是自适应步长;
- 加上 $\epsilon$ 是为了避免除 0(通常设为 $10^{-8}$)。
任务 | 符号 | 作用 |
---|---|---|
一阶矩估计 | $m_t$ | 平滑梯度方向,控制方向变化 |
二阶矩估计 | $v_t$ | 平滑梯度幅度,自适应步长 |
偏差修正 | $\hat{m}_t$, $\hat{v}_t$ | 修正初期估计偏小,提高稳定性 |
学习率常用的调度策略
固定学习率(Constant LR)
- 学习率保持不变:
$$
\alpha_t = \alpha_0
$$ - 优点:实现简单;
- 缺点:前期慢,后期震荡大,难以兼顾速度与稳定性;
- 通常只用于 baseline 或短时间训练。
- 学习率保持不变:
Step Decay(阶梯式衰减)
每隔固定步数或 epoch,将学习率乘以一个常数因子:
$$
\alpha_t = \alpha_0 \cdot \gamma^{\lfloor t / k \rfloor}
$$$\gamma$:衰减因子,如 0.1;
$k$:衰减周期,如每 10 轮。
优点:可控、实现简单;
缺点:变化不连续,可能引发梯度突变。
Exponential Decay(指数衰减)
每一步都按指数衰减:
$$
\alpha_t = \alpha_0 \cdot e^{-\lambda t}
$$或简化为:
$$
\alpha_t = \alpha_0 \cdot \gamma^t
$$优点:比 Step Decay 平滑;
缺点:衰减可能过快,需设置好初始值与 $\gamma$。
Cosine Annealing(余弦退火)
学习率呈余弦下降趋势:
$$
\alpha_t = \alpha_{\text{min}} + \frac{1}{2}(\alpha_0 - \alpha_{\text{min}})(1 + \cos(\frac{t}{T} \pi))
$$可以配合 Restart(重启) 策略使用(SGDR);
优点:训练后期学习率变化更加细腻,利于 fine-tune;
应用于如 ResNet、Transformer 等模型训练中。
Warm-up(预热)
一开始使用较小学习率,然后逐渐升高,再转入正常调度策略;
典型线性 warm-up:
$$
\alpha_t = \alpha_0 \cdot \frac{t}{T_{\text{warmup}}}, \quad t \leq T_{\text{warmup}}
$$常与 AdamW、Transformer 一起使用;
目的:避免训练初期权重剧烈更新导致发散。
ReduceLROnPlateau(性能平稳时降低)
- 当验证集 loss 在若干 epoch 内不下降时,自动降低学习率:例如:
patience=5, factor=0.1
- PyTorch / Keras 均内置该策略;
- 优点:自适应触发,智能控制收敛过程;
- 缺点:需监控指标,不适合无验证集训练。
- 当验证集 loss 在若干 epoch 内不下降时,自动降低学习率:例如:
Cyclical Learning Rate(周期性学习率)
学习率在 [low, high] 区间周期性震荡:
$$
\alpha_t = \text{cyclical}(t)
$$增强探索性,可能帮助跳出局部最优;
在某些场景(如小模型、局部最小值密集区域)下表现好;
常与 momentum 一起调制(CLR + momentum scheduling)。
Lipschitz条件
Lipschitz 条件是一种对函数“变化速度”的约束,表示函数不会“跳得太快”。
一个函数 $f(x)$ 满足 $L$-Lipschitz 连续,指对于任意 $x, y$,有:
$$
|f(x) - f(y)| \leq L |x - y|
$$
- $L$ 是 Lipschitz 常数,衡量最大“斜率”;
- 如果 $L$ 越小,函数越平滑;
- 如果 $f$ 可导,该条件等价于:$|\nabla f(x)| \leq L$
梯度 Lipschitz 连续(Gradient Lipschitz)
如果 $f(x)$ 是光滑的,我们关注的是梯度的 Lipschitz 连续性:
$$
|\nabla f(x) - \nabla f(y)| \leq L |x - y|
$$
- 表示梯度变化不太剧烈(即 Hessian 的谱范数有上界);
- $L$ 是梯度 Lipschitz 常数,常在一阶优化中设为学习率上限;
- 多数优化器默认函数满足这个条件(特别是凸优化理论)。
Lipschitz 条件与学习率的关系
在最经典的梯度下降中,如果损失函数的梯度是 $L$-Lipschitz 连续的:
为了保证每步不“走过头”,学习率必须满足:
$$
0 < \alpha \leq \frac{1}{L}
$$否则更新可能导致震荡或发散;
所以 $L$ 实际上决定了学习率的最大安全边界。
优化算法的理论收敛边界
这是从理论角度回答:“一个优化算法最坏情况下能收敛到多快?”
下面列出常见一阶优化器的最坏收敛边界(假设目标函数满足一定条件):
问题类型 | 算法 | 收敛速度 | 最坏误差界限 |
---|---|---|---|
一般凸函数 | 梯度下降 | 子线性 $\mathcal{O}(1/t)$ | $f(x_t) - f(x^) \leq \frac{L|x_0 - x^|^2}{2t}$ |
强凸 + 梯度 Lipschitz | 梯度下降 | 线性收敛 $\mathcal{O}(\rho^t)$ | $f(x_t) - f(x^) \leq (1 - \mu / L)^t (f(x_0) - f(x^))$ |
非凸函数 | SGD | 无保证 | 只保证 $\mathbb{E}|\nabla f(x)|^2 \leq \epsilon$ |
函数光滑 + Convex | Nesterov 加速 | $\mathcal{O}(1/t^2)$ | 更快但不稳定 |
说明:
- $L$ 是梯度 Lipschitz 常数;
- $\mu$ 是强凸常数;
- $t$ 是迭代次数;
- $\rho = 1 - \frac{\mu}{L}$ 是收敛率。
概念 | 含义 | 与优化的关系 |
---|---|---|
Lipschitz 连续 | 函数变化速度有限 | 保证更新稳定,避免跳跃 |
梯度 Lipschitz | 梯度变化速度有限 | 决定学习率上限与收敛性 |
强凸 | 函数最小值唯一且曲率有限 | 保证线性收敛 |
理论边界 | 算法最坏误差随步数下降速度 | 指导优化器设计、调参与收敛预估 |
反向传播与链式法则
为什么需要反向传播:因为我们需要通过反向传播计算神经网络中所有参数(权重,偏置)的梯度,才能用梯度下降算法更新参数,让模型学会降低损失
从最后一层向前面层传播,每一层都根据上层传下来的梯度,乘上自己的局部导数,作为链式乘积继续往下传
梯度消失
在反向传播中,梯度会连乘多个激活函数的导数,如果每一层的导数都是小于1的值,多层乘起来后就会导致最终梯度趋近于0,sigmoid激活函数的输出范围在0-1,当x很大或很小,函数值趋近于1或者0,只有中心附近有梯度,两端导数几乎为0;ReLU的导数在x大于0是就是1,所以没有梯度缩小的问题,不像sigmoid那样输出收缩在0-1之间;但是当x<=0时,导数为0,所以如果输入长期为负,会导致dead neuron问题,解决办法是Leaky ReLU等平滑版本的激活函数;在神经网络中,网络层数过深(连乘次数过多),还有如果参数初始化特别小(小权重代表前向输出趋近于0,激活函数进入饱和区,导数接近0),会造成梯度消失