混合精度

文章目录


混合精度

混合精度训练,指代的是单精度 float(32bit,4 个字节)和半精度 float16 混合。比较经典的就是这篇 ICLR2018,百度和 Nvidia 联合推出的论文 MIXED PRECISION TRAINING

半精度优点

  • 内存占用更少: 通用的模型 fp16 占用的内存只需原来的一半。memory-bandwidth 减半所带来的好处:

    • 模型占用的内存更小,训练的时候可以用更大的 batchsize。
    • 模型训练时,通信量(特别是多卡,或者多机多卡)大幅减少,大幅减少等待时间,加快数据的流通。
  • 计算更快:

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

半精度问题

  • 数据溢出 Overflow / Underflow:对于深度学习而言,最大的问题在于 Underflow(下溢出),在训练后期,例如激活函数的梯度会非常小, 甚至在梯度乘以学习率后,值会更加小。
  • 舍入误差 Rounding Error

解决办法

  • 混合精度训练(Mixed Precision)

    在某些模型中,fp16 矩阵乘法的过程中,需要利用 fp32 来进行矩阵乘法中间的累加(accumulated),然后再将 fp32 的值转化为 fp16 进行存储。 换句不太严谨的话来说,也就是 利用 fp16 进行乘法和存储,利用 fp32 来进行加法计算。 这么做的原因主要是为了减少加法过程中的舍入误差,保证精度不损失。

    FP32 权重备份

    这种方法主要是用于 解决舍入误差 的问题。其主要思路,可以概括为:weights, activations, gradients 等数据在训练中都 利用 fp16 来存储,同时拷贝一份 fp32 的 weights,用于更新

    在更新权重的时候,$ \text{weight}t= \text {weight}{t-1}+ \text{lr} * \text{gradients}$ ,而在深度模型中, $ \text{lr} * \text{gradients}$ 这个值往往是非常小的,如果利用 fp16 来进行相加的话, 则很可能会出现 舍入误差 Rounding Error,导致更新无效。因此上图中,通过将 weights 拷贝成 fp32 格式,并且确保整个更新(update)过程是在 fp32 格式下进行的。

    fp32 额外拷贝一份 weight 会新增加训练时候存储的占用。 但是实际上,在训练过程中,内存中占据大部分的基本都是 activations 的值。特别是在 batchsize 很大的情况下, activations 更是特别占据空间。 保存 activiations 主要是为了在 back-propogation 的时候进行计算。因此,只要 activation 的值基本都是使用 fp16 来进行存储的话,则最终模型与 fp32 相比起来, 内存占用也基本能够减半。

  • 损失放大 Loss Scale

    Loss Scale 主要是为了 解决 fp16 underflow 的问题。训练到了后期,梯度(特别是激活函数平滑段的梯度)会特别小,fp16 表示容易产生 underflow 现象。

    为了解决梯度过小的问题,论文中 对计算出来的 loss 值进行 scale,由于链式法则的存在,loss 上的 scale 也会作用在梯度上。这样比起对每个梯度进行 scale 更加划算。 scaled 过后的梯度,就会平移到 fp16 有效的展示范围内。

    1. 反向传播前,将损失变化(dLoss)手动增大 2 k 2^k 2k 倍,因此反向传播时得到的中间变量(激活函数梯度)则不会溢出;
    2. 反向传播后,将权重梯度缩 2 k 2^k 2k 倍,恢复正常值。

    这样,scaled-gradient 就可以一直使用 fp16 进行存储了。只有在进行更新的时候,才会将 scaled-gradient 转化为 fp32,同时将 scale 抹去

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值