【HRFormer】调试半精度相关总结

AMP自动混合精度计算:单精度 float和半精度 float16 混合

  1. 为什么需要半精度:

    float16和float相比恰里,总结下来就是两个原因:内存占用更少,计算更快。

    内存占用更少:这个是显然可见的,通用的模型 fp16 占用的内存只需原来的一半。memory-bandwidth 减半所带来的好处:

    模型占用的内存更小,训练的时候可以用更大的batchsize。

    模型训练时,通信量(特别是多卡,或者多机多卡)大幅减少,大幅减少等待时间,加快数据的流通。

  2. 计算更快:

    目前的不少GPU都有针对 fp16 的计算进行优化。论文指出:在近期的GPU中,半精度的计算吞吐量可以是单精度的 2-8 倍;

  3. 如何使用

    autocast 【一种上下文的模块,该模块框住的内容将自动采用混合精度】+ GradScaler【梯度scaler模块,会忽略nan值的更新】。

    autocast上下文应该只包含网络的前向过程(包括loss的计算),而不要包含反向传播,因为BP的op会使用和前向op相同的类型。

    from torch.cuda.amp import autocast as autocast
    
    # 创建model,默认是torch.FloatTensor
    model = Net().cuda()
    optimizer = optim.SGD(model.parameters(), ...)
    # 在训练最开始之前实例化一个GradScaler对象
    scaler = GradScaler()
    
    for epoch in epochs:
        for input, target in data:
            optimizer.zero_grad()
            # 前向过程(model + loss)开启 autocast
            with autocast():
                output = model(input)
                loss = loss_fn(output, target)
            # Scales loss. 为了梯度放大.
            scaler.scale(loss).backward()
            # scaler.step() 首先把梯度的值unscale回来.
            # 如果梯度的值不是 infs 或者 NaNs, 那么调用optimizer.step()来更新权重,
            # 否则,忽略step调用,从而保证权重不更新(不被破坏)
            scaler.step(optimizer)
            # 准备着,看是否要增大scaler
            scaler.update()
    

半精度带来的数据上下溢出问题

Loss在上下中,采用的仍然是半精度计算,在做Cross-Entropy-loss,会存在sum的操作,在参数设置为mean、sum都会进行sum的操作,容易出现nan值,标志是参数为none即对逐像素计算的loss不做其他操作,输出为一个矩阵,当一个矩阵的mean是正常的sum为inf可以直接判断sum操作已经溢出半精度能表示的范围了。

补充:

判断一个tensor A中是否存在nan,torch.isnan(A).any(),torch.isnan()输出为一个与A同shape的bool矩阵,any为只要由一个true输出为true

判断一个tensor A中是否存在 inf,torch.isinf(A).any()

判断一个tensor A中元素是否满足条件b,torch.where(b, x, y) → Tensor,根据条件,返回从x,y中选择元素所组成的张量。如果满足条件,则返回x中元素。若不满足,返回y中元素。可以写成torch.where(x=0,True,False)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值