4. 量化技术基础:FP32、FP16、INT8、INT4的数据格式对比

聊到量化,我得先说说自己的经历。几年前我做第一个大模型部署项目时,模型在GPU上跑得挺欢,一上边缘设备就卡成PPT。后来才发现,问题就出在数据格式上——你用FP32去跑,带宽和算力根本扛不住。量化,说白了就是用更少的比特去表示一个数,代价是损失一点精度,换来速度翻倍。

4.1 四种主流数据格式

咱们先看看这四种格式长什么样。我习惯把它们分成两类:浮点型和整型。

格式 位宽 表示范围 精度 典型场景
FP32 32-bit ±3.4×10³⁸ ~7位十进制 训练、精度敏感层
FP16 16-bit ±6.5×10⁴ ~3位十进制 推理加速、混合精度
INT8 8-bit -128~127 整数精度 推理部署主流
INT4 4-bit -8~7 整数精度 极致压缩场景

FP32是基准,每个数用1位符号、8位指数、23位尾数。FP16砍了一半,指数5位、尾数10位。你想想看,范围直接从10³⁸缩到10⁴,这意味着什么?大数容易溢出,小数容易下溢。我在项目中遇到过,一个激活值稍微大点,FP16直接变Inf,整个推理就崩了。

INT8和INT4就更狠了。它们没有指数,只有符号位和数值位。表示范围是线性的,不像浮点那样能动态缩放。所以做INT8量化时,最关键的一步就是选好缩放因子——scale。scale选大了,小值被截断;选小了,大值溢出。嗯,这里要注意,scale的选择直接决定了量化误差的大小。

核心结论:FP32是黄金标准,FP16是性价比之选,INT8是部署主力,INT4是极限挑战。选哪种,取决于你的精度容忍度和硬件支持情况。

4.2 量化误差的来源

量化误差不是凭空来的。我把它归纳为三个源头:

  • 截断误差:数值超出表示范围,直接截断。比如FP16最大65504,你激活值到了70000,那就只能变成Inf。
  • 舍入误差:数值落在两个可表示值之间,四舍五入或向下取整。INT8的步长是1,0.3和0.7都会被量化成0或1。
  • 梯度误差:量化操作本身不可导,反向传播时梯度近似不准。这个在训练时量化(QAT)里特别头疼。

我曾经调试过一个模型,INT8量化后精度掉了5个点。查了半天,发现是某个层的权重分布特别宽,最大值是-3.2到3.1,但大部分值集中在-0.1到0.1之间。你想想看,scale按最大值3.2来算,步长就是3.2/127≈0.025,但大部分值都在0.1以内,相当于只用到了4-5个量化级别。这能不丢精度吗?

避坑指南:我曾经犯过一个错误——直接对整个模型用同一个scale。结果某些层精度崩了,某些层却没事。后来才明白,每层的数据分布不一样,最好逐层或逐通道去统计min/max,做per-channel量化。

4.3 量化误差的评估方法

怎么知道量化做得好不好?光看最终精度不够,你得拆开来看。我一般用三个指标:

  1. 均方误差(MSE):量化前后输出值的平方差均值。越小越好。
  2. 信噪比(SNR):信号功率与噪声功率的比值。通常用dB表示,越高越好。
  3. 余弦相似度:量化前后特征向量的夹角余弦。接近1说明方向没偏。

举个例子,你量化一个卷积层的输出,可以这样算:

import numpy as np

def evaluate_quant_error(original, quantized):
    # 均方误差
    mse = np.mean((original - quantized) ** 2)
    # 信噪比
    signal_power = np.mean(original ** 2)
    noise_power = np.mean((original - quantized) ** 2)
    snr = 10 * np.log10(signal_power / noise_power)
    # 余弦相似度
    cos_sim = np.dot(original.flatten(), quantized.flatten()) / (
        np.linalg.norm(original) * np.linalg.norm(quantized)
    )
    return mse, snr, cos_sim

我个人习惯,先看余弦相似度。如果低于0.99,那这层量化就有问题。再看SNR,一般要大于30dB才算合格。MSE作为辅助,因为它的绝对值受数据范围影响大,不好横向比较。

4.4 知识体系图

下面这张图是我自己整理的量化知识框架,帮你理清思路:

量化技术知识体系 数据格式对比 FP32 (32-bit) FP16 (16-bit) INT8 (8-bit) INT4 (4-bit) 量化误差来源 截断误差 (Clipping) 舍入误差 (Rounding) 梯度误差 (Gradient) 评估方法 MSE (均方误差) SNR (信噪比) 余弦相似度

小技巧:实际项目中,我建议你先用余弦相似度做快速筛查,找到问题层后再用SNR和MSE做精细分析。别一上来就全量评估,浪费时间。

量化不是玄学,是工程。你理解了每种格式的脾气,知道误差从哪来,会用量化误差的评估方法,那部署时心里就有底了。我见过太多人一上来就INT8,结果精度掉了也不分析原因,直接怪量化不好。其实很多时候,换个scale策略或者做点校准数据,问题就解决了。

好了,这一章就聊到这。量化是个大话题,后面我们还会深入讲怎么选scale、怎么做校准、怎么处理异常值。先把基础打牢,后面才不慌。

专注资料整理