量化的基本概念:
量化的目标就是用 $\text{INT8}$ 这种高效格式取代 $\text{FP}$ 浮点格式进行计算。
在量化过程中,我们将浮点数转换为整数,以便模型能够在硬件上更高效地运行。这个过程通常是通过压缩数据的动态范围来实现的。
动态范围:数据的最大值和最小值之间的差。例如,如果一个数据集的值范围是 [0.0, 10.0],那么它的动态范围就是 10.0。
量化位宽:指的是你用多少位数来表示这个数据。例如,8位量化意味着用 8 位二进制数来表示每个数值,这样能表示的数值范围是 2^8=256 个不同的值,0~255.
对称量化和非对称量化
映射后的范围(整数范围)是否包含零点偏移,是量化方案的核心区别。涉及到两种主要的线性量化方案:对称量化和非对称量化。
A. 对称量化 (Symmetric Quantization)特点: 零点 $\mathbf{Z}$ 始终为 $0$。整数范围必须关于 $0$ 对称(或近似对称)。映射示例: 浮点范围 $[-10, 10]$ $\to$ 8-bit 整数范围 $[-127, 127]$。零点偏移: 没有。浮点 $0$ 必须精确映射到整数 $0$ ($\mathbf{Z}=0$)。考虑事项:优点: 公式更简单,无需计算和处理 $\mathbf{Z}_x, \mathbf{Z}_w$ 带来的零点校正偏差。缺点: 如果原始数据分布(例如激活值,它通常是非对称且只有正值)不对称,对称量化会浪费一半的量化范围(例如负数部分),导致精度损失更大。
B. 非对称量化 (Asymmetric Quantization)特点: 整数范围不一定关于 $0$ 对称,允许零点 $\mathbf{Z}$ 偏移($\mathbf{Z} \ne 0$)。映射示例:浮点范围 $[1, 9]$ $\to$ 8-bit 整数范围 $[0, 255]$。浮点 $0$ 映射到的整数值 $\mathbf{Z}$ 可以是 $0$ 到 $255$ 之间的任何值。在非对称量化中,我们使用 $\text{int8}$ 或 $\text{uint8}$ 数据类型作为底层容器,但并不要求将浮点范围 $[\text{min_r}, \text{max_r}]$ 映射到 $\text{int8}$ 的全范围 $[-128, 127]$,也不要求映射到 $\text{uint8}$ 的 $[0, 255]$。零点偏移: 有(即 $\mathbf{Z}$ 的值可能不为 $0$)。考虑事项:优点: 能更好地适应非对称分布(例如 $\text{ReLU}$ 激活的输出只有正值),可以最大化利用整数范围,提高精度。缺点: 计算更复杂,需要计算和校正零点偏差,如我们之前详细讨论的。
在 $\text{LLM}$ 量化中,非对称量化(允许 $\mathbf{Z}$ 偏移)由于其更高的精度,常用于激活值;而对称量化($\mathbf{Z}=0$)有时用于权重,以简化硬件计算。
线性变换
标准量化(仿射量化或线性量化)是一个简单的乘法、加法和舍入操作。原来的参数范围的中心是Z0,范围是S0,现在映射到Z为中心,[Z-S/2,Z+S/2]的范围内,
那么(x-Z0)/S0*S+Z就是变换的公式
量化矩阵乘法的偏移
$\mathbf{X} \cdot \mathbf{W}$ 乘法后的零点校正偏差 (Zero-Point Bias),可以被精确计算和消除,这是量化矩阵乘法 $\mathbf{Y} = \mathbf{X} \mathbf{W}$ 特有的。
在浮点世界中,$\mathbf{X} \mathbf{W}$ 是一个线性操作。但在整数世界中,由于 $\mathbf{X}$ 和 $\mathbf{W}$ 都被零点 $\mathbf{Z}_x, \mathbf{Z}_w$ 偏移了,$\mathbf{X}_q \mathbf{W}q$ 的整数累加结果不再能简单地通过一个 $\mathbf{S}{\text{out}}$ 映射回浮点 $\mathbf{Y}$。$$\mathbf{Y} \approx (\mathbf{X}_q - \mathbf{Z}_x) \cdot \mathbf{S}_x \cdot (\mathbf{W}_q - \mathbf{Z}_w) \cdot \mathbf{S}_w$$这展开后会引入与 $\mathbf{Z}_x, \mathbf{Z}_w$ 相关的复杂的偏移项,这些偏移项就是 $\text{Bias}$。
量化的其他误差
量化带来的舍入误差和非线性激活层的误差无法被消除,但可以通过QAT等尽量减少
| 元素 | 准确性 | 解释 |
|---|---|---|
| 舍入误差无法被消除 | 准确 | 舍入误差(Rounding Error)是将连续浮点值映射到离散整数格点时必然产生的,是量化的数学代价,理论上无法消除。 |
| 非线性激活层的误差无法被消除 | 准确 | $\text{ReLU}$ 或 $\text{Sigmoid/Softmax}$ 的量化(无论是 $\text{INT8}$ 截断还是 $\text{LUT}$ 近似)都会引入近似误差。特别对于 $\text{Softmax}$,动态范围压缩引起的指数项偏差无法完全消除。 |
| 但可以通过 QAT 等尽量减少 | 准确 | QAT 通过在训练中模拟这些误差,让模型学习权重调整来补偿/抵消这些误差的影响。PTQ 优化算法(如 $\text{GPTQ/AWQ}$)通过优化量化参数 ($\mathbf{S}, \mathbf{Z}$) 和权重,来最小化这些误差的幅度。 |
X W和偏置b的量化
$Y=\text{Activation}(\mathbf{XW} + \mathbf{b})$,量化作用的对象包括:输入激活 $\mathbf{X}$(通常是上一层的输出)。权重 $\mathbf{W}$。偏置 $\mathbf{b}$。
$\mathbf{W}$ 和 $\mathbf{X}$ 必须进行量化(线性仿射变换),将它们转换为低位宽整数 $\mathbf{W}_q$ 和 $\mathbf{X}_q$。这是为了利用 $\text{INT8} \times \text{INT8}$ 整数矩阵乘法的硬件加速。
XW的乘积,由于量化零点的存在,会有偏移,但可以被计算和消除:由于 $\mathbf{X}$ 和 $\mathbf{W}$ 都被零点 $\mathbf{Z}_x, \mathbf{Z}_w$ 偏移了,$\mathbf{X}_q \mathbf{W}q$ 的整数累加结果不再能简单地通过一个 $\mathbf{S}{\text{out}}$ 映射回浮点 $\mathbf{Y}$。$\mathbf{Y} \approx (\mathbf{X}_q - \mathbf{Z}_x) \cdot \mathbf{S}_x \cdot (\mathbf{W}_q - \mathbf{Z}_w) \cdot \mathbf{S}_w$,展开后会引入与 $\mathbf{Z}_x, \mathbf{Z}_w$ 相关的复杂的偏移项,这些偏移项就是 $\text{Bias}$。
$\mathbf{b}$ 通常也需要被量化,但它不是直接进行 $\text{INT8}$ 量化,而是根据 $\mathbf{XW}$ 乘积项的尺度进行高精度量化,通常量化到 $\text{INT32}$:$\text{INT32}$ (32-bit Integer) 是一种用 32 位存储的整数数据类型。它的范围大约是从 $-2.1 \times 10^9$ 到 $2.1 \times 10^9$。它比 $\text{INT8}$(8-bit 整数,范围 $[-128, 127]$ 或 $[0, 255]$)大得多,能够存储更精确、更大的数值。
为了保证尺度匹配和精度,$\mathbf{b}$ 必须根据 $\mathbf{X}$ 和 $\mathbf{W}$ 的 $\text{Scale}$ 进行缩放: 即使 $\mathbf{X}q$ 和 $\mathbf{W}q$ 都是 $\text{INT8}$(最大值 $127$),单次乘积 $\mathbf{X}{q,k} \mathbf{W}{q,k}$ 的最大值是 $127 \times 127 \approx 16,000$ ($\text{INT16}$ 即可存储)。但如果 $K=4096$,最大的累加结果可能是 $4096 \times 16,000 \approx 65,000,000$。这个数值远远超过 $\text{INT16}$ 的最大值 ($\approx 32,000$),但可以安全地存储在 $\text{INT32}$ 中。因此,$\text{INT32}$ 被用作累加器 (Accumulator) 来保存乘法和加法的中间结果,以确保计算过程中的精度和防止数值溢出。选择 $\text{INT32}$ 主要是基于硬件效率、安全性(防止溢出)和简化设计的原则,而不是追求最小的存储位宽。
由于 $\mathbf{b}_q$ 不涉及动态范围的改变(它的 $\mathbf{S}$ 和 $\mathbf{Z}$ 已经被 $\mathbf{X}$ 和 $\mathbf{W}$ 锁死),并且结果会立即被重新量化到 $\text{INT8}$,因此 $\mathbf{b}$ 自身范围过大对性能或精度的影响非常有限。
这样可以得到$\mathbf{Z}_{\text{acc}} = (\mathbf{X}_q \mathbf{W}_q) + \mathbf{b}_q + \text{Zero-Point Bias Corrections}$, 是 $\text{INT32}$ 格式,不能直接作为下一层的 $\text{INT8}$ 输入,也不能直接进行 $\text{ReLU}$ 或 $\text{Sigmoid}$ 运算。
反量化到int8作为下一层的输入
尺度调整(反量化到新的 $S_{\text{out}}$):为了将 $\mathbf{Z}{\text{acc}}$ 转换成下一层所需的 $\text{INT8}$ 格式 $\mathbf{Y}q$,需要进行一个包含尺度 $\mathbf{S}{\text{out}}$ 和零点 $\mathbf{Z}{\text{out}}$ 的操作。
尺度调整后,再作用激活函数。在 $\text{INT32}$ 域执行激活函数的计算没有硬件优势。并且,$\text{Sigmoid}$ 的量化是通过查表法 (LUT) 实现的。LUT 的索引必须是 $\text{INT8}$。
| 模型类型 | 精度 | 激活函数 | 输入类型 | 计算方式 | 执行单元 |
|---|---|---|---|---|---|
| 非量化模型 | FP32/BF16 | Sigmoid/ReLU | 浮点数 | 直接执行浮点数学函数 | CPU/GPU核心 |
| 量化模型 | INT8 | Sigmoid/ReLU | 整数 | 整数近似计算 | INT8硬件加速单元/LUT |
量化的目标就是用 $\text{INT8}$ 这种高效格式取代 $\text{FP}$ 浮点格式进行计算。
非线性函数与量化
考虑激活层的非线性函数。
指数函数(Softmax)对输入的动态范围非常敏感,量化后分布应该会变(大小排序关系不变),但性能却能保持。
在 $\text{Transformer}$ 的 $\text{Attention}$ 机制中,Softmax 的输入是 $\mathbf{Q} \mathbf{K}^T / \sqrt{d_k}$。在量化中,可以通过微调这个分母 $\sqrt{d_k}$(即温度参数),来有意识地压缩或放大 Softmax 的浮点输入范围,以使其更好地适应 $\text{INT8}$ 的 $256$ 个格点,从而减轻舍入误差的影响。
在量化感知训练 ($\text{QAT}$) 或先进的后训练量化 ($\text{PTQ}$) 方案中,模型不会直接修改 $\sqrt{d_k}$ 的数学定义,而是将其视为一个可以调整的温度参数 $T$。
$\text{Attention}(\mathbf{Q}, \mathbf{K}, \mathbf{V}) = \text{Softmax} \left( \frac{\mathbf{Q} \mathbf{K}^T}{T} \right) \mathbf{V}, \quad \text{其中 } T \text{ 初始为 } \sqrt{d_k}$
调整 $T$: 将温度参数 $T$(初始为 $\sqrt{d_k}$)乘以或除以一个因子 $\alpha$,使得 $\frac{\mathbf{Q} \mathbf{K}^T}{\alpha \cdot \sqrt{d_k}}$ 的浮点分布能更好地匹配 $\text{INT8}$ 的 $256$ 个格点$\mathbf{x}_{\text{final}} = \frac{\mathbf{Q} \mathbf{K}^T}{\alpha \cdot \sqrt{d_k}}$。$\sqrt{d_k}$ 本身不能消除量化带来的尺度差异,但因为它处于 Softmax 输入的分母位置,所以它可以作为一个可调节的温度参数,来对抗性地调整输入分布,抵消量化误差,从而使量化模型的 Softmax 输出分布更接近原始模型。
transformer量化哪些层
$\text{Transformer}$ 模型的量化通常是全量化与**混合精度(Hybrid Precision)**策略的结合。
主要被量化(转换为 INT8/INT4)的层
$\text{Transformer}$ 模型中绝大多数的计算和参数量都集中在线性层(矩阵乘法)中,因此这些层是量化的主要目标,以实现加速和压缩。
| 模块 | 符号表示 | 功能描述 |
|---|---|---|
| 注意力机制 (Attention) | 🔑 $\mathbf{Q}, \mathbf{K}, \mathbf{V}$ | 投影矩阵将输入 $\mathbf{X}$ 映射到 $\mathbf{Q}, \mathbf{K}, \mathbf{V}$ 的线性层。 |
| 📈 $\mathbf{O}$ | 投影矩阵将注意力头的结果重新映射回主维度的线性层。 | |
| 前馈网络 (FFN) | 🚀 $\mathbf{W}1$ / $\mathbf{W}{\text{up}}$ | $\text{FFN}$ 中的第一层,通常维度最大(上投射/扩展层)。 |
| ⬇️ $\mathbf{W}2$ / $\mathbf{W}{\text{down}}$ | $\text{FFN}$ 中的第二层(下投射/收缩层)。 |
原因: 这些线性层贡献了模型 $99%$ 以上的参数量和 $90%$ 以上的计算量。对它们进行量化带来的收益(速度提升和模型缩小)是最大的.
通常保持高精度(FP32/FP16)的层
这些层或操作通常被保留为高精度,因为它们对量化噪声极其敏感,或者它们的计算量占比很小,量化收益不高。
关键的非线性/归一化操作
| 模块 | 保持高精度的原因 |
|---|---|
| Softmax | 对输入的动态范围和相对值极度敏感(指数效应),需要 FP32/FP16 或高精度查表保证概率分布准确性 |
| Layer Normalization | 涉及均值和标准差的浮点运算,量化到 INT8 会导致数值不稳定,需在 FP16 或更高精度下执行除法和开方运算 |
| 残差连接的加法 | 元素级加法计算量极低,量化收益为零,保持 FP16 有助于维持梯度流精度 |
任务相关的特殊层(混合精度策略)
| 模块 | 输入 | 权重 | 原因 | 精度保持 |
|---|---|---|---|---|
| 第一层输入嵌入 | $\mathbf{X}_{\text{embed}}$ | $\mathbf{W}_{\text{embed}}$ | 保护初始信息完整性,防止量化噪声积累 | $\text{FP16}$ |
| 最后一层 Logits | $\mathbf{X}_{\text{final}}$ | $\mathbf{W}_{\text{unembed}}$ | Logits 输出对 $\text{Softmax}$ 的指数放大效应,确保最高预测准确性 | $\text{FP16}$ |
总结:混合精度策略现代 $\text{LLM}$ 量化(如 $\text{GPTQ/AWQ}$)采用的策略是异构量化,即:大规模量化: 对所有 $\mathbf{Q}, \mathbf{K}, \mathbf{V}, \mathbf{O}, \mathbf{W}_1, \mathbf{W}_2$ 矩阵的权重和激活执行 $\text{INT8}$ 或 $\text{INT4}$ 量化。关键层保护: 保留输入嵌入、最后一层线性层、$\text{Layer Norm}$ 和 $\text{Softmax}$ 的计算在高精度 ($\text{FP16}$ 或 $\text{INT32}$ 累加)。这种策略确保了最大的加速和压缩效益,同时最大限度地降低了对模型性能的影响。
总结
我感觉,量化利用的是,LLM里面有很多矩阵相乘,线性变换不改变其结构,只需要在非线性的激活层前面量化到适当范围,就可以保持最后输出结果的分布大概不偏移太多。但我还是觉得量化会给模型的效果带来很大程度的下降,例如sigmoid是对线性变化敏感的,softmax也是,这些都会改变数据的分布;但不会改变大小关系排序。
量化不仅在非线性层前发生,而且发生在每个张量上。 核心思想是确保非线性层的输入(如 $\text{ReLU}$ 或 $\text{Softmax}$)通过 $\mathbf{S}{\text{out}}$ 和 $\mathbf{Z}{\text{out}}$ 被准确对齐到新的 $\text{INT8}$ 范围,以保留非线性特性(如 $\text{ReLU}$ 的零点截断和 $\text{Softmax}$ 的相对排序)。
$\text{Sigmoid}$ 和 $\text{Softmax}$ 的敏感性会导致性能下降。现代量化技术旨在利用误差的非独立性来进行补偿。 量化感知训练就是调整原始浮点权重 $\mathbf{W}$,使得下一层激活函数之前的 $\text{Total Error}$ 得到最小化,特别是将误差推迟到相对不敏感的区域。后训练量化 等方法通过对 $\mathbf{W}$ 进行预缩放,将激活量化误差 $\mathbf{E}_x$ 转移到 $\mathbf{W}$ 上,人为地控制误差的来源,从而使 $\text{Softmax}$ 的输入更加平滑。
实际部署中,混合精度策略是性能维持的关键,而不仅仅是 $\text{INT8}$ 的对齐。高精度层作为锚点: 保留 $\text{Layer Norm}$ 和 $\text{Softmax}$ 前后 Logits 层为 $\text{FP16}$ 或 $\text{FP32}$,作用是为整个网络的量化提供高精度锚点。$\text{FP}$ 锚点将前一层累积的 $\text{INT8}$ 误差暂时“洗白”或“稳定”在高精度域,然后才进入下一轮的 $\text{INT8}$ 运算。
后训练量化 (PTQ) 和 量化感知训练 (QAT)
PTQ
PTQ 的核心: 不修改或不重新训练模型,仅使用一小部分未标记的校准数据来确定量化参数 $\mathbf{S}$ 和 $\mathbf{Z}$。
流程:加载一个完全训练好的 $\text{FP32}$ 模型。运行一小部分校准数据集(例如 100~1000 个样本)通过模型,收集每一层权重和激活的统计信息(如 $\min/\max$ 范围、分布直方图)。根据这些统计信息,使用 $\text{Min/Max}$、$\text{MSE}$ 或 $\text{KL}$ 散度等算法,为每一层计算最佳的量化尺度 $\mathbf{S}$ 和零点 $\mathbf{Z}$。使用计算出的 $\mathbf{S}$ 和 $\mathbf{Z}$ 将 $\text{FP32}$ 权重和激活的参数转换为 $\text{INT8}$ 或 $\text{INT4}$ 整数。
AWQ
$\text{AWQ}$ 是一种后训练量化 (PTQ) 方法。
核心洞察:激活值的不均衡性$\text{LLM}$ 的激活值分布通常非常不均衡,少数几个特征通道(即张量的某一维度)的激活值会非常大(称为 Outliers)。
问题: 当对权重进行量化时,这些巨大的激活值在计算 $\mathbf{XW}$ 时会被放大,导致整个计算结果对权重量化引入的微小误差变得极其敏感。
$\text{AWQ}$ 的核心在于识别输入 $\mathbf{X}$ 中哪些通道/特征的数值最大。 $\text{AWQ}$ 沿着 $D_{\text{in}}$ 维度(即输入通道)统计 $\mathbf{X}$ 中每个特征的最大值或方差。这样得到一个长度为 $D_{\text{in}}$ 的重要性向量 $\mathbf{v}$。根据这个重要性向量 $\mathbf{v}$,计算出一个逐行缩放因子 $s$.
对 $\mathbf{W}$ 的每一行应用不同的缩放因子 $s$.
为了让 $\mathbf{Y}{\text{raw}}$ 的结果恢复到原始 $\mathbf{XW}$ 的尺度,需要将 $\mathbf{Y}{\text{raw}}$ 除以 $\mathbf{s}$。$\text{AWQ}$ 将这个 $1/\mathbf{s}$ 的除法操作,合并到下一层 $\text{Layer Norm}$ (LayerNorm,对某个 token 的所有特征做一次标准化,使它们的均值变成 0、方差变成 1,然后再做一个可学习的线性变换。)
结果:误差转移和平滑激活转移误差源: 通过减小那些最容易被激活大值放大的权重,$\text{AWQ}$ 相当于将量化误差的敏感性从激活值转移到了权重。平滑 Softmax 输入: 这种处理使得 $\mathbf{X}$ 的分布不再那么“尖锐”和极端,从而使 $\mathbf{XW}$ 的结果更加平滑,显著降低了 $\text{Softmax}$ 等敏感非线性层对量化误差的敏感度。
| 特性 | 量化感知训练 (QAT) | 后训练量化 (PTQ) |
|---|---|---|
| 模型训练状态 | 需要微调或重新训练(即训练中模拟量化) | 训练完成之后(即训练后静态转换) |
| 对量化误差的适应性 | 高。模型权重会调整以主动抵消量化噪声 | 无。模型权重是固定的,被动接受量化误差 |
| 性能损失 | 极低/无损。往往能匹配 FP32 性能 | 较大。尤其是低位宽(INT4)或模型很深时 |
| 资源需求 | 高。需要完整的训练环境和时间 | 低。只需要 CPU 或少量计算资源 |
| 实现难度 | 高。需要复杂的 FakeQuant 插入和训练循环管理 | 低。简单的校准和转换脚本即可完成 |
QAT
QAT 是一种训练/微调技术,它在模型的前向传播过程中模拟低位宽量化操作,但在反向传播过程中仍然使用高精度(通常是 $\text{FP32}$ 或 $\text{FP16}$)来计算梯度。
QAT 的工作原理:伪量化节点 ($\text{FakeQuant}$)插入 $\text{FakeQuant}$: 在模型的权重、偏置和激活函数的关键位置,插入特殊的伪量化节点。
前向传播 (Forward Pass):当数据流经 $\text{FakeQuant}$ 节点时,它会被量化到 $\text{INT8}$(例如),然后立即反量化回 $\text{FP32}$。这样做的效果是:数据被添加了量化舍入误差(即“量化噪声”),但数据本身仍然是 $\text{FP32}$ 格式。
反向传播 (Backward Pass):梯度计算仍然使用 $\text{FP32}$ 格式,并且梯度会流过 $\text{FakeQuant}$ 节点,更新模型的原始 $\text{FP32}$ 权重。
QAT 的流程总结:
1 加载预训练模型($\text{FP32}$)。2 插入 $\text{FakeQuant}$ 节点到权重和激活的关键位置。3 微调/继续训练模型,同时计算并更新 $\mathbf{S}$ 和 $\mathbf{Z}$。4 导出模型时,将 $\text{FakeQuant}$ 节点去掉,并将最终学到的 $\mathbf{S}, \mathbf{Z}$ 烘焙(Bake)到 $\text{INT8}$ 权重中,用于最终的整数推理部署。
