均匀量化

均匀量化是一种将连续范围的数值(比如浮点数)转换为有限个离散值的过程,类似于用有限的 “箱子” 去装无限的数值。想象你有一堆不同身高的人(连续值),但你只能用几个固定的身高区间(比如 “150-160cm”、“160-170cm” 等)去分类他们,这就是量化的基本思想。

关键概念类比

  1. 缩放因子(Scale) 类似于 “箱子” 的宽度。如果缩放因子为 10,就相当于每个箱子能装 10 个单位的数值范围。
  2. 零点偏移(Zero Point) 类似于 “箱子” 的起始位置。比如零点偏移为 5,那么第一个箱子的范围就是从 5 开始。
  3. 量化位数 决定了 “箱子” 的数量。例如 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 等高级方法在此基础上进一步优化,以平衡内存效率和模型精度。
posted @ 2025-07-11 17:14  有何m不可  阅读(79)  评论(0)    收藏  举报