我在一个相对较小的数据集上训练一个伯特模型,不能丢失任何标记样本,因为它们都必须用于训练。由于GPU内存的限制,我使用梯度累积来训练更大的批次(例如32)。根据PyTorch documentation,梯度累积的实现如下:
scaler = GradScaler()
for epoch in epochs:
for i, (input, target) in enumerate(data):
with autocast():
output = model(input)
loss = loss_fn(output, target)
loss = loss / iters_to_accumulate
# Accumulates scaled gradients.
scaler.scale(loss).backward()
if (i + 1) % iters_to_accumulate == 0:
# may unscale_ here if desired (e.g., to allow clipping unscaled gradients)
scaler.step(optimizer)
scaler.update()
optimizer.zero_grad()
但是,如果使用110个训练样本,批次大小为8,累积步骤为4(即有效批次大小为32),则此方法仅训练前96个样本(即32 x 3),即浪费14个样本。为了避免这种情况,我想修改代码如下(注意对最终if语句的更改):
scaler = GradScaler()
for epoch in epochs:
for i, (input, target) in enumerate(data):
with autocast():
output = model(input)
loss = loss_fn(output, target)
loss = loss / iters_to_accumulate
# Accumulates scaled gradients.
scaler.scale(loss).backward()
if (i + 1) % iters_to_accumulate == 0 or (i + 1) == len(data):
# may unscale_ here if desired (e.g., to allow clipping unscaled gradients)
scaler.step(optimizer)
scaler.update()
optimizer.zero_grad()
这是正确的,真的那么简单,还是会有副作用?这对我来说似乎很简单,但我以前从未见过这样做。感谢您的帮助
我很确定我以前见过这种情况。从Pytorch Lightning(函数{}、{}和{})中查看{a1}
正如Lucas Ramos已经提到的,当使用^{} 时,底层数据集的大小不能被批大小整除,默认行为是使用较小的最后一批:
您的计划基本上是结合
drop_last=False
实施梯度累积-即最后一批比所有其他批小。因此,原则上,不同批量的培训没有什么错
但是,代码中有一些东西需要修复:
小批量的损失平均。因此,如果您以通常的方式处理小批量,则无需担心。但是,当累积梯度时,可以通过将损失除以
iters_to_accumulate
来明确地进行:在最后一个小批量(较小的大小)中,您需要更改
iter_to_accumulate
的值以反映较小的小批量大小我提出了这个修改后的代码,将训练循环分为两个:一个是小批量的外部循环,另一个是每个小批量累积梯度的内部循环。请注意,使用^{} over the ^{} 有助于将训练循环分成两部分:
相关问题 更多 >
编程相关推荐