模型量化理论与实践(一)

量化技术的完整体系与可运行实现


目录

  • 第一部分:量化基础理论
    • 第一章:绪论------为什么需要模型量化
    • 第二章:量化的数学基础------标量量化
    • 第三章:信息论视角------率失真理论
  • 第二部分:权重量化方法
    • 第四章:训练后量化(PTQ)基础
    • 第五章:GPTQ------基于 Hessian 的量化
    • 第六章:AWQ------激活感知权重量化
    • 第七章:SmoothQuant 与 QuIP------进阶 PTQ 方法
  • 第三部分:激活量化与混合精度
    • 第八章:激活量化的挑战与异常值问题
    • 第九章:量化感知训练(QAT)
    • 第十章:W4A8 与 W8A8------权重-激活联合量化
  • 第四部分:量化格式与硬件
    • 第十一章:量化数据类型------从 INT4 到 FP8
    • 第十二章:量化推理引擎与硬件加速
  • 第五部分:完整可运行代码实现
    • 第十三章:从零实现标量量化系统
    • 第十四章:从零实现 GPTQ
    • 第十五章:从零实现 AWQ 与 SmoothQuant
    • 第十六章:完整 PTQ Pipeline 与精度对比
  • 第六部分:理论分析与前沿
    • 第十七章:量化的统一理论框架与 Scaling Law
  • 附录

第一部分:量化基础理论


第一章:绪论------为什么需要模型量化

1.1 大语言模型的存储与计算瓶颈

1.1.1 模型规模的增长趋势

现代大语言模型(LLM)的参数量呈指数增长:

模型 发布年份 参数量 权重格式 存储需求
GPT-2 2019 1.5B FP32 6 GB
GPT-3 2020 175B FP16 350 GB
LLaMA-65B 2023 65B FP16 130 GB
LLaMA-2-70B 2023 70B FP16 140 GB
Mixtral 8×7B 2024 47B(活跃 13B) FP16 94 GB
LLaMA-3-405B 2024 405B BF16 810 GB

这里涉及几个关键术语:

  • FP32(32 位浮点数,Single Precision) :1 位符号 + 8 位指数 + 23 位尾数,动态范围约 ±3.4×1038\pm 3.4 \times 10^{38}±3.4×1038,精度约 7 位有效十进制数字
  • FP16(16 位浮点数,Half Precision) :1 位符号 + 5 位指数 + 10 位尾数,动态范围约 ±6.5×104\pm 6.5 \times 10^4±6.5×104,精度约 3.3 位有效十进制数字
  • BF16(Brain Float 16):1 位符号 + 8 位指数 + 7 位尾数,与 FP32 相同的动态范围但精度更低(约 2.4 位有效数字)

1.1.2 推理时的内存瓶颈

模型推理时的内存占用由以下几部分组成:

1. 模型权重(Model Weights) :这是最大的内存消耗。对于参数量为 Φ\PhiΦ 的模型,使用 bbb 比特存储每个参数:

Mweights=Φ⋅b8 字节M_{\text{weights}} = \frac{\Phi \cdot b}{8} \text{ 字节}Mweights=8Φ⋅b 字节

2. KV 缓存(Key-Value Cache) :在自回归生成中,为了避免重复计算,需要缓存每一层、每个注意力头的历史 Key 和 Value 向量。对于序列长度 sss、层数 LLL、头数 hhh、头维度 dhd_hdh:

MKV=2⋅L⋅h⋅dh⋅s⋅bact/8 字节M_{\text{KV}} = 2 \cdot L \cdot h \cdot d_h \cdot s \cdot b_{\text{act}} / 8 \text{ 字节}MKV=2⋅L⋅h⋅dh⋅s⋅bact/8 字节

其中 bactb_{\text{act}}bact 是激活值的比特数,因子 2 来自同时存储 K 和 V。

3. 激活值(Activations):前向传播中各层的中间结果,大小取决于 batch size 和序列长度。

4. 运行时开销:包括计算图、临时缓冲区等。

1.1.3 计算瓶颈

Transformer 的核心计算是矩阵乘法。对于线性层 Y=XWY = XWY=XW,其中 X∈RB×dinX \in \mathbb{R}^{B \times d_{\text{in}}}X∈RB×din,W∈Rdin×doutW \in \mathbb{R}^{d_{\text{in}} \times d_{\text{out}}}W∈Rdin×dout:

FLOPs=2⋅B⋅din⋅dout\text{FLOPs} = 2 \cdot B \cdot d_{\text{in}} \cdot d_{\text{out}}FLOPs=2⋅B⋅din⋅dout

(每个输出元素需要 dind_{\text{in}}din 次乘法和 din−1d_{\text{in}} - 1din−1 次加法,近似为 2din2 d_{\text{in}}2din 次浮点运算。)

计算强度(Arithmetic Intensity) 定义为浮点运算次数与内存访问字节数的比值:

I=FLOPsBytes AccessedI = \frac{\text{FLOPs}}{\text{Bytes Accessed}}I=Bytes AccessedFLOPs

当 I<IpeakI < I_{\text{peak}}I<Ipeak(硬件的峰值计算强度)时,推理是内存带宽受限(Memory-Bandwidth Bound) 的------处理器在等待数据从内存传输,而非在计算。

定理 1.1(Transformer 推理的带宽受限性) :在自回归生成阶段(batch size B=1B = 1B=1),每个 token 的生成需要访问所有模型权重一次,但只进行 O(d2)O(d^2)O(d2) 次浮点运算。因此计算强度为:

I=2d22d2⋅(b/8)=8b FLOPs/ByteI = \frac{2 d^2}{2 d^2 \cdot (b/8)} = \frac{8}{b} \text{ FLOPs/Byte}I=2d2⋅(b/8)2d2=b8 FLOPs/Byte

对于 FP16(b=16b = 16b=16),I=0.5I = 0.5I=0.5 FLOPs/Byte。而现代 GPU(如 A100)的 Ipeak≈156I_{\text{peak}} \approx 156Ipeak≈156 FLOPs/Byte,内存带宽峰值为 2 TB/s。因此自回归推理严重受限于内存带宽。

量化如何帮助? 将权重量化为 INT4(b=4b = 4b=4)后,I=2I = 2I=2 FLOPs/Byte,内存访问量减少 4 倍,直接提升推理吞吐量。

1.2 量化的核心动机

量化(Quantization) 是将连续值(或高精度离散值)映射到低精度离散值的过程。在深度学习中,量化特将模型的权重和/或激活值从高精度格式(FP32/FP16/BF16)转换为低精度格式(INT8/INT4 等)。

量化带来的好处:

效益 说明 数学刻画
减少存储 每个参数的比特数从 16 降至 4-8 存储减少 2×2\times2×-4×4\times4×
减少内存带宽 推理时需要读取的数据量更少 带宽需求同比降低
加速计算 整数运算比浮点运算更快,且可利用专用指令 理论加速 2×2\times2×-4×4\times4×
降低能耗 整数运算的能耗远低于浮点运算 INT8 乘法能耗约为 FP16 的 1/301/301/30

1.3 量化方法的分类

量化方法按时机是否需要训练可以分为两大类:

1.3.1 训练后量化(Post-Training Quantization, PTQ)

在模型训练完成后,直接对权重(和/或激活值)进行量化,不需要重新训练

优点:简单快速,不需要训练数据的大量计算资源。

缺点:量化误差无法通过训练补偿,精度下降可能较大。

代表方法:RTN(Round-to-Nearest)、GPTQ、AWQ、SmoothQuant。

1.3.2 量化感知训练(Quantization-Aware Training, QAT)

在训练过程中模拟量化的效果,使模型学习适应量化误差

优点:精度通常优于 PTQ。

缺点:需要完整的训练流程,计算成本高。

代表方法:LSQ(Learned Step Size Quantization)、LLM-QAT。

1.3.3 量化方案的另一个维度

量化粒度分类:

粒度 说明 精度 开销
逐张量(Per-Tensor) 整个张量共用一组量化参数 最低 最小
逐通道(Per-Channel) 每个输出通道一组量化参数 中等 中等
逐组(Per-Group) 每 ggg 个元素一组量化参数 较高 较大
逐元素(Per-Element) 每个元素独立量化 最高 最大

对称性分类:

类型 说明 零点
对称量化 量化范围关于 0 对称 z=0z = 0z=0
非对称量化 量化范围可以不对称 z≠0z \neq 0z=0

第二章:量化的数学基础------标量量化

2.1 量化问题的形式化定义

2.1.1 标量量化

定义 2.1(标量量化) :给定连续随机变量 X∈xmin⁡,xmax⁡X \in x_{\\min}, x_{\\max}X∈xmin,xmax,bbb 比特标量量化是一个映射 Q:R→CQ: \mathbb{R} \to \mathcal{C}Q:R→C,其中码本(codebook)C={c0,c1,...,c2b−1}\mathcal{C} = \{c_0, c_1, \dots, c_{2^b - 1}\}C={c0,c1,...,c2b−1} 包含 2b2^b2b 个量化级别(quantization levels)。

量化过程分为两步:

  1. 编码(Encoding) :将连续值映射到离散索引

    i=Qenc(x)=arg⁡min⁡j∈{0,...,2b−1}∣x−cj∣i = Q_{\text{enc}}(x) = \arg\min_{j \in \{0, \dots, 2^b - 1\}} |x - c_j|i=Qenc(x)=argj∈{0,...,2b−1}min∣x−cj∣

  2. 解码(Decoding) :将离散索引映射回(近似的)连续值

    x^=Qdec(i)=ci\hat{x} = Q_{\text{dec}}(i) = c_ix^=Qdec(i)=ci

量化误差(Quantization Error) 定义为:

e=x−x^=x−Q(x)e = x - \hat{x} = x - Q(x)e=x−x^=x−Q(x)

2.1.2 仿射量化(Affine Quantization)

最常见的量化方案是仿射量化(也称为零点量化,zero-point quantization),它用一个线性映射将实数映射到整数:

i=round(xs)+zi = \text{round}\left(\frac{x}{s}\right) + zi=round(sx)+z

x^=s⋅(i−z)\hat{x} = s \cdot (i - z)x^=s⋅(i−z)

其中:

  • s>0s > 0s>0 是缩放因子(scale),也称为步长(step size)
  • z∈Zz \in \mathbb{Z}z∈Z 是零点(zero-point),确保实数零被精确表示
  • iii 是量化后的整数索引,取值范围为 0,2b−10, 2\^b - 10,2b−1(无符号)或 −2b−1,2b−1−1-2\^{b-1}, 2\^{b-1} - 1−2b−1,2b−1−1(有符号)

缩放因子和零点的计算

s=xmax⁡−xmin⁡2b−1s = \frac{x_{\max} - x_{\min}}{2^b - 1}s=2b−1xmax−xmin

z=round(−xmin⁡s)z = \text{round}\left(-\frac{x_{\min}}{s}\right)z=round(−sxmin)

这里 xmax⁡x_{\max}xmax 和 xmin⁡x_{\min}xmin 是待量化张量中的最大值和最小值(或它们的某种估计)。

2.1.3 对称量化(Symmetric Quantization)

对称量化是非对称量化的特例,强制 xmin⁡=−xmax⁡x_{\min} = -x_{\max}xmin=−xmax(即量化范围关于零对称),从而 z=0z = 0z=0:

i=round(xs)i = \text{round}\left(\frac{x}{s}\right)i=round(sx)

x^=s⋅i\hat{x} = s \cdot ix^=s⋅i

s=max⁡(∣xmax⁡∣,∣xmin⁡∣)2b−1−1s = \frac{\max(|x_{\max}|, |x_{\min}|)}{2^{b-1} - 1}s=2b−1−1max(∣xmax∣,∣xmin∣)

(对于有符号 bbb 比特整数。)

对称 vs 非对称量化的理论比较

定理 2.1 :对于均值为 μ≠0\mu \neq 0μ=0 的分布,非对称量化的均方误差(MSE)严格小于对称量化。

证明:设分布为 p(x)p(x)p(x),支撑集为 a,ba, ba,b,a<0<ba < 0 < ba<0<b,μ=EX≠0\mu = \mathbb{E}X \neq 0μ=EX=0。

对称量化使用区间 −Δ,Δ-\\Delta, \\Delta−Δ,Δ,其中 Δ=max⁡(∣a∣,∣b∣)\Delta = \max(|a|, |b|)Δ=max(∣a∣,∣b∣)。

非对称量化使用区间 a,ba, ba,b

非对称量化的量化区间 a,b−Δ,Δa, b \subset -\\Delta, \\Deltaa,b−Δ,Δ(除非 ∣a∣=∣b∣|a| = |b|∣a∣=∣b∣),因此在相同比特数下,非对称量化的步长更小:

sasym=b−a2b−1<2Δ2b−1=ssyms_{\text{asym}} = \frac{b - a}{2^b - 1} < \frac{2\Delta}{2^b - 1} = s_{\text{sym}}sasym=2b−1b−a<2b−12Δ=ssym

更小的步长意味着更小的量化误差。□\square□

实际意义:权重分布通常近似对称(均值接近零),适合对称量化;激活值分布通常不对称(经过 ReLU/GELU 后全为非负),适合非对称量化。

2.2 均匀量化(Uniform Quantization)

2.2.1 定义

定义 2.2(均匀量化) :如果所有量化级别 cic_ici 之间的间距相等,即 ci+1−ci=sc_{i+1} - c_i = sci+1−ci=s(常数),则称该量化为均匀量化。

均匀量化的码本为:

ci=s⋅i+z′,i=0,1,...,2b−1c_i = s \cdot i + z', \quad i = 0, 1, \dots, 2^b - 1ci=s⋅i+z′,i=0,1,...,2b−1

其中 z′z'z′ 是偏移量。

2.2.2 量化误差分析

定理 2.2(均匀量化的误差分布) :对于步长为 sss 的均匀量化,当输入信号在量化范围内充分"活跃"(即信号变化远大于步长)时,量化误差 e=x−Q(x)e = x - Q(x)e=x−Q(x) 近似服从均匀分布 U(−s/2,s/2)U(-s/2, s/2)U(−s/2,s/2)。

证明:设 xxx 落在某个量化区间 [ci−s/2,ci+s/2)[c_i - s/2, c_i + s/2)[ci−s/2,ci+s/2) 内,则:

e=x−ci∈[−s/2,s/2)e = x - c_i \in [-s/2, s/2)e=x−ci∈[−s/2,s/2)

当 xxx 在整个量化范围内均匀分布时(或至少在一个步长范围内近似均匀),误差 eee 在 [−s/2,s/2)[-s/2, s/2)[−s/2,s/2) 上近似均匀。□\square□

推论 2.1:均匀量化的均方误差(MSE)为:

MSE=Ee2=∫−s/2s/2e2⋅1sde=1s⋅e33∣−s/2s/2=s212\text{MSE} = \mathbb{E}e\^2 = \int_{-s/2}^{s/2} e^2 \cdot \frac{1}{s} de = \frac{1}{s} \cdot \frac{e^3}{3}\Big|_{-s/2}^{s/2} = \frac{s^2}{12}MSE=Ee2=∫−s/2s/2e2⋅s1de=s1⋅3e3 −s/2s/2=12s2

这个 s2/12s^2/12s2/12 公式是量化理论中最基本的结果之一,它告诉我们:量化噪声的方差与步长的平方成正比

2.2.3 信噪比(SNR)

定义 2.3(信号量化噪声比,SQNR)

SQNR=Ex2Ee2=σx2+μx2s2/12\text{SQNR} = \frac{\mathbb{E}x\^2}{\mathbb{E}e\^2} = \frac{\sigma_x^2 + \mu_x^2}{s^2 / 12}SQNR=Ee2Ex2=s2/12σx2+μx2

对于零均值信号(μx=0\mu_x = 0μx=0)和满量程对称量化(xmax⁡=s⋅2b−1x_{\max} = s \cdot 2^{b-1}xmax=s⋅2b−1),若信号的标准差 σx=xmax⁡/3\sigma_x = x_{\max} / 3σx=xmax/3(典型的 3-sigma 规则):

SQNR=(xmax⁡/3)2s2/12=xmax⁡2/9xmax⁡2/(12⋅4b−1)=4b⋅129⋅4=4b3\text{SQNR} = \frac{(x_{\max}/3)^2}{s^2/12} = \frac{x_{\max}^2 / 9}{x_{\max}^2 / (12 \cdot 4^{b-1})} = \frac{4^b \cdot 12}{9 \cdot 4} = \frac{4^b}{3}SQNR=s2/12(xmax/3)2=xmax2/(12⋅4b−1)xmax2/9=9⋅44b⋅12=34b

以 dB 为单位:

SQNR (dB)=10log⁡10(4b3)=6.02b−4.77 dB\text{SQNR (dB)} = 10 \log_{10}\left(\frac{4^b}{3}\right) = 6.02b - 4.77 \text{ dB}SQNR (dB)=10log10(34b)=6.02b−4.77 dB

这就是著名的 6 dB/bit 规则:每增加 1 比特量化精度,SQNR 提高约 6 dB。

比特数 bbb 理论 SQNR 步长数
8 43.3 dB 256
4 19.2 dB 16
3 13.2 dB 8
2 7.2 dB 4
1 1.2 dB 2

关键洞察:4 比特量化(16 个级别)的理论 SQNR 仅约 19 dB------这在信号处理中很低。但神经网络具有内在的容错能力(冗余性、正则化效应),使得 4 比特量化在实践中仍然可用。

2.3 非均匀量化(Non-Uniform Quantization)

2.3.1 为什么需要非均匀量化?

均匀量化假设信号分布近似均匀。但实际的神经网络权重和激活值通常服从非均匀分布------最常见的是近似正态分布或拉普拉斯分布。

对于正态分布 N(0,σ2)\mathcal{N}(0, \sigma^2)N(0,σ2),大部分概率质量集中在 −2σ,2σ-2\\sigma, 2\\sigma−2σ,2σ,但尾部延伸到很远。均匀量化必须覆盖整个范围,导致步长很大,在高概率区域的量化精度不足。

非均匀量化通过在高概率区域分配更多量化级别、在低概率区域分配更少级别,可以更高效地利用有限的比特数。

2.3.2 μ-law 压扩

μ-law 压扩(ITU-T G.711)是一种经典的非均匀量化方法,广泛用于语音编码。

压缩函数

F(x)=sgn(x)⋅ln⁡(1+μ∣x∣/xmax⁡)ln⁡(1+μ)F(x) = \text{sgn}(x) \cdot \frac{\ln(1 + \mu |x| / x_{\max})}{\ln(1 + \mu)}F(x)=sgn(x)⋅ln(1+μ)ln(1+μ∣x∣/xmax)

其中 μ\muμ 是压缩参数(通常 μ=255\mu = 255μ=255),xmax⁡x_{\max}xmax 是信号的最大绝对值。

扩展函数(逆变换):

F−1(y)=sgn(y)⋅xmax⁡μ(1+μ)∣y∣−1F^{-1}(y) = \text{sgn}(y) \cdot \frac{x_{\max}}{\mu} \left(1 + \\mu)\^{\|y\|} - 1\\rightF−1(y)=sgn(y)⋅μxmax(1+μ)∣y∣−1

μ-law 压缩将信号先进行非线性变换(压缩动态范围),然后进行均匀量化,最后在解码时进行逆变换(扩展)。

2.3.3 对数量化

对数量化使用对数函数作为压缩函数:

Qlog⁡(x)=sgn(x)⋅s⋅round(log⁡2(∣x∣/xmin⁡)s)Q_{\log}(x) = \text{sgn}(x) \cdot s \cdot \text{round}\left(\frac{\log_2(|x| / x_{\min})}{s}\right)Qlog(x)=sgn(x)⋅s⋅round(slog2(∣x∣/xmin))

对数量化的一个重要性质是相对误差恒定

∣x−x^∣∣x∣≤constant\frac{|x - \hat{x}|}{|x|} \leq \text{constant}∣x∣∣x−x^∣≤constant

这与均匀量化的绝对误差恒定 (∣x−x^∣≤s/2|x - \hat{x}| \leq s/2∣x−x^∣≤s/2)形成对比。

2.4 最优量化器:Lloyd-Max 算法

2.4.1 问题形式化

问题 :给定信号的概率密度函数 p(x)p(x)p(x) 和比特数 bbb,找到最优的码本 C={c0,...,cN−1}\mathcal{C} = \{c_0, \dots, c_{N-1}\}C={c0,...,cN−1}(N=2bN = 2^bN=2b)和决策边界 {t0,...,tN}\{t_0, \dots, t_{N}\}{t0,...,tN},使得均方量化误差最小:

min⁡C,{ti}MSE=∫−∞∞(x−Q(x))2p(x)dx=∑i=0N−1∫titi+1(x−ci)2p(x)dx\min_{\mathcal{C}, \{t_i\}} \text{MSE} = \int_{-\infty}^{\infty} (x - Q(x))^2 p(x) dx = \sum_{i=0}^{N-1} \int_{t_i}^{t_{i+1}} (x - c_i)^2 p(x) dxC,{ti}minMSE=∫−∞∞(x−Q(x))2p(x)dx=i=0∑N−1∫titi+1(x−ci)2p(x)dx

其中 t0=−∞t_0 = -\inftyt0=−∞,tN=+∞t_N = +\inftytN=+∞,t1,...,tN−1t_1, \dots, t_{N-1}t1,...,tN−1 是决策边界。

2.4.2 最优条件

定理 2.3(Lloyd-Max 最优条件):最优量化器满足以下两个必要条件:

条件 1(最近邻条件):每个样本被分配到最近的量化级别:

ti=ci−1+ci2,i=1,...,N−1t_i = \frac{c_{i-1} + c_i}{2}, \quad i = 1, \dots, N-1ti=2ci−1+ci,i=1,...,N−1

条件 2(质心条件):每个量化级别是其对应区间的条件期望:

ci=EX∣ti≤X\=∫titi+1x⋅p(x)dx∫titi+1p(x)dxc_i = \mathbb{E}X \| t_i \\leq X \< t_{i+1} = \frac{\int_{t_i}^{t_{i+1}} x \cdot p(x) dx}{\int_{t_i}^{t_{i+1}} p(x) dx}ci=EX∣ti≤X\=∫titi+1p(x)dx∫titi+1x⋅p(x)dx

证明:对 MSE 分别关于 cic_ici 和 tit_iti 求导并令其为零。

关于 cic_ici:

∂MSE∂ci=−2∫titi+1(x−ci)p(x)dx=0\frac{\partial \text{MSE}}{\partial c_i} = -2 \int_{t_i}^{t_{i+1}} (x - c_i) p(x) dx = 0∂ci∂MSE=−2∫titi+1(x−ci)p(x)dx=0

解得:ci=∫titi+1xp(x)dx∫titi+1p(x)dxc_i = \frac{\int_{t_i}^{t_{i+1}} x p(x) dx}{\int_{t_i}^{t_{i+1}} p(x) dx}ci=∫titi+1p(x)dx∫titi+1xp(x)dx。

关于 tit_iti(1≤i≤N−11 \leq i \leq N-11≤i≤N−1):

∂MSE∂ti=(ti−ci−1)2p(ti)−(ti−ci)2p(ti)=0\frac{\partial \text{MSE}}{\partial t_i} = (t_i - c_{i-1})^2 p(t_i) - (t_i - c_i)^2 p(t_i) = 0∂ti∂MSE=(ti−ci−1)2p(ti)−(ti−ci)2p(ti)=0

当 p(ti)>0p(t_i) > 0p(ti)>0 时,(ti−ci−1)2=(ti−ci)2(t_i - c_{i-1})^2 = (t_i - c_i)^2(ti−ci−1)2=(ti−ci)2,解得 ti=ci−1+ci2t_i = \frac{c_{i-1} + c_i}{2}ti=2ci−1+ci。□\square□

2.4.3 Lloyd-Max 算法

Lloyd-Max 算法(也称为迭代量化算法)交替执行上述两个条件,直至收敛:

算法 2.1(Lloyd-Max 算法)

复制代码
输入:概率密度 p(x),比特数 b,初始码本 {c_i^0}
输出:最优码本 {c_i*} 和决策边界 {t_i*}

重复:
  1. 计算决策边界:t_i = (c_{i-1} + c_i) / 2
  2. 更新码本:c_i = E[X | t_i ≤ X < t_{i+1}]
直到 收敛(码本变化 < 阈值)

定理 2.4(Lloyd-Max 算法的收敛性):Lloyd-Max 算法单调递减地收敛到 MSE 的一个局部最优解。即:

MSE(k+1)≤MSE(k)\text{MSE}^{(k+1)} \leq \text{MSE}^{(k)}MSE(k+1)≤MSE(k)

证明:每一步分别对 cic_ici 或 tit_iti 进行最优更新,MSE 不会增加。由于 MSE 有下界(≥0\geq 0≥0),序列收敛。□\square□

2.5 量化噪声的统计分析

2.5.1 加性噪声模型

将量化视为在原始信号上叠加一个加性噪声:

x^=Q(x)=x+e\hat{x} = Q(x) = x + ex^=Q(x)=x+e

其中 e=Q(x)−xe = Q(x) - xe=Q(x)−x 是量化噪声。

定理 2.5(量化噪声的经典假设):在以下条件下:

  1. 量化步长 sss 足够小
  2. 信号在量化区间内变化充分
  3. 信号与量化噪声不相关

量化噪声满足:

  1. e∼U(−s/2,s/2)e \sim U(-s/2, s/2)e∼U(−s/2,s/2)(均匀分布)
  2. Ee=0\mathbb{E}e = 0Ee=0(零均值)
  3. Vare=s2/12\text{Var}e = s^2 / 12Vare=s2/12
  4. eee 与 xxx 不相关:Exe=0\mathbb{E}xe = 0Exe=0

证明:条件 1 和 2 由定理 2.2 得到。条件 3 由推论 2.1 得到。

对于条件 4,设 xxx 落在第 iii 个量化区间 [ci−s/2,ci+s/2)[c_i - s/2, c_i + s/2)[ci−s/2,ci+s/2),e=x−cie = x - c_ie=x−ci:

Exe∣x∈区间i=E(ci+e)e∣x∈区间i=ciEe⏟=0+Ee2=s2/12\mathbb{E}xe \| x \\in \\text{区间} i = \mathbb{E}(c_i + e)e \| x \\in \\text{区间} i = c_i \underbrace{\mathbb{E}e}_{=0} + \mathbb{E}e\^2 = s^2/12Exe∣x∈区间i=E(ci+e)e∣x∈区间i=ci=0 Ee+Ee2=s2/12

当信号在各区间均匀分布时,cic_ici 的均值为零(对于对称分布),因此 Exe≈0\mathbb{E}xe \approx 0Exe≈0。□\square□

2.5.2 加性噪声模型的局限

注意 :上述加性噪声模型是近似的。当以下条件不满足时,模型失效:

  1. 信号幅度很小(接近零):此时多个连续值可能被量化到同一个级别,噪声不再是均匀分布
  2. 过载(Clipping) :当信号超出量化范围时,误差远大于 s/2s/2s/2
  3. 信号变化缓慢:相邻样本的量化误差高度相关,不再是白噪声

2.6 数值实现

python 复制代码
import numpy as np
import matplotlib.pyplot as plt


def uniform_quantize(x: np.ndarray, num_bits: int, symmetric: bool = True) -> tuple:
    """均匀量化。

    Args:
        x: 输入数组
        num_bits: 量化比特数
        symmetric: 是否使用对称量化

    Returns:
        x_q: 量化后的值
        scale: 缩放因子
        zero_point: 零点
    """
    if symmetric:
        abs_max = np.max(np.abs(x))
        abs_max = max(abs_max, 1e-8)  # 避免除零
        qmax = 2 ** (num_bits - 1) - 1
        qmin = -2 ** (num_bits - 1)
        scale = abs_max / qmax
        zero_point = 0
    else:
        x_min, x_max = np.min(x), np.max(x)
        qmax = 2 ** num_bits - 1
        qmin = 0
        scale = (x_max - x_min) / (qmax - qmin)
        scale = max(scale, 1e-10)
        zero_point = np.round(qmin - x_min / scale).astype(int)

    # 编码:实数 -> 整数索引
    x_int = np.clip(np.round(x / scale) + zero_point, qmin, qmax).astype(int)

    # 解码:整数索引 -> 实数
    x_q = (x_int - zero_point).astype(float) * scale

    return x_q, scale, zero_point


def demonstrate_quantization_basics():
    """演示量化基础:误差分析、比特数影响。"""
    np.random.seed(42)

    # 生成正态分布信号
    n = 10000
    x = np.random.randn(n) * 3.0  # N(0, 9)

    print("=" * 70)
    print("均匀量化基础演示")
    print("=" * 70)
    print(f"信号: {n} 个样本, 均值={x.mean():.4f}, 标准差={x.std():.4f}")
    print()

    for bits in [8, 4, 3, 2, 1]:
        x_q, scale, zp = uniform_quantize(x, bits, symmetric=True)
        mse = np.mean((x - x_q) ** 2)
        theoretical_mse = scale ** 2 / 12

        # SQNR
        sqnr = 10 * np.log10(np.mean(x ** 2) / mse)
        theoretical_sqnr = 6.02 * bits - 4.77

        print(f"  {bits}-bit 量化:")
        print(f"    步长 s = {scale:.6f}")
        print(f"    实际 MSE = {mse:.6f}, 理论 MSE (s²/12) = {theoretical_mse:.6f}")
        print(f"    实际 SQNR = {sqnr:.2f} dB, 理论 SQNR = {theoretical_sqnr:.2f} dB")
        print(f"    量化级别数: {2**bits}")
        print()


def demonstrate_symmetric_vs_asymmetric():
    """演示对称 vs 非对称量化。"""
    np.random.seed(42)

    # 非对称分布(模拟 ReLU 后的激活值)
    x = np.abs(np.random.randn(5000)) * 2.0  # 半正态分布

    print("=" * 70)
    print("对称 vs 非对称量化对比")
    print("=" * 70)
    print(f"信号: 半正态分布, 均值={x.mean():.4f}, 范围=[{x.min():.4f}, {x.max():.4f}]")
    print()

    for bits in [8, 4, 3]:
        # 对称量化
        x_q_sym, _, _ = uniform_quantize(x, bits, symmetric=True)
        mse_sym = np.mean((x - x_q_sym) ** 2)

        # 非对称量化
        x_q_asym, _, _ = uniform_quantize(x, bits, symmetric=False)
        mse_asym = np.mean((x - x_q_asym) ** 2)

        improvement = (mse_sym - mse_asym) / mse_sym * 100

        print(f"  {bits}-bit:")
        print(f"    对称量化 MSE:   {mse_sym:.6f}")
        print(f"    非对称量化 MSE: {mse_asym:.6f}")
        print(f"    非对称改善:     {improvement:.1f}%")
        print()


def lloyd_max_quantizer(x: np.ndarray, num_bits: int, max_iter: int = 100, tol: float = 1e-8) -> tuple:
    """Lloyd-Max 最优量化器。

    通过迭代优化找到最优的量化级别和决策边界。

    Args:
        x: 输入信号
        num_bits: 量化比特数
        max_iter: 最大迭代次数
        tol: 收敛阈值

    Returns:
        codebook: 最优码本
        boundaries: 决策边界
        mse: 均方误差
    """
    N = 2 ** num_bits

    # 用经验分位数初始化码本
    percentiles = np.linspace(0, 100, N + 1)
    boundaries = np.percentile(x, percentiles)
    codebook = np.array([
        np.mean(x[(x >= boundaries[i]) & (x < boundaries[i + 1])])
        if np.sum((x >= boundaries[i]) & (x < boundaries[i + 1])) > 0
        else (boundaries[i] + boundaries[i + 1]) / 2
        for i in range(N)
    ])

    prev_mse = np.inf
    for iteration in range(max_iter):
        # 步骤 1: 更新决策边界(最近邻条件)
        boundaries = np.concatenate([
            [-np.inf],
            (codebook[:-1] + codebook[1:]) / 2,
            [np.inf]
        ])

        # 步骤 2: 更新码本(质心条件)
        for i in range(N):
            mask = (x >= boundaries[i]) & (x < boundaries[i + 1])
            if np.sum(mask) > 0:
                codebook[i] = np.mean(x[mask])

        # 计算 MSE
        # 量化每个样本
        x_q = np.zeros_like(x)
        for i in range(N):
            mask = (x >= boundaries[i]) & (x < boundaries[i + 1])
            x_q[mask] = codebook[i]

        mse = np.mean((x - x_q) ** 2)

        if abs(prev_mse - mse) < tol:
            break
        prev_mse = mse

    return codebook, boundaries, mse


def compare_uniform_vs_lloyd_max():
    """对比均匀量化和 Lloyd-Max 量化。"""
    np.random.seed(42)

    # 标准正态分布
    x = np.random.randn(50000)

    print("=" * 70)
    print("均匀量化 vs Lloyd-Max 最优量化")
    print("=" * 70)
    print(f"信号: 标准正态分布 N(0,1), {len(x)} 个样本")
    print()
    print(f"  {'比特数':>6} {'均匀 MSE':>15} {'Lloyd-Max MSE':>15} {'改善':>10}")
    print(f"  {'-'*6} {'-'*15} {'-'*15} {'-'*10}")

    for bits in [4, 3, 2]:
        # 均匀量化
        x_q_uniform, _, _ = uniform_quantize(x, bits, symmetric=True)
        mse_uniform = np.mean((x - x_q_uniform) ** 2)

        # Lloyd-Max 量化
        codebook, _, mse_lloyd = lloyd_max_quantizer(x, bits)

        improvement = (mse_uniform - mse_lloyd) / mse_uniform * 100

        print(f"  {bits:>6} {mse_uniform:>15.6f} {mse_lloyd:>15.6f} {improvement:>9.1f}%")


if __name__ == "__main__":
    demonstrate_quantization_basics()
    print()
    demonstrate_symmetric_vs_asymmetric()
    print()
    compare_uniform_vs_lloyd_max()

第三章:信息论视角------率失真理论

3.1 熵与信息量

3.1.1 信息熵

定义 3.1(香农信息熵) :离散随机变量 XXX 取值于 {x1,...,xn}\{x_1, \dots, x_n\}{x1,...,xn},概率为 pi=P(X=xi)p_i = P(X = x_i)pi=P(X=xi),其信息熵定义为:

H(X)=−∑i=1npilog⁡2piH(X) = -\sum_{i=1}^{n} p_i \log_2 p_iH(X)=−i=1∑npilog2pi

信息熵衡量了随机变量的不确定性------或者说,编码该随机变量的最优平均比特数。

关键性质

  1. H(X)≥0H(X) \geq 0H(X)≥0,等号成立当且仅当 XXX 是确定性的
  2. H(X)≤log⁡2nH(X) \leq \log_2 nH(X)≤log2n,等号成立当且仅当 XXX 是均匀分布的
  3. 对于连续随机变量,使用微分熵:h(X)=−∫p(x)log⁡2p(x)dxh(X) = -\int p(x) \log_2 p(x) dxh(X)=−∫p(x)log2p(x)dx

3.1.2 量化与熵编码

量化后的索引 i=Qenc(x)i = Q_{\text{enc}}(x)i=Qenc(x) 是一个离散随机变量,其概率为:

pi=P(Qenc(X)=i)=∫titi+1p(x)dxp_i = P(Q_{\text{enc}}(X) = i) = \int_{t_i}^{t_{i+1}} p(x) dxpi=P(Qenc(X)=i)=∫titi+1p(x)dx

根据香农信源编码定理,无损编码这些索引至少需要 H(Q(X))H(Q(X))H(Q(X)) 比特/样本。

定理 3.1(量化后的熵):均匀量化器的输出熵为:

H(Q(X))=−∑i=02b−1pilog⁡2piH(Q(X)) = -\sum_{i=0}^{2^b - 1} p_i \log_2 p_iH(Q(X))=−i=0∑2b−1pilog2pi

当信号均匀分布时,pi=1/2bp_i = 1/2^bpi=1/2b,H=bH = bH=b 比特------每个量化级别等概率,需要完整 bbb 比特来编码。

当信号高度非均匀时(如正态分布),H<bH < bH<b------某些量化级别出现频率更高,可以用更短的编码。

实际意义 :这启发了熵编码量化(Entropy-Coded Quantization) ------先量化,再用算术编码或霍夫曼编码压缩量化索引,实际比特率可以低于 bbb。

3.2 率失真理论

3.2.1 率失真函数

定义 3.2(率失真函数) :给定信源 XXX 和失真度量 d(x,x^)d(x, \hat{x})d(x,x^),率失真函数 R(D)R(D)R(D) 定义为在失真不超过 DDD 的约束下,编码所需的最小比特率:

R(D)=min⁡p(x^∣x):Ed(X,X\^)≤DI(X;X^)R(D) = \min_{p(\hat{x}|x): \mathbb{E}d(X, \\hat{X}) \leq D} I(X; \hat{X})R(D)=p(x^∣x):Ed(X,X\^)≤DminI(X;X^)

其中 I(X;X^)I(X; \hat{X})I(X;X^) 是 XXX 和 X^\hat{X}X^ 之间的互信息(mutual information):

I(X;X^)=∫∫p(x,x^)log⁡2p(x,x^)p(x)p(x^)dx dx^I(X; \hat{X}) = \int \int p(x, \hat{x}) \log_2 \frac{p(x, \hat{x})}{p(x) p(\hat{x})} dx \, d\hat{x}I(X;X^)=∫∫p(x,x^)log2p(x)p(x^)p(x,x^)dxdx^

互信息衡量了 X^\hat{X}X^ 关于 XXX 的信息量------即量化后保留了多少原始信息。

3.2.2 高斯信源的率失真函数

定理 3.2(高斯信源的率失真函数) :对于 X∼N(0,σ2)X \sim \mathcal{N}(0, \sigma^2)X∼N(0,σ2) 和均方误差失真 d(x,x^)=(x−x^)2d(x, \hat{x}) = (x - \hat{x})^2d(x,x^)=(x−x^)2:

R(D)={12log⁡2σ2Dif 0≤D≤σ20if D>σ2R(D) = \begin{cases} \frac{1}{2} \log_2 \frac{\sigma^2}{D} & \text{if } 0 \leq D \leq \sigma^2 \\ 0 & \text{if } D > \sigma^2 \end{cases}R(D)={21log2Dσ20if 0≤D≤σ2if D>σ2

证明(逆定理方向):由数据处理不等式和高斯分布的性质。

设 X^\hat{X}X^ 是 XXX 的任意估计,E(X−X\^)2≤D\mathbb{E}(X - \\hat{X})\^2 \leq DE(X−X\^)2≤D。则:

I(X;X^)=h(X)−h(X∣X^)≥h(X)−h(X−X^)I(X; \hat{X}) = h(X) - h(X | \hat{X}) \geq h(X) - h(X - \hat{X})I(X;X^)=h(X)−h(X∣X^)≥h(X)−h(X−X^)

由高斯分布的最大熵性质:h(X−X^)≤12log⁡2(2πeD)h(X - \hat{X}) \leq \frac{1}{2} \log_2(2\pi e D)h(X−X^)≤21log2(2πeD)

因此:I(X;X^)≥12log⁡2(2πeσ2)−12log⁡2(2πeD)=12log⁡2σ2DI(X; \hat{X}) \geq \frac{1}{2} \log_2(2\pi e \sigma^2) - \frac{1}{2} \log_2(2\pi e D) = \frac{1}{2} \log_2 \frac{\sigma^2}{D}I(X;X^)≥21log2(2πeσ2)−21log2(2πeD)=21log2Dσ2。□\square□

推论 3.1 :要将高斯信源的均方误差失真限制在 DDD 以下,至少需要:

b≥12log⁡2σ2D 比特/样本b \geq \frac{1}{2} \log_2 \frac{\sigma^2}{D} \text{ 比特/样本}b≥21log2Dσ2 比特/样本

等价地,使用 bbb 比特能达到的最小失真为:

Dmin⁡=σ2⋅2−2b=σ24bD_{\min} = \sigma^2 \cdot 2^{-2b} = \frac{\sigma^2}{4^b}Dmin=σ2⋅2−2b=4bσ2

这与均匀量化的 s2/12s^2/12s2/12 公式对比:

方法 MSE 公式 说明
均匀量化 s2/12s^2 / 12s2/12 简单但非最优
Lloyd-Max Dmax⁡2⋅ϵ(b)D_{\max}^2 \cdot \epsilon(b)Dmax2⋅ϵ(b) 最优标量量化
率失真下界 σ2/4b\sigma^2 / 4^bσ2/4b 理论下界,需要矢量量化逼近

3.2.3 率失真函数的物理含义

R(D)R(D)R(D) 函数告诉我们一个深刻的道理:

比特率=R(D)≈12log⁡2σ2D  ⟹  D≈σ2⋅4−R\text{比特率} = R(D) \approx \frac{1}{2} \log_2 \frac{\sigma^2}{D} \implies D \approx \sigma^2 \cdot 4^{-R}比特率=R(D)≈21log2Dσ2⟹D≈σ2⋅4−R

  • 每增加 1 比特 ,失真减少为原来的 1/41/41/4(即 -6 dB,与前面的 6 dB/bit 规则一致)
  • 失真与方差成正比:信号方差越大,需要更多比特来达到相同精度
  • 存在理论下界 :无论用什么方法,bbb 比特量化不可能达到低于 σ2/4b\sigma^2/4^bσ2/4b 的 MSE

3.3 矢量量化与标量量化的差距

3.3.1 矢量量化

矢量量化(Vector Quantization, VQ) 将 kkk 个标量样本组成一个矢量 x=(x1,...,xk)∈Rk\mathbf{x} = (x_1, \dots, x_k) \in \mathbb{R}^kx=(x1,...,xk)∈Rk,然后在 Rk\mathbb{R}^kRk 空间中整体量化。

矢量量化的码本包含 NNN 个 kkk 维码字:C={c1,...,cN}\mathcal{C} = \{\mathbf{c}_1, \dots, \mathbf{c}_N\}C={c1,...,cN}。

编码:i=arg⁡min⁡j∥x−cj∥2i = \arg\min_j \|\mathbf{x} - \mathbf{c}_j\|^2i=argminj∥x−cj∥2

3.3.2 矢量量化的优势

定理 3.3(矢量量化的渐近最优性) :随着矢量维度 k→∞k \to \inftyk→∞,矢量量化的性能可以逼近率失真函数 R(D)R(D)R(D)。

定理 3.4(标量量化的次优性) :标量量化的性能一般无法 达到率失真函数。两者之间的差距称为率失真差距(rate-distortion gap)

对于高斯信源,kkk 维矢量量化的渐近 MSE 为:

Dk≈σ24b⋅kk+1⋅Vk2/kD_k \approx \frac{\sigma^2}{4^b} \cdot \frac{k}{k+1} \cdot V_k^{2/k}Dk≈4bσ2⋅k+1k⋅Vk2/k

其中 VkV_kVk 是 kkk 维单位球的体积。当 k→∞k \to \inftyk→∞ 时,Dk→σ2/4bD_k \to \sigma^2 / 4^bDk→σ2/4b(率失真下界)。

实际意义:理论上,将多个权重一起量化(矢量量化)可以比逐个量化(标量量化)更高效。但矢量量化的编码复杂度随维度指数增长,实际中通常使用结构化的矢量量化(如格量化、乘积量化)。

3.4 量化比特数的理论下界

3.4.1 给定精度要求的最低比特数

问题 :对于一个参数矩阵 W∈Rm×nW \in \mathbb{R}^{m \times n}W∈Rm×n,如果要求量化后的模型精度(如任务准确率)下降不超过 ϵ\epsilonϵ,最少需要多少比特?

定理 3.5(量化精度-比特数关系) :设模型输出为 f(x;W)f(x; W)f(x;W),量化后的输出为 f(x;W^)f(x; \hat{W})f(x;W^)。在权重扰动的一阶近似下:

∣f(x;W)−f(x;W^)∣≤∥∇Wf∥∗⋅∥W−W^∥F|f(x; W) - f(x; \hat{W})| \leq \|\nabla_W f\|_* \cdot \|W - \hat{W}\|_F∣f(x;W)−f(x;W^)∣≤∥∇Wf∥∗⋅∥W−W^∥F

其中 ∥⋅∥∗\|\cdot\|_*∥⋅∥∗ 是核范数。

如果使用 bbb 比特均匀量化,∥W−W^∥F2≈mn⋅s212\|W - \hat{W}\|_F^2 \approx \frac{mn \cdot s^2}{12}∥W−W^∥F2≈12mn⋅s2。因此:

b≥12log⁡2mn⋅max⁡iσi(W)212ϵ2/∥∇Wf∥∗2b \geq \frac{1}{2} \log_2 \frac{mn \cdot \max_i \sigma_i(W)^2}{12 \epsilon^2 / \|\nabla_W f\|_*^2}b≥21log212ϵ2/∥∇Wf∥∗2mn⋅maxiσi(W)2

3.4.2 不同层的量化敏感度

观察:模型中不同层对量化的敏感度不同。量化误差通过网络逐层传播,越靠近输出的层,其误差对最终输出的影响越大。

定理 3.6(误差传播) :对于 LLL 层的顺序网络 f=fL∘fL−1∘⋯∘f1f = f_L \circ f_{L-1} \circ \dots \circ f_1f=fL∘fL−1∘⋯∘f1,第 lll 层的量化误差 δl\delta_lδl 传播到输出的上界为:

∥δoutput∥≤∥δl∥⋅∏j=l+1L∥Jj∥\|\delta_{\text{output}}\| \leq \|\delta_l\| \cdot \prod_{j=l+1}^{L} \|J_j\|∥δoutput∥≤∥δl∥⋅j=l+1∏L∥Jj∥

其中 Jj=∂fj/∂xJ_j = \partial f_j / \partial xJj=∂fj/∂x 是第 jjj 层的 Jacobian 矩阵。

实际含义 :对梯度较大Jacobian 谱范数较大的层,量化应该更谨慎(使用更多比特)。

python 复制代码
import numpy as np
from numpy.linalg import norm


def rate_distortion_gaussian(sigma_sq: float, bits: float) -> float:
    """计算高斯信源的率失真函数值。

    Args:
        sigma_sq: 信号方差
        bits: 比特率

    Returns:
        D: 最小可达到的 MSE
    """
    return sigma_sq * (2 ** (-2 * bits))


def entropy_of_quantized_gaussian(sigma: float, num_bits: int, num_samples: int = 100000) -> float:
    """计算高斯分布均匀量化后的熵。

    Args:
        sigma: 标准差
        num_bits: 量化比特数
        num_samples: 样本数

    Returns:
        H: 量化后的熵 (bits)
    """
    x = np.random.randn(num_samples) * sigma
    x_q, scale, _ = uniform_quantize(x, num_bits, symmetric=True)

    # 统计各量化级别的概率
    unique_vals, counts = np.unique(x_q, return_counts=True)
    probs = counts / counts.sum()

    # 熵
    H = -np.sum(probs * np.log2(probs))
    return H


def demonstrate_rate_distortion():
    """演示率失真理论。"""
    np.random.seed(42)

    print("=" * 70)
    print("率失真理论演示")
    print("=" * 70)

    sigma_sq = 1.0
    print(f"信号: 高斯分布 N(0, {sigma_sq})")
    print()
    print(f"  {'比特数 b':>10} {'理论下界 D':>15} {'均匀量化 MSE':>15} {'Lloyd-Max MSE':>15} {'差距(dB)':>12}")
    print(f"  {'-'*10} {'-'*15} {'-'*15} {'-'*15} {'-'*12}")

    x = np.random.randn(100000) * np.sqrt(sigma_sq)

    for bits in [8, 4, 3, 2]:
        # 率失真下界
        D_rd = rate_distortion_gaussian(sigma_sq, bits)

        # 均匀量化
        x_q_uniform, scale, _ = uniform_quantize(x, bits, symmetric=True)
        mse_uniform = np.mean((x - x_q_uniform) ** 2)

        # Lloyd-Max
        codebook, _, mse_lloyd = lloyd_max_quantizer(x, bits)

        # 差距
        gap_db = 10 * np.log10(mse_lloyd / D_rd)

        print(f"  {bits:>10} {D_rd:>15.6f} {mse_uniform:>15.6f} {mse_lloyd:>15.6f} {gap_db:>12.2f}")


def demonstrate_entropy_coding():
    """演示熵编码量化的优势。"""
    np.random.seed(42)

    print("\n" + "=" * 70)
    print("量化后熵 vs 固定比特数")
    print("=" * 70)

    sigma = 1.0
    print(f"信号: 高斯分布 N(0, {sigma})")
    print()
    print(f"  {'量化比特':>10} {'固定比特率':>12} {'实际熵':>12} {'节省':>10}")
    print(f"  {'-'*10} {'-'*12} {'-'*12} {'-'*10}")

    for bits in [8, 4, 3, 2]:
        H = entropy_of_quantized_gaussian(sigma, bits)
        savings = (bits - H) / bits * 100
        print(f"  {bits:>10} {bits:>12.1f} {H:>12.3f} {savings:>9.1f}%")


if __name__ == "__main__":
    demonstrate_rate_distortion()
    demonstrate_entropy_coding()

第二部分:权重量化方法


第四章:训练后量化(PTQ)基础

4.1 Round-to-Nearest(RTN)量化

4.1.1 基本定义

Round-to-Nearest(RTN) 是最简单的量化方法------直接将每个权重值四舍五入到最近的量化级别:

w^=s⋅round(ws)\hat{w} = s \cdot \text{round}\left(\frac{w}{s}\right)w^=s⋅round(sw)

其中步长 sss 的选择至关重要。

4.1.2 最优步长的选择

问题 :对于给定的权重张量 WWW 和比特数 bbb,如何选择最优的步长 s∗s^*s∗ 使量化误差最小?

s∗=arg⁡min⁡s>0∥W−Qs(W)∥F2s^* = \arg\min_{s > 0} \|W - Q_s(W)\|_F^2s∗=args>0min∥W−Qs(W)∥F2

定理 4.1(最优步长的一阶条件):在连续近似下(忽略 round 操作的离散性),最优步长满足:

s∗=12⋅MSEtarget1=12mn∑i,jwij2⋅12bs^* = \sqrt{\frac{12 \cdot \text{MSE}{\text{target}}}{1}} = \sqrt{\frac{12}{mn} \sum{i,j} w_{ij}^2} \cdot \frac{1}{2^b}s∗=112⋅MSEtarget =mn12i,j∑wij2 ⋅2b1

但在实践中,更常用的是基于绝对最大值(absmax) 的方法:

sabsmax=max⁡i,j∣wij∣2b−1−1s_{\text{absmax}} = \frac{\max_{i,j} |w_{ij}|}{2^{b-1} - 1}sabsmax=2b−1−1maxi,j∣wij∣

或基于分位数(percentile) 的方法:

spercentile=Percentile99.99(∣W∣)2b−1−1s_{\text{percentile}} = \frac{\text{Percentile}_{99.99}(|W|)}{2^{b-1} - 1}spercentile=2b−1−1Percentile99.99(∣W∣)

定理 4.2(absmax 量化的最优性) :对于对称分布(如正态分布),absmax 量化在所有对称均匀量化方案中最小化 MSE,当且仅当分布的支撑集恰好等于 −s⋅(2b−1−1),s⋅(2b−1−1)-s \\cdot (2\^{b-1} - 1), s \\cdot (2\^{b-1} - 1)−s⋅(2b−1−1),s⋅(2b−1−1)

但实际上,由于正态分布有无限支撑集,总会有一些值超出量化范围(过载),导致额外误差。

4.1.3 过载误差与颗粒误差

量化的总误差可以分解为两部分:

MSEtotal=MSEgranular+MSEoverload\text{MSE}{\text{total}} = \text{MSE}{\text{granular}} + \text{MSE}_{\text{overload}}MSEtotal=MSEgranular+MSEoverload

颗粒误差(Granular Error) :在量化范围内的误差,来自有限精度的离散化。对于步长 sss:

MSEgranular≈s212\text{MSE}_{\text{granular}} \approx \frac{s^2}{12}MSEgranular≈12s2

过载误差(Overload Error) :当信号值超出量化范围 −xmax⁡,xmax⁡-x_{\\max}, x_{\\max}−xmax,xmax 时产生的截断误差:

MSEoverload=2∫xmax⁡∞(x−xmax⁡)2p(x)dx\text{MSE}{\text{overload}} = 2 \int{x_{\max}}^{\infty} (x - x_{\max})^2 p(x) dxMSEoverload=2∫xmax∞(x−xmax)2p(x)dx

权衡 :增大步长 sss(扩大量化范围)减少过载误差但增加颗粒误差;减小步长 sss(缩小量化范围)反之。最优步长使两者的和最小。

4.2 逐通道量化与逐组量化

4.2.1 逐张量量化的局限

逐张量量化(Per-Tensor Quantization) 对整个权重张量使用同一组量化参数(s,zs, zs,z)。当张量中不同通道(或不同行/列)的数值范围差异很大时,这会导致严重的精度损失。

例子 :考虑一个权重矩阵 W∈R3×4W \in \mathbb{R}^{3 \times 4}W∈R3×4:

W=(0.10.20.150.055.06.05.54.50.010.020.0150.005)W = \begin{pmatrix} 0.1 & 0.2 & 0.15 & 0.05 \\ 5.0 & 6.0 & 5.5 & 4.5 \\ 0.01 & 0.02 & 0.015 & 0.005 \end{pmatrix}W= 0.15.00.010.26.00.020.155.50.0150.054.50.005

逐张量量化时,xmax⁡=6.0x_{\max} = 6.0xmax=6.0,步长 s=6.0/7≈0.857s = 6.0 / 7 \approx 0.857s=6.0/7≈0.857(4 比特)。

第一行的值(0.05-0.2)占步长的很小一部分,量化后精度极差。第三行更是几乎全部量化为零。

4.2.2 逐通道量化

逐通道量化(Per-Channel Quantization) 为每个输出通道(行或列)使用独立的量化参数:

sc=max⁡j∣wcj∣2b−1−1s_c = \frac{\max_j |w_{cj}|}{2^{b-1} - 1}sc=2b−1−1maxj∣wcj∣

w^cj=sc⋅round(wcjsc)\hat{w}{cj} = s_c \cdot \text{round}\left(\frac{w{cj}}{s_c}\right)w^cj=sc⋅round(scwcj)

定理 4.3(逐通道量化的误差上界) :设权重矩阵 WWW 的第 ccc 行的最大绝对值为 Mc=max⁡j∣wcj∣M_c = \max_j |w_{cj}|Mc=maxj∣wcj∣,则:

MSEper-channel=1mn∑c=1mMc212(2b−1−1)2⋅n=112m(2b−1−1)2∑c=1mMc2\text{MSE}{\text{per-channel}} = \frac{1}{mn} \sum{c=1}^{m} \frac{M_c^2}{12(2^{b-1} - 1)^2} \cdot n = \frac{1}{12m(2^{b-1} - 1)^2} \sum_{c=1}^{m} M_c^2MSEper-channel=mn1c=1∑m12(2b−1−1)2Mc2⋅n=12m(2b−1−1)21c=1∑mMc2

而逐张量量化的 MSE 为:

MSEper-tensor=(max⁡cMc)212(2b−1−1)2\text{MSE}{\text{per-tensor}} = \frac{(\max{c} M_c)^2}{12(2^{b-1} - 1)^2}MSEper-tensor=12(2b−1−1)2(maxcMc)2

由于 ∑cMc2/m≤(max⁡cMc)2\sum_c M_c^2 / m \leq (\max_c M_c)^2∑cMc2/m≤(maxcMc)2(当各通道范围不等时严格小于),逐通道量化的 MSE 严格更小。

4.2.3 逐组量化

逐组量化(Per-Group Quantization) 将每个通道分成大小为 ggg 的组,每组使用独立的量化参数。这是逐通道量化的泛化------当 g=1g = 1g=1 时退化为逐元素量化,当 g=ng = ng=n 时退化为逐通道量化。

sc,k=max⁡j∈groupk∣wcj∣2b−1−1s_{c,k} = \frac{\max_{j \in \text{group}k} |w{cj}|}{2^{b-1} - 1}sc,k=2b−1−1maxj∈groupk∣wcj∣

参数开销 :逐组量化需要额外存储每组的缩放因子。对于 m×nm \times nm×n 权重矩阵,组大小为 ggg:

额外存储=mng×(32 bits for scale)=4mng 字节\text{额外存储} = \frac{mn}{g} \times (32 \text{ bits for scale}) = \frac{4mn}{g} \text{ 字节}额外存储=gmn×(32 bits for scale)=g4mn 字节

当 g=128g = 128g=128(常用设置)时,额外开销约为 4/128=3.1%4/128 = 3.1\%4/128=3.1%。

4.3 对称 vs 非对称量化

4.3.1 对称量化的数学性质

对称量化(也称为零点量化,z=0z = 0z=0)假设量化范围关于零对称:

Qsym(x)=s⋅round(x/s),s=max⁡∣x∣2b−1−1Q_{\text{sym}}(x) = s \cdot \text{round}(x / s), \quad s = \frac{\max |x|}{2^{b-1} - 1}Qsym(x)=s⋅round(x/s),s=2b−1−1max∣x∣

优点

  • 实现简单,不需要存储零点
  • 对于近似对称分布(如权重),效率高
  • 硬件实现更高效(不需要零点偏移运算)

4.3.2 非对称量化的数学性质

非对称量化(也称为仿射量化)允许量化范围不对称:

Qasym(x)=s⋅(round(x/s)+z),s=xmax⁡−xmin⁡2b−1,z=round(−xmin⁡/s)Q_{\text{asym}}(x) = s \cdot (\text{round}(x / s) + z), \quad s = \frac{x_{\max} - x_{\min}}{2^b - 1}, \quad z = \text{round}(-x_{\min} / s)Qasym(x)=s⋅(round(x/s)+z),s=2b−1xmax−xmin,z=round(−xmin/s)

定理 4.4(非对称量化的最优性条件) :当待量化分布的均值 μ≠0\mu \neq 0μ=0 时,非对称量化严格优于对称量化。

证明:设分布支撑集为 a,ba, ba,b,a<0<ba < 0 < ba<0<b,μ≠0\mu \neq 0μ=0。设 Δ=max⁡(∣a∣,∣b∣)\Delta = \max(|a|, |b|)Δ=max(∣a∣,∣b∣)。

对称量化范围为 −Δ,Δ-\\Delta, \\Delta−Δ,Δ,步长 ssym=2Δ/(2b−1)s_{\text{sym}} = 2\Delta / (2^b - 1)ssym=2Δ/(2b−1)。

非对称量化范围为 a,ba, ba,b,步长 sasym=(b−a)/(2b−1)s_{\text{asym}} = (b - a) / (2^b - 1)sasym=(b−a)/(2b−1)。

由于 b−a≤2Δb - a \leq 2\Deltab−a≤2Δ(等号仅当 a=−ba = -ba=−b),sasym≤ssyms_{\text{asym}} \leq s_{\text{sym}}sasym≤ssym。

更小的步长意味着更小的颗粒误差 s2/12s^2/12s2/12。□\square□

python 复制代码
import numpy as np
from numpy.linalg import norm


def quantize_per_tensor(W: np.ndarray, num_bits: int, symmetric: bool = True) -> tuple:
    """逐张量量化。

    Args:
        W: 权重矩阵
        num_bits: 比特数
        symmetric: 是否对称

    Returns:
        W_q: 量化后的权重
        scale: 缩放因子
        zero_point: 零点
    """
    if symmetric:
        abs_max = np.max(np.abs(W))
        abs_max = max(abs_max, 1e-8)
        qmax = 2 ** (num_bits - 1) - 1
        scale = abs_max / qmax
        zero_point = 0
    else:
        w_min, w_max = W.min(), W.max()
        qmax = 2 ** num_bits - 1
        scale = (w_max - w_min) / qmax
        scale = max(scale, 1e-10)
        zero_point = np.round(-w_min / scale).astype(int)

    W_int = np.clip(np.round(W / scale) + zero_point, 0 if not symmetric else -(2**(num_bits-1)),
                    (2**num_bits - 1) if not symmetric else (2**(num_bits-1) - 1)).astype(int)
    W_q = (W_int - zero_point).astype(float) * scale

    return W_q, scale, zero_point


def quantize_per_channel(W: np.ndarray, num_bits: int, channel_dim: int = 0) -> tuple:
    """逐通道量化。

    Args:
        W: 权重矩阵
        num_bits: 比特数
        channel_dim: 通道维度 (0=按行, 1=按列)

    Returns:
        W_q: 量化后的权重
        scales: 每个通道的缩放因子
    """
    qmax = 2 ** (num_bits - 1) - 1

    # 计算每个通道的最大绝对值
    if channel_dim == 0:
        abs_max = np.max(np.abs(W), axis=1, keepdims=True)  # (m, 1)
    else:
        abs_max = np.max(np.abs(W), axis=0, keepdims=True)  # (1, n)

    abs_max = np.maximum(abs_max, 1e-8)
    scales = abs_max / qmax

    W_int = np.clip(np.round(W / scales), -qmax, qmax).astype(int)
    W_q = W_int.astype(float) * scales

    return W_q, scales


def quantize_per_group(W: np.ndarray, num_bits: int, group_size: int = 128) -> tuple:
    """逐组量化。

    Args:
        W: 权重矩阵 (m, n)
        num_bits: 比特数
        group_size: 组大小

    Returns:
        W_q: 量化后的权重
        scales: 每组的缩放因子
    """
    m, n = W.shape
    qmax = 2 ** (num_bits - 1) - 1

    # 将权重展平并分组
    W_flat = W.flatten()
    n_elements = len(W_flat)
    n_groups = (n_elements + group_size - 1) // group_size

    # 填充到 group_size 的整数倍
    padded_len = n_groups * group_size
    W_padded = np.pad(W_flat, (0, padded_len - n_elements))
    W_groups = W_padded.reshape(n_groups, group_size)

    # 每组的缩放因子
    abs_max = np.max(np.abs(W_groups), axis=1, keepdims=True)
    abs_max = np.maximum(abs_max, 1e-8)
    scales = abs_max / qmax

    # 量化
    W_int = np.clip(np.round(W_groups / scales), -qmax, qmax).astype(int)
    W_q_groups = W_int.astype(float) * scales

    # 恢复原始形状
    W_q = W_q_groups.flatten()[:n_elements].reshape(m, n)

    return W_q, scales.flatten()


def demonstrate_granularity_comparison():
    """演示不同量化粒度的对比。"""
    np.random.seed(42)

    # 构造一个不同通道范围差异很大的权重矩阵
    m, n = 128, 256
    W = np.random.randn(m, n)
    # 人为制造通道间范围差异
    for i in range(m):
        W[i] *= (0.01 + 10.0 * (i / m))  # 范围从 0.01 到 10

    print("=" * 70)
    print("量化粒度对比: 逐张量 vs 逐通道 vs 逐组")
    print("=" * 70)
    print(f"权重矩阵: {m} x {n}")
    print(f"通道范围: [{np.min(np.max(np.abs(W), axis=1)):.4f}, {np.max(np.max(np.abs(W), axis=1)):.4f}]")
    print()

    for bits in [8, 4, 3]:
        # 逐张量
        W_q_tensor, _, _ = quantize_per_tensor(W, bits)
        mse_tensor = norm(W - W_q_tensor, 'fro') ** 2 / (m * n)

        # 逐通道
        W_q_channel, _ = quantize_per_channel(W, bits)
        mse_channel = norm(W - W_q_channel, 'fro') ** 2 / (m * n)

        # 逐组
        for g in [128, 64]:
            W_q_group, _ = quantize_per_group(W, bits, group_size=g)
            mse_group = norm(W - W_q_group, 'fro') ** 2 / (m * n)

        print(f"  {bits}-bit:")
        print(f"    逐张量 MSE: {mse_tensor:.8f}")
        print(f"    逐通道 MSE: {mse_channel:.8f}")
        print(f"    逐组(g=128) MSE: {norm(W - quantize_per_group(W, bits, 128)[0], 'fro')**2/(m*n):.8f}")
        print(f"    逐组(g=64)  MSE: {norm(W - quantize_per_group(W, bits, 64)[0], 'fro')**2/(m*n):.8f}")
        print()


def demonstrate_clip_range_optimization():
    """演示最优裁剪范围的搜索。"""
    np.random.seed(42)

    # 正态分布权重
    W = np.random.randn(256, 256) * 0.5
    num_bits = 4
    qmax = 2 ** (num_bits - 1) - 1  # 7

    print("=" * 70)
    print("最优裁剪范围搜索")
    print("=" * 70)
    print(f"权重分布: N(0, 0.5), 形状 256x256, {num_bits}-bit 量化")
    print()

    # 搜索不同的裁剪比例
    # 裁剪比例 alpha: x_max = alpha * max(|W|)
    abs_max = np.max(np.abs(W))

    print(f"  {'裁剪比例 α':>12} {'x_max':>10} {'步长 s':>10} {'MSE':>15} {'过载比例':>10}")
    print(f"  {'-'*12} {'-'*10} {'-'*10} {'-'*15} {'-'*10}")

    best_alpha = 0
    best_mse = np.inf

    for alpha_pct in [100, 99, 98, 95, 90, 85, 80, 70, 60]:
        alpha = alpha_pct / 100.0
        x_max = abs_max * alpha
        s = x_max / qmax

        # 量化(带裁剪)
        W_clipped = np.clip(W, -x_max, x_max)
        W_q = s * np.round(W_clipped / s)
        mse = np.mean((W - W_q) ** 2)

        # 过载比例
        overload_ratio = np.mean(np.abs(W) > x_max)

        if mse < best_mse:
            best_mse = mse
            best_alpha = alpha

        print(f"  {alpha:>12.2f} {x_max:>10.4f} {s:>10.4f} {mse:>15.8f} {overload_ratio:>10.2%}")

    print(f"\n  最优裁剪比例: {best_alpha:.2f}")
    print(f"  最优 MSE: {best_mse:.8f}")


if __name__ == "__main__":
    demonstrate_granularity_comparison()
    demonstrate_clip_range_optimization()
相关推荐
wechat_Neal7 小时前
车载导航市场与技术对标分析报告
人工智能·华为·汽车
运维小欣7 小时前
2026年 企业智能可观测平台选型指南——“以智驭繁、稳筑根基”
人工智能
博图光电7 小时前
博图DVS相机,高速低延迟视觉感知首选
人工智能·数码相机
土拨鼠烧电路7 小时前
第5章:破壁者——MCP与巴别塔的倒塌
人工智能
吃好睡好便好7 小时前
矩阵的乘法运算
数据结构·人工智能·学习·线性代数·算法·matlab·矩阵
lqqjuly8 小时前
词嵌入与语言模型详解
人工智能·语言模型
摩尔线程8 小时前
喜报|摩尔线程MTT S5000(PH100芯片)通过国家《安全可靠测评》
人工智能·摩尔线程
Ricky05538 小时前
RF-DETR:实时检测变换器(transformers)的神经架构搜索(美国2025.12研究)
图像处理·人工智能·算法
HZZSDSCYZ8 小时前
2026年杭州电商新趋势:专业公司如何引领未来市场
大数据·人工智能·python