梯度下降法 优化器
核心目标:找到函数的最小值点(或极小值点)。在机器学习中,这个函数通常是损失函数,衡量模型预测值与真实值的差距。最小化损失函数意味着让模型预测更准确。
核心思想:想象你站在一个山坡上(函数曲面),目标是尽快下到山谷最低点(最小值点)。你不知道最低点的具体位置,但你能感受到脚下山坡的最陡峭下降方向(梯度方向)。沿着这个方向走一步(更新参数),然后重新感受方向,再走一步... 如此反复,直到接近谷底。
基本原理:
-
梯度 (Gradient):
-
函数
f(θ)
在点θ
处的梯度(记作∇f(θ)
或g
)是一个向量。 -
梯度的方向指向函数在该点增长最快的方向。
-
关键结论:梯度的反方向 (
-∇f(θ)
) 就是函数在该点下降最快的方向。 -
补充知识:对于多维参数
θ = [θ₁, θ₂, ..., θₙ]
,梯度是各个偏导数组成的向量:∇f(θ) = [∂f/∂θ₁, ∂f/∂θ₂, ..., ∂f/∂θₙ]ᵀ
。
-
-
参数更新公式 (基本形式):
θ_new = θ_old - η * ∇f(θ_old)
-
θ_old
: 当前参数值(当前位置)。 -
∇f(θ_old)
: 损失函数在θ_old
处的梯度。 -
η
(eta): 学习率 (Learning Rate)。这是梯度下降中最重要的超参数之一。-
作用:控制每次更新步长的大小。
-
太小:收敛速度非常慢,需要很多步才能到达最低点。
-
太大:可能导致在最低点附近反复横跳甚至发散(越过最低点,损失反而增大),永远无法收敛。
-
-
θ_new
: 更新后的参数值(新的位置)。
-
-
迭代过程:
-
初始化参数
θ
(随机初始化或特定策略)。 -
计算当前点
θ
的梯度∇f(θ)
。 -
更新参数:
θ = θ - η * ∇f(θ)
。 -
重复步骤 2 和 3,直到满足停止条件(例如:梯度变得非常小(接近零)、损失函数变化很小、达到预设的最大迭代次数)。
-
1. 基本梯度下降法
-
批量梯度下降 (Batch Gradient Descent, BGD):
-
原理: 在每一次参数更新时,使用整个训练数据集计算损失函数的梯度
∇f(θ) = (1/m) * Σᵢ ∇L(θ; x⁽ⁱ⁾, y⁽ⁱ⁾)
(m 是样本总数)。 -
优点: 梯度方向准确,指向整个数据集上的最优下降方向。理论收敛性好。
-
缺点: 每次更新计算开销巨大(尤其大数据集),速度慢。内存可能放不下整个数据集。容易陷入局部极小值(如果损失函数非凸)。
-
适用: 数据集较小或较简单时。
-
-
随机梯度下降 (Stochastic Gradient Descent, SGD):
-
原理: 在每一次参数更新时,随机抽取一个样本
(x⁽ⁱ⁾, y⁽ⁱ⁾)
,仅用这一个样本计算梯度∇f(θ) ≈ ∇L(θ; x⁽ⁱ⁾, y⁽ⁱ⁾)
来更新参数。 -
优点: 每次更新计算量极小,速度快。可以在线学习(数据流式到来)。有噪音的梯度有时可以帮助跳出局部极小值点。
-
缺点: 梯度估计非常嘈杂(Noisy),更新方向波动大,导致损失函数下降过程震荡剧烈,收敛路径曲折。可能最终在最小值点附近徘徊而不精确收敛。需要仔细调整学习率(通常需要逐渐减小)。
-
适用: 大规模数据集。对训练速度要求高时。
-
-
小批量梯度下降 (Mini-batch Gradient Descent, MBGD):
-
原理: 最常用的梯度下降算法!在每一次参数更新时,随机抽取一小批 (Mini-batch) 样本(大小为
b
,通常32
,64
,128
,256
),用这小批样本计算平均梯度∇f(θ) ≈ (1/b) * Σⱼ ∇L(θ; x⁽ʲ⁾, y⁽ʲ⁾)
来更新参数。 -
优点: 结合了 BGD 和 SGD 的优点。梯度估计比 SGD 更稳定(噪音小),震荡减小。比 BGD 计算效率高(利用现代计算库的向量化优势)。是目前深度学习中最主流的优化算法基础。
-
缺点: 需要选择合适的小批量大小
b
(超参数)。仍然需要调整学习率。 -
适用: 绝大多数深度学习训练场景。
-
注意: 我们常说的“SGD”优化器(PyTorch 的 torch.optim.SGD
),默认指的就是 Mini-batch SGD,并且通常结合了后续介绍的动量等改进方法。纯 SGD(batch_size=1)在实践中较少单独使用。
基本 SGD(尤其是 Mini-batch SGD)存在两个主要问题:
-
震荡与收敛慢: 在山谷(损失函数等高线呈狭长峡谷状)中,梯度方向在峡谷壁之间剧烈摆动,导致沿峡谷方向(指向最小值)的进展缓慢。
-
不同参数方向的学习率需求不同: 损失函数在不同参数维度上的曲率(curvature)可能差异很大。有些方向需要小步长(高曲率,陡峭),有些方向可以承受大步长(低曲率,平缓)。固定的全局学习率
η
难以适应。
例子:用梯度下降法求函数 f(θ) = θ² + 10θ₂²
的最小值点(显然是 (0, 0)
)。我们分别用基本 SGD 和 SGD with Momentum 演示几步迭代。
设初始点 θ₀ = [-4.0, 4.0]
,学习率 η = 0.1
。
对于 Momentum,设 β = 0.9
。
在这个简单的山谷地形(θ₂ 方向曲率远大于 θ₁ 方向)中:
-
基本 SGD 在 θ₂ 方向步长过大,导致剧烈震荡(在
4.0
和-4.0
之间跳跃),严重拖慢整体收敛速度。 -
SGD with Momentum 通过累积梯度(动量),在震荡方向(θ₂)上,当前梯度会被衰减(乘以
(1-β)
)并叠加到动量中。虽然当前梯度可能很大(如第一步的80.0
),但动量项v
初始为0
且更新较慢(β=0.9
使得(1-β)=0.1
),导致实际更新步长较小。随着连续多步在震荡方向梯度符号一致(前几步都是正梯度,意味着需要减小 θ₂),动量v
在该方向上的负值(注意更新公式中的负号)会累积增大,从而加速向谷底(θ₂=0)前进,同时抑制了来回震荡。在平缓方向(θ₁),动量也帮助稳定前进。
2. 改进的梯度下降法
动量梯度下降法 (Momentum):
-
核心思想: 引入“速度”的概念。参数更新不仅依赖于当前梯度,还累积了历史梯度的(指数衰减)平均值作为动量(Momentum)。类似于小球滚下山坡,有惯性。
-
作用:
-
加速收敛: 在持续下降的方向上,动量不断累积,速度越来越快。
-
减少震荡: 在梯度方向来回摆动的维度上(如峡谷壁),正负动量会相互抵消一部分,使得更新方向更偏向于峡谷底部(最小值)的方向。帮助穿越平坦区域、减小震荡、加快峡谷方向进展。
-
v_t = β * v_{t-1} + (1 - β) * ∇f(θ_{t-1}) // 计算动量 (指数加权移动平均)
θ_t = θ_{t-1} - η * v_t // 用动量更新参数
-
v_t
: 当前时刻的速度/动量向量(与参数 θ 同维度)。 -
β
(beta): 动量衰减因子(超参数),通常取0.9
或0.99
。控制历史梯度对当前动量的贡献程度 (β
越大,历史影响越大,越平滑)。 -
∇f(θ_{t-1})
: 当前小批量梯度。 -
η
: 学习率。 -
物理比喻: 推铅球。当前梯度是你现在施加的推力,动量
v_t
是铅球当前的速度。新的速度是旧速度的衰减(β * v_{t-1}
)加上新的推力((1-β) * ∇f
)。铅球的位置θ
根据当前速度更新。
RMSprop (Root Mean Square Propagation):
-
核心思想: 自适应地调整每个参数的学习率。对梯度平方进行指数加权移动平均,用这个平均值来缩放当前梯度。梯度大的方向(可能是陡峭、震荡的方向)累积的平方和大,缩放后更新步长变小;梯度小的方向(可能是平缓、持续下降的方向)累积的平方和小,缩放后更新步长相对变大。
-
作用:
-
自适应学习率: 解决不同参数方向需要不同学习率的问题。
-
抑制震荡: 在梯度变化剧烈的方向(大梯度),分母
√(s_t + ε)
变大,有效学习率η / √(s_t + ε)
变小,抑制震荡。 -
加速平缓方向: 在梯度平缓的方向(小梯度),分母相对较小,有效学习率相对较大,加速前进。
-
s_t = ρ * s_{t-1} + (1 - ρ) * (∇f(θ_{t-1}))² // 计算梯度平方的指数加权移动平均
θ_t = θ_{t-1} - η * (∇f(θ_{t-1}) / (√s_t + ε)) // 用缩放后的梯度更新参数
-
s_t
: 当前时刻的梯度平方累积量(与参数 θ 同维度)。 -
ρ
(rho): 衰减因子(超参数),通常取0.9
或0.99
。 -
(∇f(θ_{t-1}))²
: 当前小批量梯度的逐元素平方。 -
√s_t
: 对s_t
逐元素开平方。 -
ε
(epsilon): 一个很小的常数(如1e-8
),防止除以零,增加数值稳定性。 -
η
: 全局学习率。 -
关键:
s_t
累积的是历史梯度平方,用来估计每个参数的梯度幅度的“平均值”。分母√s_t
可以看作是该参数方向上的梯度“尺度”或“波动程度”的度量。
Adam (Adaptive Moment Estimation):
-
核心思想: 结合了 Momentum (一阶矩估计) 和 RMSprop (二阶矩估计) 的优点,并进行偏差修正(Bias Correction)。是目前应用最广泛、效果最鲁棒的优化算法之一。
-
作用: 兼具 Momentum 的加速收敛和减少震荡能力,以及 RMSprop 的自适应学习率能力。偏差修正使得在训练初期(t 较小时)的估计更准确。
# 计算一阶矩(动量)估计
m_t = β₁ * m_{t-1} + (1 - β₁) * ∇f(θ_{t-1})
# 计算二阶矩(梯度平方)估计
v_t = β₂ * v_{t-1} + (1 - β₂) * (∇f(θ_{t-1}))²
# 偏差修正 (Bias Correction)
m̂_t = m_t / (1 - β₁^t)
v̂_t = v_t / (1 - β₂^t)
# 参数更新
θ_t = θ_{t-1} - η * (m̂_t / (√v̂_t + ε))
-
m_t
: 一阶矩(动量)估计的指数加权移动平均。 -
v_t
: 二阶矩(梯度平方)估计的指数加权移动平均。 -
β₁
: 一阶矩衰减因子(类似 Momentum 的 β),通常取0.9
。 -
β₂
: 二阶矩衰减因子(类似 RMSprop 的 ρ),通常取0.999
。 -
t
: 当前迭代次数(时间步)。 -
m̂_t
,v̂_t
: 经过偏差修正的一阶矩和二阶矩估计。因为m_t
和v_t
在t=0
时初始化为0
,初期估计会偏向0
,修正后更接近真实期望。 -
ε
: 小常数(如1e-8
),防止除以零。 -
η
: 全局学习率。
-
为什么好? Adam 综合了两种方法的优势,自适应效果好,鲁棒性强,通常只需要很少的超参数调优(主要是学习率
η
)。