深度学习中我们一般使用浮点进行原始模型的训练推理,但是有时候我们希望占用更少的内存,加快推理速度,精度又要求没有特别高的情况下,假设硬件支持了fp16的加速优化,我们就可以使用。
那么是如何处理float和fp16转换的,在介绍这个之前,有一个前置知识点就是fp32、fp16在内存中是怎么存储的,可以看这个这篇文章。
下面贴下转换代码
fp32 ->fp16
typedef unsigned short half;
half nvFloat2Half(float m2)
{
/*
1、强制把float转为unsigned long(32bit),用来取对应bit的数
2、截取后23位尾数,右移13位,剩余10位,得到了fp16的尾数位(取高10位)
3、符号位直接右移16位,得到了fp16的符号位
4、截取指数的8位先右移13位,这里得到8位,但是我们只用到5位,左边多出的3位不用管
由于之前0~255表示-127~128,调整过后变成 0~31表示-15~16,所以fp16情况下指数位是+15,
所以这里需要在移位后指数的基础上减去(127-15) = 112(左移10位,因为指数是在bit10开始),
*/
unsigned short t = ((m2 & 0x007fffff) >> 13) | ((m2 & 0x80000000) >> 16)
| (((m2 & 0x7f800000) >> 13) - (112 << 10));
if(m2 & 0x1000)
t++; // 四舍五入(尾数被截掉部分的最高位为1, 则尾数剩余部分+1)
half h = *(half*)(&t); // 强制转为half
return h ;
}
fp16->fp32
float nvHalf2Float(half n)
{
unsigned short frac = (n & 0x3ff) | 0x400;
int exp = ((n & 0x7c00) >> 10) - 25;
float m;
if(frac == 0 && exp == 0x1f)
m = INFINITY;
else if (frac || exp)
m = frac * pow(2, exp);
else
m = 0;
return (n & 0x8000) ? -m : m;
}