本文针深度学习中不同的优化器进行了汇总,包括公式实现、代码示例、演变过程和优缺点做了较为详细的分析。
随机梯度下降(SGD)
随机梯度下降(SGD)是一种简单但极其有效的优化算法,经常用于训练各种类型的机器学习模型,特别是大规模数据集上的深度学习模型。SGD 的核心在于每次更新参数时只使用数据集中的一个样本或一小批样本来计算梯度,这与传统的批量梯度下降(BGD)算法相比,可以大大加快计算速度并降低内存需求。
提出的契机
在 SGD 被普遍采纳之前,批量梯度下降是最常见的优化方法,它在每一步都使用整个数据集来计算梯度并更新参数。虽然这种方法理论上可以保证在凸优化问题上收敛到全局最优解,但在面对大规模数据集时,每次迭代都需要大量的计算资源和时间。SGD 的提出正是为了解决这个问题,通过每次只使用一个样本或一小批样本来估计真实梯度,从而加速训练过程,并使得模型能够在线更新和处理大数据。
理论与公式
SGD 的基本更新公式非常简单:
- 选择初始参数 θ0\theta_0θ0 和学习率 η\etaη。
- 在每一次迭代 kkk 中,随机选择一个样本 iii(或一小批样本),计算该样本上的梯度:
g=∇θk−1Li(θ)g = \nabla_{\theta_{k-1}} L_i(\theta)g=∇θk−1Li(θ)
其中 Li(θ)L_i(\theta)Li(θ) 是在第 iii 个样本上的损失函数。 - 更新参数:
θk=θk−1−ηg\theta_{k} = \theta_{k-1} - \eta gθk=θk−1−ηg
这里没有 rkr_krk 的概念,因为 SGD 不涉及梯度累积或调整学习率的复杂机制。每次迭代直接使用当前梯度进行参数更新。
代码示例
下面是 SGD 算法的一个简单 Python 代码示例:
def sgd_update(parameters, gradients, lr=0.01):
for param, grad in zip(parameters, gradients):
param -= lr * grad
这个函数接受 parameters(模型参数列表),gradients(对应梯度列表),以及 lr(学习率)作为输入,然后使用 SGD 公式更新每个参数。
优缺点
优点
- 效率高: 由于每次只处理一个样本或一小批样本,SGD 可以快速完成迭代,特别适合大规模数据集。
- 在线学习: SGD 可以用于在线学习场景,即模型可以随着新数据的到来实时更新。
- 跳出局部最优: SGD 因为其随机性,有可能跳出局部最优,找到更好的解。
缺点
- 收敛问题: 由于每次更新只使用一个样本,SGD 的收敛过程可能会非常嘈杂,导致训练不稳定。
- 超参数调整: 学习率等超参数的选择对 SGD 性能有很大影响,而且不容易调整。
- 可能不是最优解: 在非凸优化问题上,SGD 可能只能找到局部最优解而非全局最优解。
总的来说,SGD 是一种高效且广泛应用的优化算法,尤其适用于大规模数据集。然而,其随机性也带来了一些挑战,比如可能的训练不稳定
梯度下降 + Momentum
动量梯度下降(Momentum Gradient Descent)是一种优化算法,用于训练机器学习模型,特别是神经网络模型。它是在标准梯度下降算法的基础上引入了动量概念,以解决梯度下降中的一些问题,例如局部最小值、鞍点等。
提出背景:
动量梯度下降算法的提出是为了解决传统梯度下降算法中的一些问题。
- 在高度曲折的损失函数表面上的震荡
- 收敛速度缓慢等。
通过引入动量的概念,可以在一定程度上加速收敛,并且有助于跳出局部最小值。
理论:
动量梯度下降的核心思想是引入动量因子,使得更新方向不仅取决于当前梯度,还考虑了之前更新方向的影响。这样可以在一定程度上平滑更新路径,加速收敛。
公式
- While 条件:
- g←∇θk−1L(θ)g \leftarrow \nabla_{\theta_{k-1}} L(\theta)g←∇θk−1L(θ) # 计算梯度
- wk=αwk−1+(1−α)gw_k = \alpha w_{k-1} + (1 - \alpha) gwk=αwk−1+(1−α)g # 计算动量
- θk=θk−1−ηwk\theta_{k} = \theta_{k-1} - \eta w_kθk=θk−1−ηwk # 更新参数
其中:
- θk−1\theta_{k-1}θk−1是第k-1步的模型参数向量。
- ∇L(θk−1)\nabla L(\theta_{k-1})∇L(θk−1) 是损失函数 LLL 对参数 θk−1\theta_{k-1}θk−1 的梯度。
- η\etaη是学习率。
- α\alphaα是动量参数,通常取值在 0 到 1 之间,决定了历史梯度对当前更新的影响程度。
- wkw_kwk是动量,表示历史梯度的加权累积。
代码示例
下面是一个简单的 Python 代码示例,演示了如何使用动量梯度下降算法来训练一个简单的线性回归模型:
import numpy as np
def momentum_gradient_descent(params, grads, velocities, lr=0.01, momentum=0.9):
for param, grad, velocity in zip(params, grads, velocities):
velocity[:] = momentum * velocity + lr * grad
param[:] -= velocity
优缺点
优点:
- 加速收敛:动量可以帮助加速SGD在相关方向上的收敛,并抑制振荡,使得训练过程更快。
- 降低震荡:通过平滑梯度,动量方法可以减少训练过程中的震荡,使得更新过程更稳定。
- 逃离局部最小:动量的累积可以帮助算法跳出局部最小值。
缺点:
- 超参数敏感:动量系数的选择对算法的性能影响很大,需要仔细调整。
- 可能错过最小值:过大的动量可能会导致算法在最小值附近“冲过头”,从而错过最优解。
Adagrad
AdaGrad(Adaptive Gradient Algorithm)是一种自适应学习率的梯度下降算法,于2011年由Duchi等人提出。这个算法主要是为了解决标准的梯度下降算法中学习率一成不变的问题。在标准的梯度下降算法中,如果学习率过大,可能会导致算法在最小值附近震荡而不收敛;如果学习率过小,又会导致收敛速度过慢。AdaGrad算法通过自适应调整每个参数的学习率,尝试解决这个问题。
理论和公式
AdaGrad算法的核心思想是对每个参数根据其历史梯度的平方和进行自适应地调整学习率。这意味着对于出现频率高的特征,其学习率会较低;而对于出现频率低的特征,其学习率会较高。这种方式使得模型在稀疏数据上的表现更好。
AdaGrad的参数更新公式如下:
-
while 条件:
- g=∇θk−1L(θ)g = \nabla_{\theta_{k-1}} L(\theta)g=∇θ