使能混合精度后,由于数值表示范围和最小间隔发生变化,可能导致极少部分网络出现精度掉点甚至无法收敛的情况。如下图所示。
在以上样例情况中,loss值由于未使能混合精度,导致梯度上溢,进而loss出现异常。
用户可以参考以下方案进行精度调优尝试。
用户可以尽可能让更多算子使用float32计算,回补精度损失。具体方法如下:
APEX和AMP默认使用了动态loss scale,部分网络可能对频繁变化的scale值较敏感,影响收敛。可尝试切换至静态loss scale训练。具体方法如下:
model, optimizer = amp.initialize(model, optimizer, combine_grad=True, opt_level='O1', loss_scale=128.0)
scaler=amp.GradScaler(init_scale=2.**10, dynamic=False)
由于float16计算精度不如float32,可能导致部分网络梯度计算不稳定,进而导致梯度爆炸。可尝试使用梯度裁剪,按范数进行裁剪torch.nn.utils.clip_grad_norm_()或按值进行裁剪torch.nn.utils.clip_grad_value_()。具体方法如下:
output = model(input) loss = criterion(output, target) with amp.scale_loss(loss, optimizer) as scaled_loss: scaled_loss.backward() torch.nn.utils.clip_grad_norm_(parameters=moel.parameters(), max_norm=10) optimizer.step()
with autocast(): output = model(input) loss = criterion(output, target) scaler.scale(loss).backward() scaler.unscale_(optimizer) torch.nn.utils.clip_grad_norm_(parameters=moel.parameters(), max_norm=10) scaler.step(optimizer) scaler.update()
若精度问题好转,用户可通过调整梯度裁剪超参进行调优;若未好转,则建议尝试其他调优方法。