fp16与fp32简介与试验


目录

一、fp16和fp32介绍

二、为什么应用fp16训练:

三、应用fp16存在问题

四、实践对比

引用:


一、fp16和fp32介绍

  • fp16是指采用2字节(16位)进行编码存储的一种数据类型;同理fp32是指采用4字节(32位);

  • 如上图,fp16第一位表示+-符号,接着5位表示指数,最后10位表示分数;
    • 公式:

    • 其中,sign位表示正负,exponent位表示指数( ),fraction位表示的是分数( )。其中当指数为零的时候,下图加号左边为0,其他情况为1。
    • 具体计算情况可分为下面三种:

    • Exp:

    • 所以可以计算出,fp16值动态区间:精度其实为
    • fp32值动态区间:

二、为什么应用fp16训练:

  • fp16和fp32相比对训练的优化:
    • 1.内存占用减少:很明显,应用fp16内存占用比原来更小,可以设置更大的batch_size
    • 2.加速计算:加速计算只在最近的一些新gpu中,这一块我还没有体验到好处...有论文指出fp16训练速度可以是fp32的2-8倍

三、应用fp16存在问题

  • 由于fp16的值区间比fp32的值区间小很多,所以在计算过程中很容易出现上溢出(Overflow,>65504 )和下溢出(Underflow,<6x10^-8 )的错误,溢出之后就会出现“Nan”的问题
  • 借用别人例子:

  • 解决办法:
    • 1.混合精度加速:简单的讲就是使用fp16进行乘法和存储,只使用fp32进行加法操作,避免累加误差;
    • 2.损失放大化:
      • 反向传播前,将损失变化(dLoss)手动增大 倍,因此反向传播时得到的中间变量(激活函数梯度)则不会溢出;
      • 反向传播后,将权重梯度缩 倍,恢复正常值。

四、实践对比

实践代码:

1
2
3
4
from apex import amp
model, optimizer = amp.initialize(model, optimizer, opt_level="O1") # 这里是“欧一”,不是“零一”
with amp.scale_loss(loss, optimizer) as scaled_loss:
    scaled_loss.backward()
  • 这里我直接应用fairseq代码的fp16参数:gpu用1080Ti简单试验了下
    • fp16:

    • fp32:

    • 总结:1080Ti应用fp16确实可以省内存,但是理论上是不能加速的啊,这里小朋友有比较多问号???
  • 混合精度加速,需要用到 Volta 结构的GPU,只有V100 和 TITAN V 系列是支持 TensorCore 加速计算

引用:

  • https://zhuanlan.zhihu.com/p/79887894
  • https://en.wikipedia.org/wiki/Half-precision_floating-point_format
  • https://zhuanlan.zhihu.com/p/103685761
  • https://arxiv.org/pdf/1710.03740.pdf