(本文只是个人在学习过程记录的问题以及我对这个问题浅显的解释,如有不当之处,望请指正。)
AMP简介
上图截取自pytorch官网。
上图第一段,主要描述了AMP提供了混合精度运算,主要是因为:一些operations在float16等数据类型上计算效率高,另一些operations则在float32上计算效率更高,故而混合精度的算法设计是有必要的。(听说效率可以提高一倍以上,真的恐怖!!!)
第二段则是说要使用AMP,需要联合使用autocast和GradScaler,在cpu上,对于bfloat16类型,可以仅使用autocast。
使用的代码示例(来自AMP示例),这里描述已经非常详细了,还有一个使用unscale_的示例就不放上来的。
# 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()
简述NAN报错的原因
通过一张图简述原因(以下纯属个人拙见,错了请在评论区指出,非常感谢!!!)
第一段讲述autocast的作用(自动选择合适的精度,以提高运算的效率)
第二段讲述GradScaler的作用(帮助网络的收敛,并有效防止梯度下溢)
在递上一张图,这里第二点说的是当梯度是inf/NaN时,则会跳过对此次梯度的更新,防止破坏网络的参数,在看MAE源码中,
with torch.cuda.amp.autocast():
loss, _, _ = model(samples, mask_ratio=args.mask_ratio)
loss_value = loss.item()
if not math.isfinite(loss_value):
print("Loss is {}, stopping training".format(loss_value))
sys.exit(1)
上述代码loss_value的值为Nan,可能就是因为梯度下溢问题。(到这里就不知道怎么分析了)