模型量化是将模型权重和激活值从高精度浮点数(如FP32)转换为低精度定点整数(如INT8)的过程,以减少模型大小和计算延迟。在面试中,理解均匀量化(Uniform Quantization)的基础知识,特别是如何计算 Scale ($S$) 和 Zero Point ($Z$) 是必备技能。
1. 均匀量化 (Uniform Quantization)
均匀量化是最主流的量化方式,它使用一个固定的比例因子 Scale ($S$) 和一个零点 Zero Point ($Z$) 来在浮点数 $r$(Real Value)和定点整数 $q$(Quantized Value)之间建立线性映射关系。
核心思想是:浮点数的范围 $[r_{min}, r_{max}]$ 线性地映射到整数的范围 $[q_{min}, q_{max}]$。
关系公式:
$$r \approx S(q – Z)$$
其中:
* $r$ 是原始浮点数。
* $q$ 是量化后的整数。
* $S$ 是比例因子(Scale),代表每个整数步长对应的浮点数值。
* $Z$ 是零点(Zero Point),表示浮点数 $0.0$ 映射到的整数值。
2. 如何计算 Scale ($S$) 和 Zero Point ($Z$)
计算 $S$ 和 $Z$ 的目标是确保浮点数的最小值 $r_{min}$ 映射到整数的最小值 $q_{min}$,以及 $r_{max}$ 映射到 $q_{max}$。我们以 8-bit 无符号量化($q_{min}=0, q_{max}=255$)为例进行推导。
步骤 1: 计算 Scale ($S$)
Scale $S$ 代表了量化范围的总长度比上整数范围的总长度:
$$S = \frac{r_{max} – r_{min}}{q_{max} – q_{min}}$$
步骤 2: 计算 Zero Point ($Z$)
Zero Point $Z$ 确保浮点数 $r=0$ 映射到的整数 $q$ 是 $Z$。我们可以利用 $r_{min}$ 和 $q_{min}$ 的关系来求解 $Z$。
从公式 $r = S(q – Z)$ 可得 $Z = q – r/S$。
将端点值代入:$r_{min} = S(q_{min} – Z)$,得到:
$$Z = q_{min} – \frac{r_{min}}{S}$$
由于 $Z$ 必须是整数,且必须落在整数范围 $[q_{min}, q_{max}]$ 内,我们需要进行四舍五入和截断(Clamping):
$$Z = \text{max}(q_{min}, \text{min}(q_{max}, \text{round}(q_{min} – \frac{r_{min}}{S})))$$
Python 示例:计算 S 和 Z
以下代码展示了如何使用 NumPy 计算 S 和 Z,并进行量化和反量化:
import numpy as np
def calculate_scale_and_zero_point(r_min, r_max, q_min, q_max):
# 1. 计算 Scale
S = (r_max - r_min) / (q_max - q_min)
# 2. 计算未截断的 Zero Point (基于 r_min)
Z_raw = q_min - (r_min / S)
# 3. 四舍五入到最近的整数
Z = int(np.round(Z_raw))
# 4. 截断 Zero Point 到合法范围 [q_min, q_max]
Z = np.clip(Z, q_min, q_max)
return S, Z
# 8-bit Unsigned Quantization Example (q_min=0, q_max=255)
r_min = -1.5
r_max = 2.5
q_min = 0
q_max = 255
S, Z = calculate_scale_and_zero_point(r_min, r_max, q_min, q_max)
print(f"Scale (S): {S:.6f}")
print(f"Zero Point (Z): {Z}")
# 验证量化与反量化
def quantize(r, S, Z):
q = np.round(r / S) + Z
return np.clip(q, q_min, q_max).astype(np.int32)
def dequantize(q, S, Z):
return S * (q - Z)
r_value = 0.5
q_value = quantize(r_value, S, Z)
r_reconstructed = dequantize(q_value, S, Z)
print(f"Original r: {r_value}")
print(f"Quantized q: {q_value}")
print(f"Reconstructed r: {r_reconstructed:.6f}")
# 输出: Scale (S): 0.015686, Zero Point (Z): 96
3. 均匀量化与非均匀量化的区别
| 特性 | 均匀量化 (Uniform Quantization) | 非均匀量化 (Non-Uniform Quantization) |
|---|---|---|
| 映射方式 | 线性映射 | 非线性映射 (通常基于对数或聚类) |
| 量化步长 | 恒定 ($S$) | 不恒定,步长随数值大小变化 |
| 计算复杂度 | 低,硬件友好 | 高,需要查表或复杂计算 |
| 零点 | 必须精确映射浮点数 0 | 通常不保证 0 的精确映射 |
| 适用场景 | 绝大多数主流硬件加速器和深度学习框架 (如TFLite, ONNX Runtime) | 需要更高精度或对权重分布有特殊要求的研究场景 (如VQ, Log Quantization) |
总结: 均匀量化由于其硬件实现的简易性,是目前工业界端侧部署模型量化的标准选择。非均匀量化理论上可以提供更好的精度,尤其对于那些服从长尾分布(heavy-tailed distribution)的权重,但实现和部署难度更高。
汤不热吧