1、混合精度训练
混合精度训练(mixed-precision)的原理是降低部分变量和运算的精度,一般GPU默认浮点精度为32位,即每个变量占用4个字节内存,可以将浮点精度将为16位,即每个变量2个字节,于是就可以减少一半的内存占用。这样的做法不会缩减模型的规模(参数量),但会降低计算精度,提高训练速度,尤其是在支持TensorCore的GPU上。
Pytorch 1.5以后的版本均支持自动混合精度(AMP)训练,该框架可以自动识别需要全精度计算的部分,对其使用32位浮点精度运算,对其他部分则使用16位浮点运算。官方代码如下:
# Creates model and optimizer in default precision
model = Net().cuda()
optimizer = optim.SGD(model.parameters(), ...)
# Creates a GradScaler once at the beginning of training.
scaler = GradScaler()
for epoch in epochs:
for input, target in data:
optimizer.zero_grad()
# Runs the forward pass with autocasting
with autocast():
output = model(input)
loss = loss_fn(output, target)
# Scales loss. Calls backward() on scaled loss to create scaled gradients
# Backward passes under autocast are not recommended.
# Backward ops run in the same dtype autocast chose for corresponding forward ops.
scaler.scale(loss).backward()
# Scaler.step() first unscales the gradients of the optimizer's assigned params.
# If these gradients do not contain infs or NaNs, optimizer.step()is then called,
# otherwise, optimizer.step() is skipped
scaler.step(optimizer)
# Updates the scale for next iteration.
scaler.update()
2、梯度累积
梯度累积的原理比较容易理解:在优化器更新参数之前,使用相同的模型参数进行几次前向传播和反向传播;每次反向传播时计算的梯度累积(求和);若batch_size=N
,过程中累计了M
步梯度,则等效的批处理大小为N*M
。但这样做的代价是训练结果精度下降,因为有些参数不能完全累积,如Batch Normalization
。
实现方法可以参考Pytorch官方文档。
3、注意事项
- 当同时使用混合精度和梯度累积进行训练时,
scale
应该为有效批次进行校准,scale
更新需要在有效批次上完成 - 当使用梯度累积进行分布式数据并行(DDP)训练时,可以调用
no_sync()
上下文管理器来禁用前M-1
步的梯度还原,帮助进一步提高训练速度
4、梯度检查点(Gradient Checkpoint)
梯度检查点(Gradient Checkpoint)的思想是将一部分节点的中间结果保存为checkpoint
,在反向传播过程中对这些节点之间的其他部分重新进行计算。在该技巧的帮助下,研究人员可以将10倍大的模型放到GPU上,且计算时间仅增加20%,Pytorch、Hugging Face均支持这一功能,仅需两行代码便可实现:
bert = AutoModel.from_pretrained("pretrained-model-name")
bert.config.gradient_checkpointing = True