均匀量化
均匀量化是一种将连续范围的数值(比如浮点数)转换为有限个离散值的过程,类似于用有限的 “箱子” 去装无限的数值。想象你有一堆不同身高的人(连续值),但你只能用几个固定的身高区间(比如 “150-160cm”、“160-170cm” 等)去分类他们,这就是量化的基本思想。
关键概念类比
-
缩放因子(Scale) 类似于 “箱子” 的宽度。如果缩放因子为 10,就相当于每个箱子能装 10 个单位的数值范围。
-
零点偏移(Zero Point) 类似于 “箱子” 的起始位置。比如零点偏移为 5,那么第一个箱子的范围就是从 5 开始。
-
量化位数 决定了 “箱子” 的数量。例如 8 位量化有 256 个箱子,4 位则只有 16 个箱子。
均匀量化的数学推导
1. 基本定义
给定一个浮点数 x,均匀量化将其映射为整数 q,再通过反量化恢复为近似值 \(\hat{x}\)。 正向量化公式:\(q = \text{round}\left(\frac{x - Z}{S}\right)\) 反向反量化公式:\(\hat{x} = S \cdot q + Z\) 其中:
- S 是缩放因子(scale),控制量化的 “粒度”;
- Z 是零点偏移(zero point),处理非对称分布;
- \(\text{round}\) 是取整函数(通常四舍五入)。
2. 缩放因子与零点的计算
假设浮点数 x 的取值范围是 \([x_{\text{min}}, x_{\text{max}}]\),量化后的整数范围是 \([q_{\text{min}}, q_{\text{max}}]\)(例如 4 位量化时为 \([-8, 7]\) 或 \([0, 15]\))。
缩放因子:\(S = \frac{x_{\text{max}} - x_{\text{min}}}{q_{\text{max}} - q_{\text{min}}}\)
直观理解:将浮点数范围 “压缩” 到整数范围内。
零点偏移:\(Z = q_{\text{min}} - \frac{x_{\text{min}}}{S}\)
直观理解:确保 \(x_{\text{min}}\) 映射到 \(q_{\text{min}}\)。
3. 非对称量化推导
当 \(x_{\text{min}} \neq 0\) 或 \(x_{\text{max}} \neq 0\) 时,需要非对称量化。
步骤 1:计算缩放因子 S\(S = \frac{x_{\text{max}} - x_{\text{min}}}{q_{\text{max}} - q_{\text{min}}}\)
步骤 2:计算零点偏移 Z
为保证 \(x_{\text{min}}\) 和 \(x_{\text{max}}\) 映射到正确的整数边界:\(q_{\text{min}} = \text{round}\left(\frac{x_{\text{min}}}{S}\right) + Z\)\(q_{\text{max}} = \text{round}\left(\frac{x_{\text{max}}}{S}\right) + Z\)
联立解得:\(Z = q_{\text{min}} - \text{round}\left(\frac{x_{\text{min}}}{S}\right)\)
通常需要调整 Z 为整数,确保量化后的 q 落在 \([q_{\text{min}}, q_{\text{max}}]\) 内。
4. 对称量化特例
当 \(x_{\text{min}} = -x_{\text{max}}\) 时(对称分布),零点偏移 \(Z = 0\),公式简化为:\(q = \text{round}\left(\frac{x}{S}\right)\)\(\hat{x} = S \cdot q\)
此时缩放因子:\(S = \frac{x_{\text{max}}}{q_{\text{max}}}\)
5. 量化误差分析
量化引入的误差为:\(\epsilon = x - \hat{x} = x - (S \cdot \text{round}\left(\frac{x - Z}{S}\right) + Z)\)
最大误差为 \(\pm \frac{S}{2}\),即缩放因子的一半。因此,减小 S 可以降低量化误差,但会减少可表示的数值范围。
均匀量化的 Python 实现示例
import numpy as np import matplotlib.pyplot as plt def uniform_quantize(x, bit_width=8, symmetric=False): """ 均匀量化实现 参数: x: 输入浮点数数组 bit_width: 量化位数 symmetric: 是否使用对称量化 返回: q: 量化后的整数 x_hat: 反量化后的近似浮点数 """ # 计算量化范围 q_min = - (2 ** (bit_width - 1)) # 例如8位为-128 q_max = (2 ** (bit_width - 1)) - 1 # 例如8位为127 # 确定输入范围 x_min = np.min(x) x_max = np.max(x) # 计算缩放因子和零点 if symmetric: # 对称量化 x_max = max(abs(x_min), abs(x_max)) x_min = -x_max S = x_max / q_max Z = 0 else: # 非对称量化 S = (x_max - x_min) / (q_max - q_min) Z = q_min - np.round(x_min / S) # 量化操作 q = np.round((x / S) - Z).astype(np.int32) # 裁剪超出范围的数值 q = np.clip(q, q_min, q_max) # 反量化操作 x_hat = S * (q + Z) return q, x_hat, S, Z # 示例:量化随机数据 np.random.seed(42) x = np.random.randn(1000) * 5 # 生成正态分布数据 # 执行8位量化 q, x_hat, S, Z = uniform_quantize(x, bit_width=8, symmetric=False) # 计算量化误差 error = x - x_hat # 可视化结果 plt.figure(figsize=(12, 4)) plt.subplot(1, 3, 1) plt.hist(x, bins=50, alpha=0.7, label='Original') plt.title('原始数据分布') plt.subplot(1, 3, 2) plt.hist(x_hat, bins=50, alpha=0.7, label='Quantized') plt.title('量化后数据分布') plt.subplot(1, 3, 3) plt.hist(error, bins=50, alpha=0.7, label='Error') plt.title('量化误差分布') plt.tight_layout() plt.show() print(f"缩放因子 S: {S:.4f}") print(f"零点偏移 Z: {Z}") print(f"最大误差: {np.max(np.abs(error)):.4f}") print(f"平均误差: {np.mean(np.abs(error)):.4f}")
总结
- 均匀量化通过缩放因子和零点偏移将连续值映射到有限整数空间。
- 对称量化简化计算,但可能浪费表示范围(尤其对于非对称分布)。
- 非对称量化更灵活,适用于任意分布的数据。
- 量化误差与缩放因子成正比,位数越高误差越小。
均匀量化是神经网络量化的基础,QLoRA 等高级方法在此基础上进一步优化,以平衡内存效率和模型精度。

浙公网安备 33010602011771号