专栏名称: 吃果冻不吐果冻皮
专注于AI工程化(LLM、MLOps、LLMOps、RAG、Agent)落地。
目录
相关文章推荐
成都本地宝  ·  明确了!四川再添6个国家4A级景区! ·  2 天前  
成都发布  ·  通知!考试时间定了 ·  昨天  
清廉蓉城  ·  中国纪检监察报关注成都:居有所安 ·  3 天前  
51好读  ›  专栏  ›  吃果冻不吐果冻皮

FP8 量化基础知识(扫盲)

吃果冻不吐果冻皮  · 公众号  ·  · 2024-06-26 12:42

正文

【点击】 加入大模型技术交流群

原文:https://zhuanlan.zhihu.com/p/619431625

1. Background

硬件的支持

许多硬件厂商的芯片开始支持 FP8 的计算,如英伟达最新的两种架构 Ada (4090) 和 Hopper (H100)。它们的 Tensor Core 计算单元都开始支持 FP8 的计算,如图所示:

在 H100 的第四代 Tensor Core 中,支持任意的 FP8 格式矩阵的乘法 (E4M3xE4M3, E5M2xE5M2, E4M3xE5M2, E5M2xE4M3)

然后会进行累加到 FP32 和 FP16 的数据格式之中

同时也支持浮点格式之间的互相转换,如下图

FP8 好处

  1. FP8 Tensor Cores 比 16-bit Tensor Cores 快

  2. 减少 memory movement

  3. 如果模型已经在 FP8 中进行,部署更加方便

  4. FP8 拥有更宽的动态范围

  5. FP8 到 FP16/FP32/BF16 之间的转换电路,可以设计得更简单直接,而不需要像INT8/UINT8到FP的转化需要乘法和加法的开销。

2. FP8 TYPES

先简单回顾一下浮点数的表示方式:

IEEE 754

  • 浮点数会分为符号位(sign), 指数位 (exponent), 和小数位 (Mantissa)

float32 的表示方法
  • 浮点数根据 Exponent 的值会分为规格化,非规格化和特殊值 (无穷和NAN)。

  • 规格化的值计算公式如下:

Tensor Cores 中,根据指数位和小数位的不同,支持 E5M2 和 E4M3

下面分别来看看它们的浮点数表示方法:

E5M2

E5M2 遵循上面的 IEEE 754 的浮点数格式,其中 bias =2^(e-1)-1 = 15

  • 规格化的值 (指数位不全为 0 /不全为 1)eg: 0 | 01101 | 01 ,如下图

易得最大值和最小值

max= 2^(30-15)*(1+1/2+1/4)=577344

如果指数位和小数位都为 0,则表示 0

同时,易得非规格化的最大值最小值

  • 特殊值 (指数位全为 1)

    特殊值根据小数位的不同分为 无穷 (Infinites) 和 NaN (Not a number),表示如下:

E4M3

E4M3 不完全遵循 IEEE 754 的数据格式,主要不同在于当指数位全为1 时,一样可以用来表示规格化的值(当小数位不为1) 当且仅当指数与底数部分全为1时,其表示NaN,不能用来表示 Infinites 。其中, bias = 7

计算方式还是一样的,综合一下,可参考下图:

E4M3的最大值=(2^4-1-7)*(1+1/2+1/4)=2^8*(7/4)=448

根据表示的方式,可以把浮点数看成 2 的幂之间的 2^M 个样本的精度,比如在 E5M2 中,2 和 4 之间会有 4 个样本,4 和 8 之间也会有 4 个样本;在 E4M3 中,2 和 4 之间有 8 个样本。通过这一特性,可以容易得出浮点量化的误差会随着数值变化的增大而增大。

3. Convert to FP8

先试想一下,模型的权重如果都是 [-2, 2],它们原本的数据格式都是 FP32,如果你想把它转换成 FP8,其实只需要一个 round 函数。

eg: 易得 FP8 E5M2 在 [1,2] 之间的数为 [1, 1.25, 1.5, 1.75],fp32 的值为 1.4445,那么 fp8 = round(1.4445) = 1.5

不过,FP8 E4M3 的表示范围为 [-448, 448],明显远远小于正常的 FP32 表示的范围。在一些应用上肯定还是无法表示的,办法就是引入一个缩放因子 scale,使得原 Tensor 的值可以在 FP8 的表示范围下表示,如图:


所以对于一个 FP32 的数,要想转换成 FP8, 只需要两步:

  1. Unscaled FP32 = FP32 / scale

  2. FP8 = Convert(Unscaled FP32)

第一步,就是尽可能地把 FP32 的数据放到 FP8 的表示范围内。

eg: 假设有 fp32 数组 [1000.0, 23.0, 123.123],最简单的操作类似于 “minmax”,所有数除以 1000.0/448, 得到 Unscaled FP32 数组 [448, 10.304, 55.104]。

第二步,其实就是上面所说的 Rounding 了,FP8 表示不了精确的 10.304 和 55.104。具体方法可见FP8 量化-原理、实现与误差分析

寻找 scaling factor

这里提供两种较为容易理解的方法:

第一种 (from Nvidia):

假设是 Per-Tensor 的量化,就是找到整个 Tensor 中的最大值,而为了减少找全局最大值带来的 memory consumption, 这里提出了一个基于一个 window, 即找到一个局部的最大值,然后再在这个局部最大值添加一个 margin 在作为 scaling factor







请到「今天看啥」查看全文