自学内容网 自学内容网

【分布式训练(6)】深入理解多卡训练时 training steps, epoch 的相关概念

【分布式训练 debug】VS Code Debug 技巧:launch.json实用参数
【分布式训练(2)】深入理解 DeepSpeed 的 ZeRO 内存优化策略 (三阶段的区别)
【分布式训练(3)】accelerator + deepspeed debug 报错 “Timed out waiting for debuggee to spawn“ 解决方法✅
【分布式训练(4)】accelerator.sync_gradients 和 checkpointing 深入理解
【分布式训练(5)】无法 kill PID?如何 kill 休眠中的 GPU 占用进程

概念

不同于单卡训练,注意要考虑 Batch Size 是总的还是每张 GPU 的。

概念定义关系与说明
Train Batch Size每次迭代用于训练模型的数据样本总数。总批量大小,可以分布在多个GPU上。
Batch Size per GPU每个GPU上每次迭代用于训练模型的数据样本数。如果使用多个GPU,train batch size = (batch size per GPU) × (GPU数量)
Step一次前向传播和一次反向传播的完整过程。每次参数更新,一个train batch size包含多个steps(如果使用梯度累积)。
Epoch模型完整地在训练集上训练一遍。一个epoch包含多个steps,具体数量取决于train batch size。

例如,假设我们有以下情况:

  • Train Batch Size: 1000
  • Batch Size per GPU: 250
  • GPU数量: 4

那么在一个epoch中:

  • 每个GPU将处理250个样本的批量。
  • 总共有1000个样本被用来更新模型一次,这意味着在不考虑最后一个不完整的批量的情况下,每个epoch包含1000个step
  • 如果使用梯度累积,可能需要多个step的梯度累积起来再进行一次参数更新。

这样,我们就可以在多GPU环境中更有效地利用硬件资源,加速训练过程。同时,通过调整train batch sizebatch size per GPU,我们可以控制每次更新模型时使用的数据量,进而影响模型训练的稳定性和收敛速度。

相关分布式训练代码理解

文本以 flux 的微调训练代码为例 https://github.com/XLabs-AI/x-flux/blob/main/train_flux_deepspeed.py

dataloader 部分
    train_dataloader = loader(**args.data_config)
    # Scheduler and math around the number of training steps.
    overrode_max_train_steps = False
    num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps)
  1. train_dataloader 是一个数据加载器,用于在训练过程中按批次加载训练数据。
    • 这个 dataloader 会有每次加载的数据数量:batch size。
    • 以及总数据集(文图对)中图像/文本的总数量:len(train_dataloader) 。
  2. args.gradient_accumulation_steps 是一个超参数,表示在**进行一次参数更新之前要累积的梯度步数。**也就是说,如果这个值为 k,那么模型将在 k 个批次上计算梯度,然后再进行一次更新。
  3. num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) 计算出在一个 epoch 中进行的更新步骤数。这个值是通过将总批次数除以每次更新所需的批次数来获得的。
    args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch)

通常情况下,像 args.num_train_epochs 这样的超参数应该在训练开始之前被设定为固定值,而不是在训练过程中被动态计算和赋值。并且这行代码还出现了两次一模一样的,所以合理怀疑这里写的是有点问题。

total_batch_size = args.train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps

总的 batch size = 每张 GPU 的 train_batch_size x 进程数量(GPU 数量) x 梯度累计的步数

loss 回传部分
   # Gather the losses across all processes for logging (if we use distributed training).
   avg_loss = accelerator.gather(loss.repeat(args.train_batch_size)).mean()
   train_loss += avg_loss.item() / args.gradient_accumulation_steps
  • 在分布式训练中,模型可能在多个 GPU 或多个机器上并行训练。每个进程(或设备)会计算自己的损失值。为了进行有效的监控和记录,通常需要将所有进程的损失值汇总到主进程中。
  • loss.repeat(args.train_batch_size):将当前进程计算的损失值 loss 重复 args.train_batch_size 次。这样做的目的是为了确保在后续的汇总过程中,每个样本的损失都能被正确地考虑。
    • 例如,如果当前进程的批次大小是 8,而 args.train_batch_size 是 32,那么 loss 将被重复 4 次,以便在汇总时能够反映出整个批次的损失。
  • accelerator.gather(…):accelerator.gather 是一个用于收集所有进程的张量的函数。
    • 在分布式训练中,每个进程会计算自己的损失,使用 gather 可以将这些损失值从所有进程收集到主进程。
    • 这使得主进程能够访问所有进程的损失值,以便进行后续的处理和记录。
    • .mean():在收集到所有损失值后,使用 .mean() 计算所有进程损失的平均值。这是因为在分布式训练中,通常希望得到一个全局的损失值,以便更好地监控训练过程。
  • train_loss += avg_loss.item() / args.gradient_accumulation_steps:
    • 最后,将计算得到的平均损失 avg_loss 除以 args.gradient_accumulation_steps,并累加到 train_loss 中。
    • 这是因为在使用梯度累积时,损失是累积的,实际的训练损失需要考虑到累积的步数。
  • 通过这种方式,train_loss 将反映出在当前梯度累积步骤中的平均损失。

原文地址:https://blog.csdn.net/weixin_44212848/article/details/142957625

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!