GradScaler 是否需要使用 pytorch 进行混合精度训练?

问题描述 投票:0回答:2

因此,查看 Normal 网络的 AMP:自动混合精度训练 教程,我发现有两个版本:

Automatic
GradScaler
。我只是想知道在训练中使用 GradScaler 是否是“建议/必要”,因为文档中写道:

在混合精度训练时,梯度缩放有助于防止小幅度梯度冲至零(“下溢”)。

scaler = torch.cuda.amp.GradScaler() for epoch in range(1): for input, target in zip(data, targets): with torch.cuda.amp.autocast(): output = net(input) loss = loss_fn(output, target) scaler.scale(loss).backward() scaler.step(opt) scaler.update() opt.zero_grad()
另外

,查看PyTorch 的 NVIDIA Apex 文档,他们将其用作, from apex import amp model, optimizer = amp.initialize(model, optimizer) loss = criterion(…) with amp.scale_loss(loss, optimizer) as scaled_loss: scaled_loss.backward() optimizer.step()

我认为这也是
GradScaler

所做的,所以我认为这是必须的。有人可以帮我解决这里的问题吗?

    

deep-learning pytorch nvidia apex torch
2个回答
16
投票
GradScaler()

,你的模型可能无法收敛。

使用 FP16 存在三个基本问题:

权重更新:半精度,1 + 0.0001 四舍五入到 1。
    autocast()
  • 处理这个问题。
    消失梯度:半精度时,任何小于(大约)2e-14 的值都会四舍五入到 0,而不是单精度 2e-126。 
  • GradScaler()
  • 照顾这个。
    爆炸性损失:与上面类似,半精度时溢出的可能性也更大。这也是由 
  • autocast()
  • 上下文管理的。
    
        

0
投票

与 FP32 相比,使用低精度 FP16 通常存在两个问题。

    算术下溢/溢出
  1. :在fp16中,当update/param weight += lr*gradient)时,如下例所示。在归约运算中,fp16 会导致算术溢出。 < 2^-11 i.e. 0.00049, param update will have no effect. This means weight update (
    解决方案
    是在可能发生下溢/溢出的地方使用 FP32,PyTorch 中的 AMP 会处理这一点。
PyTorch 自动转换行为运营Ops 自动转换为 fp16Ops 自动转换为 fp32
matmul、线性、conv2d、LSTMCell 等
pow、sum、归一化、softmax 等
# Imprecise weight update p = torch.FloatTensor([1.0]), device='cuda:0') print(p.dtype, p + 0.0001) # weight += lr*gradient p = torch.HalfTensor([1.0]), device='cuda:0') print(p.dtype, p + 0.0001, '-> undeflow') # output torch.float32 tensor([1.0001]) torch.float16 tensor([1.], dtype=torch.float16) -> undeflow # reduction operation a = torch.FloatTensor(4096).fill_(16.0) # a 4096x1 tensor having each value 16.0 print(a.dtype, a.sum()) a = torch.HalfTensor(4096).fill_(16.0) print(a.dtype, a.sum(), '-> overflow') #output torch.float32 tensor(65536.) torch.float16 tensor(inf, dtype=torch.float16) -> overflow
    损失缩放
  1. :另一个问题是从 FP32 转换为 FP16 时梯度值变为零,因为它们只是位于 FP16 范围之外,如 nvidia 文档 中的图中所示。请注意,FP16 范围足够,但其中大部分未使用。简单的解决方案是将梯度向右缩放,以防止它们在 FP16 中变成 0。这就是混合精度中需要梯度缩放的原因。

loss scaling

© www.soinside.com 2019 - 2024. All rights reserved.