目录
一、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