1. 优化器(Optimizer)

作用

优化器负责 根据损失函数的梯度来更新模型参数,目标是逐步减小损失值,使模型逼近最优解。

核心机制

  1. 计算梯度:通过反向传播(Backpropagation)计算损失函数对模型参数的梯度。

  2. 参数更新:根据梯度方向和优化策略来调整参数。

常见优化器类型

优化器 特点 适用场景
SGD 基础随机梯度下降,无动量,直接沿负梯度方向更新参数。 简单任务,需精细调参时。
SGD + Momentum 引入动量(惯性),累积历史梯度方向,加速收敛并减少震荡。 非凸优化、存在局部极小值的场景。
Adam 结合动量(一阶矩估计)和自适应学习率(二阶矩估计),自动调整学习率。 大多数深度学习任务,默认选择。
AdamW 在Adam基础上解耦权重衰减 大规模深度学习模型
RMSprop 自适应调整学习率,对梯度平方进行指数加权平均,缓解学习率消失问题。 RNN、非平稳目标函数场景。
Adagrad 为每个参数分配独立的学习率,适合稀疏数据,但学习率会单调下降至零。 自然语言处理、稀疏特征任务。

AdamW 和 Adam 的详细对比:


  1. 权重衰减(Weight Decay)的作用

权重衰减是一种正则化方法,通过在损失函数中加入参数的 L2 范数(即权重平方和),防止模型过拟合。其公式为:

$$
L_{total}​=L_{task​}+λ⋅\frac{1}{2}​∑_i​w_i^2​
$$

其中:

  • Ltask​ 是任务损失(如交叉熵损失)。

  • λ 是权重衰减系数。

  • wi​ 是模型参数(较小的权重意味着模型不会对输入特征的微小变化过于敏感,从而降低了模型的复杂度)。

在优化过程中,权重衰减会直接影响参数的更新。

2. Adam 中的权重衰减问题

在 Adam 优化器中,权重衰减被直接添加到梯度中,导致权重衰减与自适应学习率耦合。具体表现为:

  • 权重衰减的梯度会被 Adam 的自适应学习率机制(如动量、二阶矩估计)调整。

  • 这种耦合会导致权重衰减的效果不稳定,尤其是在学习率较大时,可能无法有效防止过拟合。


3. AdamW 的改进

AdamW 将权重衰减从梯度更新中分离出来,直接作用于参数本身,而不是通过梯度调整。具体改进如下:

  1. 解耦权重衰减

    • 在 Adam 中,权重衰减被添加到梯度中:

      $$
      g_t​=∇L(w_t​)+λw_t​
      $$

    • 在 AdamW 中,权重衰减直接作用于参数:

      $$
      w_{t+1}​=w_t​−η⋅Adam(g_t​)−ηλw_t​
      $$

      其中:

      • η 是学习率。

      • Adam(gt​) 是 Adam 优化器的更新规则。

      • λ 是权重衰减系数。

  2. 更稳定的正则化效果

    • 由于权重衰减不再受自适应学习率的影响,其正则化效果更加稳定。

    • 能够更好地防止过拟合,尤其是在大规模数据集和复杂模型上。


4. AdamW 的优势

  • 更好的泛化能力:通过解耦权重衰减,AdamW 能够更有效地控制模型复杂度,提高泛化性能。

  • 更稳定的训练:权重衰减的效果不再受自适应学习率的影响,训练过程更加稳定。

  • 适用于大规模模型:在训练大规模模型(如 Transformer、BERT)时,AdamW 表现优于 Adam。


5. 使用场景

  • 推荐使用 AdamW 的场景

    • 训练大规模深度学习模型(如 Transformer、BERT)。

    • 需要较强的正则化效果(如防止过拟合)。

    • 训练过程中学习率变化较大(如使用学习率调度器)。

  • 推荐使用 Adam 的场景

    • 简单任务或小规模模型。

    • 不需要强正则化效果的任务。

Momentum(动量)

原理

momentum 借鉴了物理学中动量的概念,在优化算法(如随机梯度下降 SGD)中引入动量项可以加速收敛并减少震荡。在传统的随机梯度下降中,参数的更新仅依赖于当前计算得到的梯度。而引入动量后,参数的更新不仅考虑当前梯度,还会结合之前的更新方向。

具体来说,动量优化算法在更新参数时,会计算一个累积的梯度移动平均值。这个移动平均值就像物体的动量,它会使得梯度更新具有一定的惯性,使得在梯度方向大致不变的地方能够加速前进,而在梯度方向频繁变化的地方能够减少震荡。

作用

  • 加速收敛:当梯度方向保持一致时,动量项会不断累积,使得参数更新的步长增大,从而加快模型收敛的速度。例如,在一些鞍点或者平缓区域,传统的 SGD 可能会收敛很慢,而引入动量后可以更快地跳出这些区域。
  • 减少震荡:在梯度方向频繁变化的地方,动量项会起到平滑的作用,减少参数更新的震荡,使得模型的训练过程更加稳定。

定义优化器

optimizer = optim.Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999))
optimizer = optim.AdamW(model.parameters(), lr=0.001, weight_decay=0.01)

2. 学习率调度器(Learning Rate Scheduler)

作用

学习率调度器在训练过程中 动态调整学习率,平衡收敛速度与稳定性,避免陷入局部极小值。

核心机制

  • 学习率衰减:随着训练进行,逐步减小学习率,使模型在后期更精细地调整参数。

  • 周期性调整:通过周期性变化的学习率,帮助模型跳出局部极小值。

常见调度器类型

调度器 特点 适用场景
StepLR 每隔固定epoch将学习率乘以衰减因子(如每10个epoch学习率×0.1)。 简单任务,稳定收敛。
CosineAnnealingLR 按余弦函数周期性调整学习率,从初始值下降到最小值再回升,帮助跳出局部极小。 存在多个局部极小值的复杂优化场景。
ReduceLROnPlateau 监控验证集损失,当损失不再下降时自动降低学习率。 需要自适应调整学习率的任务。
OneCycleLR 结合线性增长和余弦退火,在训练中先升后降学习率,加速收敛并提高泛化能力。 快速训练(如图像分类)。
ExponentialLR 每个epoch按指数衰减学习率(如学习率×0.95)。 需要平滑衰减的场景。

示例(Poly学习策略)

def poly_lr(epoch):
return (1 - epoch / total_epochs) ** power

scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=poly_lr)

其它:

optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=100, eta_min=1e-6)

3. 优化器与调度器的协同工作

训练流程

  1. 前向传播:输入数据计算预测值。

  2. 计算损失:比较预测值与真实值的差异。

  3. 反向传播:计算损失对参数的梯度。

  4. 优化器更新:根据梯度更新参数。

  5. 调度器调整:按策略更新学习率(通常在每个epoch或batch后)。

代码示例

python

复制

for epoch in range(num_epochs):
model.train()
for batch in train_loader:
inputs, labels = batch
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step() # 优化器更新参数

# 每个epoch后调整学习率
scheduler.step()

4. 选择优化器和调度器的策略

优化器选择

  • 默认选择:优先尝试 Adam(自适应学习率,适用于大多数任务)。

  • 精细调优:使用 SGD + Momentum(需要手动调参,但可能达到更高精度)。

调度器选择

  • 简单任务:使用 StepLR 或 ExponentialLR

  • 复杂优化:使用 CosineAnnealingLR 或 OneCycleLR

  • 自适应调整:使用 ReduceLROnPlateau(依赖验证集监控)。


5. 实际应用技巧

  1. 学习率预热(Warmup)
    训练初期逐步增大学习率,避免初始梯度不稳定(尤其适用于大模型)。

  2. 权重衰减(Weight Decay)
    在优化器中加入L2正则化,防止过拟合(如AdamW优化器)。

  3. 梯度裁剪(Gradient Clipping)
    限制梯度幅值,防止梯度爆炸(常见于RNN)。


总结

  • 优化器:决定如何利用梯度更新参数,直接影响收敛速度和稳定性。

  • 调度器:动态调整学习率,平衡探索(大学习率)与开发(小学习率)。

  • 协同作用:合理搭配优化器和调度器,可显著提升模型性能和训练效率。

batch_size

batch_size(批量大小)不同会显著影响模型的训练结果,下面从收敛速度、泛化能力、内存使用等多个方面详细分析其影响:

对收敛速度的影响

  • 较大的 batch_size
    • 通常情况下,较大的 batch_size 能让梯度计算更稳定。因为它基于更多样本的信息来更新模型参数,梯度估计的方差较小,使得参数更新的方向更接近真实的最优方向。这样在训练初期,模型可能会更快地朝着最优解的方向前进。
    • 例如,在大规模图像分类任务中,使用较大的 batch_size(如 256 或 512)可以让模型在较少的迭代次数内达到较高的准确率。
    • 然而,当接近最优解时,较大的 batch_size 可能会导致模型越过最优解,难以收敛到精确的最优值,因为每次更新的步长相对较大。
  • 较小的 batch_size
    • 较小的 batch_size 使得梯度估计的方差较大,每次参数更新的方向可能会有较大波动。但这种随机性也可以帮助模型跳出局部最优解,有可能找到更优的全局最优解。
    • 不过,由于梯度不稳定,模型的收敛速度可能会较慢,需要更多的迭代次数才能达到较好的训练效果。例如,在一些复杂的生成对抗网络(GAN)训练中,较小的 batch_size(如 16 或 32)可以增加训练的随机性,有助于生成更真实的样本。

对泛化能力的影响

  • 较大的 batch_size
    • 可能会导致模型过拟合。因为较大的 batch_size 会使模型在训练过程中对数据的统计特征学习得过于精细,容易记住训练数据中的噪声和特定模式,而忽略了数据的一般性规律。
    • 例如,在图像识别任务中,如果 batch_size 过大,模型可能会对训练集中某些图像的特殊特征过度敏感,而在测试集上表现不佳。
  • 较小的 batch_size
    • 一般能提高模型的泛化能力。较小的 batch_size 引入的随机性使得模型在不同的小批量数据上学习,能够更好地捕捉数据的多样性,从而在测试集上表现出更好的泛化性能。

对内存使用和训练时间的影响

  • 较大的 batch_size
    • 需要更多的内存来存储每个批次的数据和中间计算结果。如果显存有限,可能会导致内存溢出的错误。
    • 但由于每次迭代处理的样本数量较多,在一定程度上可以减少训练所需的迭代次数,从而可能缩短总的训练时间。
  • 较小的 batch_size
    • 内存占用较少,适合在显存较小的设备上训练模型。
    • 然而,由于需要更多的迭代次数才能完成训练,总的训练时间可能会更长。