1 大模型数值精度
1.1 计算机对小数的表达方式
以8.56,FP16精度为例
- 符号位 (Sign, S):,0代表正数,1代表负数,这里S=1。
- 指数位 (Exponent, E):计算机是二进制,所以进行区间长度的确认也是2的幂级进行划分,如
2^(-2)~2^(-1)区间长度是,下一个区间是2^(-1)~2^(0)区间长度是[0.5,1),区间长度由小逐步变大的。指数位的范围是2的5次方,偏置项是2^(5-1)-1 = 15 那8.56就是处于2^(3)~2^(4)之间,指数位为3, 3+15(BIAS),即最后的指数位结果为18,E=18. - 尾数位 (Mantissa/Fraction, M):rem = 8.56 - 2 ^ 3 = 0.56,
区间长度为2^4 - 2^3 = 8,将8切分为1024(1024是FP16约定的份数)份。
D=8/1024=0.0078,0.56大约为72份,72*8/1024=0.5625,尾数位为72,M=72 - 计算机表示:fp16就用8.5625近似表示8.56,符号位为0,指数位表示18,尾数位表示72,二进制表示为0_10010_0001001000。
在这里需要注意的是,由2^(-2)~2^(-1) 到2^(-1)~2^(0)再到2^(0)~2^(1),数字越大,区间宽度越宽,这个时候再进行1024份划分,精度可能会下降,即数值越大,精度可能越低。
1.2 FP16
- 内存占用:8bit一个字节,一共占用2个字节;
- 位数划分:符号位1,指数位5,尾数位10
- 偏置值 (Bias)::对于 5 位指数,偏置值为 。
- 特殊指数值的规定:根据 IEEE 754 标准:E = 0 (00000): 用于表示 0 或 非规格化数 (Subnormal numbers);E = 31 (11111): 用于表示 无穷大 (Infinity) 或 非数 (NaN) 。1 ≤ E ≤ 30: 用于表示 规格化数 (Normalized numbers) 。
- FP16精度转数值计算公式:
- 范围:最大值为0 11110 1111111111,即最大值65504,最小值为-65504;最大正数为65504,最小规格化正数为0 00001 0000000000,即,最小规格化正数为,这是保持标准精度的最小值;
- 应用场景:模型训练,相比BF16精度更好,但是数值范围也相对较小
1.3 BF16
- 内存占用:8bit 一个字节,一共占用 2 个字节;
- 位数划分:符号位 1,指数位 8,尾数位 7
- 偏置值 (Bias) :对于 8 位指数,偏置值为 。
- 特殊指数值的规定:1 ≤ E ≤ 254: 用于表示 规格化数 (Normalized numbers)。
- BF16 精度转数值计算公式:
- 范围:最大值为0 11111110 1111111, 即最大值约 3.39e38,最小值为 -3.39e38;最大正数为 3.39e38,最小规格化正数为0 00000001 0000000,即 ,最小规格化正数为 ,这是保持标准精度的最小值;
- 应用场景:深度学习训练(如 Google TPU),相比 FP16 数值范围更大(与 FP32 相同),不易溢出,但精度略低于 FP16。
1.4 FP32
- 内存占用:8bit 一个字节,一共占用 4 个字节;
- 位数划分:符号位 1,指数位 8,尾数位 23
- 偏置值 (Bias) :对于 8 位指数,偏置值为 。
- 特殊指数值的规定:1 ≤ E ≤ 254: 用于表示 规格化数 (Normalized numbers)。
- FP32 精度转数值计算公式:
- 范围:最大值为0 11111110 11111111111111111111111, 即最大值约 3.40e38,最小值为 -3.40e38;最大正数为 3.40e38,最小规格化正数为0 00000001 00000000000000000000000,即 21−127×(1+0/223)=2−126 ,最小规格化正数为 2−126 ,这是保持标准精度的最小值;
- 应用场景:通用 CPU/GPU 计算,高精度模型训练与推理,科学计算,数值稳定性最好,但内存占用和计算成本较高。
1.5 INT8
- 内存占用:8bit 一个字节,一共占用 1 个字节;
- 位数划分:符号位 1,数值位 7(有符号整型);
- 偏置值 (Bias):无 (量化推理中通常使用 Scale 缩放因子和 ZeroPoint 零点偏移);
- 特殊指数值的规定:无 (不支持 NaN/Inf,溢出即 wrap-around 或饱和);
- INT8 量化转数值计算公式: (反量化公式);
- 范围:最大值为01111111,即 ,最大值 127,最小值为 -128(10000000);若用于量化,实际表示的浮点范围取决于 Scale,通常映射到 [-1, 1] 或激活值范围;最小精度间隔为 1(原始整型),量化后精度为 Scale;
- 应用场景:模型推理量化(Post-training Quantization),边缘设备部署,显著减少内存带宽压力,计算速度快,但训练阶段通常不使用。
1.6 INT4
- 内存占用:4bit 半个字节,2 个数值占用 1 个字节;
- 位数划分:符号位 1,数值位 3(有符号整型);
- 偏置值 (Bias):无 (量化推理中通常使用 Scale 缩放因子和 ZeroPoint 零点偏移);
- 特殊指数值的规定:无 (不支持 NaN/Inf);
- INT4 量化转数值计算公式: (反量化公式);
- 范围:最大值为0111,即 ,最大值 7,最小值为 -8(1000);若用于量化,实际表示的浮点范围取决于 Scale;最小精度间隔为 1(原始整型),量化后精度为 Scale;
- 应用场景:超大语言模型(LLM)推理量化(如 LLM.int4()),显存极度受限场景,精度损失较 INT8 更大,通常需要混合精度或异常值处理来弥补。
1.7 NF4 (Normal Float 4)
- 内存占用:4bit 半个字节,2 个数值占用 1 个字节;
- 位数划分:4 位索引位(无独立符号/指数/尾数,基于查找表);
- 偏置值 (Bias):无 (基于正态分布的分位数进行量化);
- 特殊指数值的规定:无 (16 个离散浮点值,不支持 NaN/Inf);
- NF4 转数值计算公式: (Index 为 4 位二进制对应的 0-15 整数);
- 范围:最大值为1111(对应查找表中最大值),最大值约 1.0,最小值约 -1.0;NF4 专门针对权重服从正态分布的特性设计,16 个量化级别在 0 附近分布更密集,最小精度间隔在 0 附近更优,这是 QLoRA 技术的核心,相比 INT4 能更好地保留权重信息;
- 应用场景:大模型高效微调(QLoRA),在保持 4bit 低内存占用的同时,比 INT4 更好地保留模型精度,适合显存有限的微调任务。
1.8 精度差异总结
常见数值精度的差异
| 数据类型 | 总位数 | 符号位 | 指数位 | 尾数位 / 量化方式 | 动态范围(最小正数 ~ 最大正数) | 精度(约十进制位数) | 典型应用 |
|---|---|---|---|---|---|---|---|
| FP32 | 32 | 1 | 8 | 23 | 1.4×10⁻⁴⁵ ~ 3.4×10³⁸ | 7 位 | 通用计算,训练基线 |
| FP16 | 16 | 1 | 5 | 10 | 5.96×10⁻⁸ ~ 65,504 | 3~4 位 | 混合精度训练,推理 |
| BF16 | 16 | 1 | 8 | 7 | 同 FP32(约 1.2×10⁻³⁸ ~ 3.4×10³⁸) | 2~3 位 | 大模型训练(如 TPU、Ampere GPU) |
| INT8 | 8 | 1 | - | 均匀整数(无小数) | -128 ~ 127(有符号)或 0~255(无符号) | 1 位(整数值) | 推理加速,量化部署 |
| INT4 | 4 | 1 | - | 均匀整数(无小数) | -8 ~ 7(有符号)或 0~15(无符号) | 1 位(整数值) | 超大语言模型(LLM)推理量化 |
| NF4 | 4 | 隐式对称 | - | 基于正态分布分位数的 16 个离散值 | 依赖于缩放因子(通常归一化到约 [-1, 1]) | 约 1 位(log10(16)≈1.2) | 4 比特量化微调(QLoRA) |
2 数值带来的问题
2.1 溢出问题
- 上溢出:数值区间都是左闭右开,比如FP16的最大保留精度正数是65504,一直到,也就是在[65505,65536)之间都是可以被FP16表示的,但是一旦大于等于65536就产生上溢出,表现为inf。
- 下溢出:同理,比如0.000000001,0.000000001 小于 FP16 所能表示的最小正数(约 5.96e-8),因此在 FP16 精度下会下溢为 0,如果此时一个数字除以该数字,就会造成上溢出。
2.2 NAN的产生
NaN 和 Inf 是相关的。通常先是数值溢出变成 Inf(无穷大),然后 Inf 参与进一步的计算(如 Inf 减去 Inf,或者 Inf 乘以 0)就变成了 NaN
- 梯度爆炸:在深度神经网络中,梯度在反向传播过程中不断累积乘法,如果网络权重初始化不当或学习率过高,梯度值会变得极大,超出数值精度范围(即上溢),就会变成无穷大(Inf)。Inf 参与任何后续运算(如加法、乘法、梯度更新)都会直接导致 NaN。
- 除零错误:在损失函数、归一化层(如 BatchNorm)或自定义运算中,如果分母在计算过程中恰好变成了 0,就会产生 NaN
- 对负数进行 log 运算:损失函数中经常使用对数运算(如交叉熵损失),如果模型的输出经过 Softmax 后,由于数值问题(如下溢)导致某个类别的预测概率恰好是 0,那么计算 log(0)log(0) 就会得到负无穷大(-Inf),-Inf 参与后续运算(如求和、平均)后就会变为 NaN。
2.3 舍入误差
梯度即便不会出现上/下溢出,如果梯度值和模型的参数值相差太远,也会发生舍入误差的问题,假设模型参数weight=,学习率η=,梯度
2.4 解决方案
- 缩放
3 大模型显存占用
- 1.模型状态(model states):模型参数(fp16) + 模型梯度(fp16) + Adam状态(fp32的模型参数备份,fp32的momentum和fp32的variance);假设模型参数量为Φ,则共需要2Φ+2Φ+(4Φ+4Φ+4Φ)=4Φ+12Φ=16Φ字节存储,可以看到,Adam状态占比75%。
- 2.剩余状态(residual states):除了模型状态之外的显存占用,包括激活值(activation)、各种临时缓冲区(buffer)以及无法使用的显存碎片(fragmentation)。 GPT-2含有1.5B个参数,如果用fp16格式(只需要3GB显存)但是模型状态实际上需要耗费24GB,也就是一般来说进行全参数微调需要的显存占用是模型本身占用的8倍。