pytorch 中的损失函数使用“平均”减少。因此,这意味着在给定任何批量大小的情况下,模型梯度将具有大致相同的大小。当你增加批次大小时,你想扩大学习率是有道理的,因为你的梯度不会随着你增加批次大小而变大。
对于 PyTorch 中的梯度累积,它将“求和”梯度 N 次,其中 N 是您在调用
backward()
之前调用 step()
的次数。我的直觉是这会增加梯度的幅度,你应该降低学习率,或者至少不要增加它。
但是我看到有人在this repo中写了乘法到梯度累加步骤:
if args.scale_lr:
args.learning_rate = (
args.learning_rate * args.gradient_accumulation_steps * args.train_batch_size * accelerator.num_processes
)
我在this repo中也看到了类似的代码:
model.learning_rate = accumulate_grad_batches * ngpu * bs * base_lr
我明白你为什么要通过批量大小来增加学习率。但我不明白为什么他们试图通过累积步骤的数量来提高学习率。
我发现他们确实将loss除以N(梯度累加步数)。您可以在此处查看
accelerate
包中的示例代码:https://huggingface.co/docs/accelerate/usage_guides/gradient_accumulation
注意上面指南中的以下代码行:
loss = loss / gradient_accumulation_steps
这解释了为什么你需要将学习率乘以梯度累积步骤。
我假设 PyTorch Lightning 中也会发生相同的过程。我在这里的 github 讨论中问了一个相关的 Lightning 问题:https://github.com/Lightning-AI/lightning/discussions/17035
希望后面有人回答,
Trainer
在Lightning中也是一样的除法过程。
来自加速包的证据让我认为来自不同 GPU 的梯度也是平均的,而不是求和。如果要将它们相加,每个 GPU 上的损失必须除以 GPU 的数量。
这导致了对大多数 PyTorch 训练工作流程中的梯度的简单直觉:无论批次大小,梯度始终具有大致相同的大小。如果您在 step() 调用之前检查梯度的大小,即使您改变批量大小、梯度累积步数、GPU 数量,甚至计算机数量,它也应该大致保持不变。