梯度累积步长

wen IT资讯 26

本文目录导读:

梯度累积步长

  1. 定义
  2. 工作原理(核心)
  3. 为什么需要它?(主要用途)
  4. 代价与注意事项
  5. 如何设置?(实战建议)
  6. 总结表格

这是一个很好的技术问题,在深度学习(特别是大模型训练)中,梯度累积步长(通常称为 Gradient Accumulation Steps,简写为 gradient_accumulation_steps)是一个至关重要的参数。

它解决的是 “显存不够,但想用大批量数据训练” 的矛盾。

下面我将从定义、工作原理、为什么需要它以及如何设置这四个方面详细解释。

定义

梯度累积步长 指的是:在执行一次模型参数更新之前,需要累计多少次小批量数据(Micro-Batch)的梯度。

  • Effective Batch Size(有效批量大小) = per_device_batch_size(每个设备的小批量大小)× world_size(设备数量)× gradient_accumulation_steps(梯度累积步数)

工作原理(核心)

这里的关键在于,训练过程是分“前向传播”和“反向传播”的。

  1. 正常情况(无累积):

    • 你设置 batch_size=64
    • 硬件一次处理64个样本,计算梯度,立即更新参数。
  2. 有梯度累积(假设 steps=4):

    • 你设置 per_device_batch_size=16gradient_accumulation_steps=4
    • 流程如下:
      • 第1步(step 1): 加载16个样本 → 前向传播 → 反向传播 → 计算梯度(但不更新参数) → 将梯度累加到临时的“梯度累加器”中。
      • 第2步(step 2): 加载另外16个样本 → 前向传播 → 反向传播 → 计算梯度(但不更新参数) → 将新梯度累加到累加器中。
      • 第3步(step 3): 同第2步。
      • 第4步(step 4): 加载最后16个样本 → 前向传播 → 反向传播 → 计算梯度 → 将梯度累加到累加器中,此时累加器中已经累积了 4个16样本(即64个样本)的梯度总和
      • 优化器更新: 使用这个总梯度对模型参数进行 一次更新,然后清空梯度累加器,为下一个循环做准备。

关键点: 在累积的4步中,模型参数本身是没有被更新的,它只是在不停地计算并累加梯度,只有到了第4步,才会根据累加的总梯度,一次性调整参数。

为什么需要它?(主要用途)

  1. 突破显存限制: 这是最主要的原因,如果你的显卡显存很小(比如8GB、16GB),无法直接加载 batch_size=64 的数据(会OOM),通过将batch拆成16,走4步累积,你实际上实现了batch_size=64的效果,而每步只消耗batch_size=16的显存。

  2. 模拟更大的有效batch size: 某些模型或任务(如自监督学习SimCLR、对比学习)需要非常大的batch size(比如4096),在单卡甚至多卡都做不到时,通过梯度累积可以虚拟地实现。

  3. 更稳定的梯度估计: 使用更大的批量大小计算得到的梯度,方差更小,方向更精确,训练通常更稳定,梯度累积让你可以在小显存下获得这种优势。

代价与注意事项

  • 训练时间增加: 这是最主要的代价,因为虽然参数更新次数少了(每4步才更新一次),但 前向+反向传播的次数并没有减少,你依然需要处理相同数量的总样本(64个),所以总训练步骤数不变,但模型更新的频率降低了,总训练时间会比直接用 batch_size=64 基本一致(因为计算量一样)。batch_size=64 很快但会OOM,那累积就是唯一办法。

  • Batch Normalization (BN) 的失效: 严重问题! 如果你使用了 BatchNorm 层,梯度累积的方式会破坏BN的正常统计,因为每小步只看到小批量(16个样本),BN会基于这16个样本计算均值和方差,而不是整个64个样本的全局分布,这会导致模型性能下降。

    • 解决方法: 尽量使用 Layer Normalization (LN)(如Transformer、BERT、GPT中),它对batch大小不敏感,如果你的模型必须用BN,可以考虑使用 同步BatchNorm(SyncBN),但实现比较复杂。
  • 优化器状态更新时机: 优化器(如Adam)中的动量(Momentum)和学习率调度器(Scheduler)的“步数”是针对 参数更新次数 的。total_steps 应该设置为 总样本数 / 有效batch_size,而不是实际的前向传播步数。

  • 虚拟批次大小(Virtual Batch Size): 累积后的那个总大小被称为“虚拟批次大小”或“有效批次大小”。

如何设置?(实战建议)

  1. 第一步:确定最大物理Batch Size。 先尝试直接设置一个较小的 per_device_batch_size(2, 4, 8),看看你的显卡能跑多大而不会OOM,记下这个值。

  2. 第二步:确定目标有效Batch Size。 参考论文或经验,确定你模型需要的“有效batch size”(比如64, 128, 256)。

  3. 第三步:计算步数。 gradient_accumulation_steps = 有效Batch Size / (物理Batch Size × 显卡数量)

    • 目标有效batch=64,单卡最大物理batch=8,单卡训练,则 steps = 64 / (8 × 1) = 8
  4. 代码示例(Hugging Face Transformers Trainer):

    from transformers import Trainer, TrainingArguments
    training_args = TrainingArguments(
        output_dir="./results",
        per_device_train_batch_size=8,      # 物理batch size
        gradient_accumulation_steps=8,       # 累积8步,有效batch = 8 * 8 = 64
        num_train_epochs=3,
        # ... 其他参数
    )
    trainer = Trainer(
        model=your_model,
        args=training_args,
        train_dataset=your_dataset,
        # ...
    )

总结表格

概念 解释 类比
per_device_batch_size 每次前向传播时,单个GPU(或CPU)上处理的样本数。 每次拿取的酒杯大小。
梯度累积步长 在执行一次参数更新之前,累计多少次梯度。 积满几杯酒才倒进大桶。
Effective Batch Size 实际用于更新参数的、经过累积的总样本数。 最终倒入大桶的酒的总体积。
梯度累加器 存储累积梯度的临时变量,相当于一个中间杯子。 存储临时积分的中间桶。

一句话总结:梯度累积是用“训练时间”(步数增加)和“注意BN问题”为代价,换取在不增加硬件需求下实现大有效batch size的方法。

抱歉,评论功能暂时关闭!