2、量化基础:什么是模型量化、定点数与浮点数、量化参数(scale、zero-point)、对称与非对称量化
在进入 QAT(量化感知训练)实战之前,必须先建立对量化基础概念的清晰认知。很多初学者直接调用 PyTorch 的 torch.quantization 接口,却对 scale、zero-point 的含义一知半解,导致模型精度异常时无从排查。本章将从模型量化的本质出发,逐步拆解定点数与浮点数的差异、量化参数的计算逻辑,以及对称/非对称两种量化策略的适用场景。这些内容不仅是 QAT 的理论基石,更是后续调试量化模型时定位误差来源的关键工具。
2.1 模型量化的核心原理
模型量化本质上是一种数值精度压缩技术,其目标是将神经网络中高精度的浮点数参数(权重、激活值)转换为低比特的整数表示,从而在保持模型功能基本不变的前提下,显著降低模型的存储体积和推理时的计算开销。以最常见的 INT8 量化为例,一个 FP32 模型(约 4 字节/参数)转换为 INT8(1 字节/参数)后,模型体积直接缩减为原来的 1/4。在推理阶段,INT8 矩阵乘法可以利用硬件提供的 SIMD(单指令多数据)指令集并行执行,吞吐量通常可提升 2~4 倍。
量化的数学本质是一个区间映射问题:我们需要找到一个从浮点数区间 [r_min, r_max] 到整数区间 [q_min, q_max] 的双射关系。这个映射不是简单的截断或取整,而是需要保证映射后的整数能够尽可能精确地还原原始浮点数值。映射过程中必然引入量化误差,QAT 的核心思想就是让模型在训练阶段就"感知"到这种误差,通过反向传播调整权重,使模型对量化误差具有鲁棒性。
从信息论的角度看,量化是一个有损压缩过程。FP32 提供约 23 位二进制精度,而 INT8 仅提供 8 位。这意味着每个数值的表示精度从约 7 位十进制有效数字下降到约 2~3 位。对于神经网络而言,这种精度损失通常是可以接受的,因为网络本身具有一定的容错能力,且权重和激活值的分布往往集中在某个有限区间内,并非均匀分布在整个 FP32 表示范围内。
2.2 定点数与浮点数的本质差异
要理解量化,必须先厘清定点数(Fixed-point)与浮点数(Floating-point)的差异。浮点数(如 FP32)采用科学计数法的二进制形式,由符号位、指数位和尾数位三部分组成。以 FP32 为例,其 32 位被划分为:1 位符号位(S)、8 位指数位(E)和 23 位尾数位(M)。这种设计使得浮点数能够表示极大和极小的数值范围(约 ±3.4×10³⁸),且在整个范围内保持相对精度(约 7 位十进制有效数字)。
定点数则完全不同,它使用固定的二进制位数来表示整数部分和小数部分。例如,Q7.8 定点格式表示 7 位整数位和 8 位小数位,总共 16 位。定点数的表示范围是固定的,由整数位决定;精度也是固定的,由小数位决定。定点数的优势在于硬件实现简单、计算速度快、功耗低,但缺点是动态范围有限,容易溢出或精度不足。
在神经网络中,权重和激活值的分布通常具有以下特征:权重往往集中在零附近的小范围内(如 [-0.1, 0.1]),而激活值经过 ReLU 后通常为非负值(如 [0, 6])。这些分布特征使得我们不需要浮点数那样巨大的动态范围,只需要针对实际分布选择合适的定点格式即可。模型量化正是基于这一观察,将浮点数映射到定点整数,同时通过 scale 和 zero-point 两个参数来适配不同的数值分布。
| 对比维度 | FP32 浮点数 | INT8 定点数 | 量化后的影响 |
|---|---|---|---|
| 存储空间 | 4 字节 | 1 字节 | 模型体积减少 75% |
| 表示范围 | ±3.4×10³⁸ | [-128, 127] 或 [0, 255] | 需要 scale 映射 |
| 精度 | ~7 位十进制有效数字 | ~2 位十进制有效数字 | 引入量化误差 |
| 计算速度 | 慢(需浮点运算单元) | 快(整数运算) | 推理加速 2~4 倍 |
| 硬件支持 | 通用 CPU/GPU | 移动端 NPU/DSP 友好 | 边缘部署可行 |
2.3 量化参数:scale 与 zero-point 的数学定义
量化参数是连接浮点数和整数的桥梁。给定浮点数 r 和量化后的整数 q,它们之间的转换关系由以下公式定义:
量化(浮点 → 整数):
q = round(r / scale) + zero_point
反量化(整数 → 浮点):
r = (q - zero_point) × scale
其中,scale(缩放因子)是一个正浮点数,表示每个整数单位对应的浮点数值大小。scale 的计算公式为:
scale = (r_max - r_min) / (q_max - q_min)
zero_point(零点)是一个整数,表示浮点数值 0 对应的量化整数。它的计算公式为:
zero_point = round(q_min - r_min / scale)
zero_point 的存在是为了处理浮点区间不对称的情况。例如,当激活值经过 ReLU 后全为非负数(如 [0, 6])时,如果直接映射到 [-128, 127] 的 INT8 区间,会浪费一半的表示能力。通过设置合适的 zero_point,可以将 [0, 6] 完整映射到 [0, 255] 的 UINT8 区间,充分利用所有整数编码。
在实际的量化实现中,scale 和 zero_point 的确定有两种主要方法:校准(Calibration)和训练中统计。校准方法在模型训练完成后,使用一小部分验证数据统计激活值的分布范围,从而确定 scale 和 zero_point。而 QAT 则在训练过程中动态统计这些值,并让模型适应量化误差。
FakeQuantize 模块会自动处理这一过程,但理解其内部机制对调试至关重要。
2.4 对称量化与非对称量化
根据 zero_point 是否为零,量化策略分为对称量化和非对称量化两种。
对称量化强制 zero_point = 0,即浮点数的 0 映射到整数的 0。此时量化公式简化为:
q = round(r / scale)
r = q × scale
对称量化的优点是实现简单,不需要额外存储 zero_point,且整数运算时无需考虑零点偏移,计算效率更高。其缺点是当浮点数据分布不对称时(如全为正的激活值),会浪费一部分整数表示范围。对称量化通常适用于权重,因为训练良好的网络权重分布近似于零均值的正态分布。
非对称量化允许 zero_point 不为零,能够更灵活地适配不对称的数据分布。例如,ReLU 后的激活值范围为 [0, 6],使用非对称量化可以将该区间完整映射到 [0, 255],充分利用所有整数编码,从而获得更高的精度。非对称量化的代价是需要额外存储 zero_point,且在推理时需要进行一次额外的加法运算。
| 对比维度 | 对称量化 | 非对称量化 |
|---|---|---|
| zero_point | 恒为 0 | 可为非零整数 |
| 适用场景 | 权重(分布近似零均值) | 激活值(ReLU 后全为正) |
| 表示效率 | 可能浪费部分整数范围 | 充分利用整数范围 |
| 计算复杂度 | 低(无需零点偏移) | 略高(需处理零点) |
| 精度表现 | 对不对称分布精度较低 | 对不对称分布精度较高 |
2.5 案例拆解:一个卷积层的量化参数计算
为了将上述概念具体化,我们以一个实际场景来演示量化参数的计算过程。假设我们有一个训练好的卷积层,其权重分布经统计为 [-0.15, 0.12],激活值(ReLU 后)分布为 [0.0, 5.8]。我们计划将权重量化为 INT8(对称量化),激活值量化为 UINT8(非对称量化)。
第一步:计算权重的 scale
权重范围: r_min = -0.15, r_max = 0.12
INT8 范围: q_min = -128, q_max = 127
scale_w = (0.12 - (-0.15)) / (127 - (-128)) = 0.27 / 255 ≈ 0.001059
zero_point_w = 0 (对称量化)
第二步:计算激活值的 scale 和 zero_point
激活范围: r_min = 0.0, r_max = 5.8
UINT8 范围: q_min = 0, q_max = 255
scale_a = (5.8 - 0.0) / (255 - 0) = 5.8 / 255 ≈ 0.022745
zero_point_a = round(0 - 0.0 / 0.022745) = 0
在这个例子中,由于激活值的最小值恰好为 0,zero_point 恰好为 0。但如果激活值的最小值为 0.5,则 zero_point 将不为零。例如:
激活范围: r_min = 0.5, r_max = 5.8
scale_a = (5.8 - 0.5) / 255 ≈ 0.020784
zero_point_a = round(0 - 0.5 / 0.020784) = round(-24.06) = -24
第三步:验证量化-反量化误差
以权重值 r = 0.05 为例:
q = round(0.05 / 0.001059) = round(47.21) = 47
r' = 47 × 0.001059 = 0.049773
量化误差 = |0.05 - 0.049773| = 0.000227
这个误差在可接受范围内。如果误差过大,说明 scale 选择不当,或者数据分布中存在极端离群值,需要采用 clipping(截断)策略来牺牲少量范围换取更高的精度。
2.6 常见误区与总结复盘
在理解量化基础时,初学者常犯以下错误,需要特别警惕:
- 误区一:认为量化就是简单的四舍五入。实际上,量化涉及区间映射、scale 计算和零点偏移,是一个系统性的数值变换过程。简单的四舍五入会导致严重的精度损失。
- 误区二:对称量化一定比非对称量化差。对于权重这种零均值分布,对称量化不仅精度相当,而且计算效率更高。选择哪种策略取决于数据分布特征,而非一概而论。
- 误区三:忽略 zero_point 的作用。zero_point 不是可有可无的,它决定了浮点 0 在整数域中的位置。如果 zero_point 计算错误,会导致整个量化映射偏移,产生系统性误差。
- 误区四:认为量化误差只影响精度。量化误差还会影响模型的数值稳定性,特别是在深层网络中,误差会逐层累积,最终导致输出严重偏离。
总结本章内容,模型量化的核心在于理解浮点到整数的映射关系,掌握 scale 和 zero-point 的计算方法,并根据数据分布特征选择合适的量化策略。对称量化适合权重,非对称量化适合激活值,这是 QAT 中最常见的组合方案。在后续章节中,我们将基于这些基础概念,深入探讨如何在 PyTorch 中实现 QAT 训练流程,以及如何评估和优化量化模型的精度。
- 量化是将 FP32 映射到 INT8/UINT8 的有损压缩过程,核心收益是存储减少 75%、推理加速 2~4 倍。
- scale 决定每个整数单位代表的浮点大小,zero-point 决定浮点 0 对应的整数位置。
- 对称量化(zero-point=0)适合权重,非对称量化(zero-point≠0)适合激活值。
- QAT 的核心思想是在训练中模拟量化误差,让模型权重适应精度限制。
- 计算 scale 时需注意离群值影响,必要时采用百分位截断或 KL 散度校准。