三、模型量化
三、 模型量化¶
1. 什么是训练后量化(PTQ)?它与量化感知训练(QAT)的区别?¶
训练后量化(PTQ, Post-Training Quantization)¶
是在模型完成全精度训练之后,直接对权重(Weights)和/或激活(Activations)进行低精度转换——例如从 FP32/FP16 转到 INT8。其核心在于不需要任何重新训练或反向传播,仅需要少量校准数据(通常几百至几千个样本)来统计激活值的数值范围,从而确定每个张量的量化参数(尺度因子 s 和零点 z)。PTQ 的整个流程通常可以在几分钟到几小时内完成,尤其适合大语言模型这种全量训练成本极高的场景。像 GPTQ、AWQ、SmoothQuant 等都属于 PTQ 的范畴。
量化感知训练(QAT,Quantization-Aware Training)¶
则完全不同。它在训练阶段就模拟了量化误差:在前向传播时,对权重和激活插入“伪量化”节点
(Quantize + Dequantize),让模型在优化过程中学会适应低精度表示;反向传播时,由于量化函数不可导,通常使用直通估计器(Straight-Through Estimator, STE)来近似梯度,从而更新全精度权重。QAT需要完整的训练流水线、标注数据和大量的计算资源,通常耗时几小时到几天,但最终可以得到精度几乎无损的低精度模型,尤其适合INT4或更低位宽的极端压缩场景。
核心区别一览表:¶
| 维度 | PTQ | QAT |
| 时间成本 | 分钟 ~ 小时(校准) | 小时 ~ 天(需完整训练) |
| 数据需求 | 少量无标签校准样本 | 完整标注训练集 |
| 精度保持 | 大模型通常良好,小模型/低位宽可能下降 | 接近全精度,鲁棒性强 |
| 典型应用 | 大语言模型快速部署 | 移动端视觉模型、极端压缩 |
| 计算开销 | 极低 | 与重新训练相当 |
| 代表方法 | GPTQ, AWQ, SmoothQuant | LSQ, PACT, QAT-BERT |
大模型时代的选择哲学:由于 GPT-3、LLaMA 等大模型重训成本动辄百万美元,PTQ 成为工业部署事实上的标准。我通常给团队的建设是:先用 PTQ 快速出结果,如果精度损失在可接受范围内就直接上线;只有当业务对精度极度敏感、且 QAT 的资源投入能通过模型效果提升收回成本时,才考虑 QAT。实际中,90% 以上的场景 PTQ 都能满足需求。

2. 对称量化与非对称量化的公式和优缺点是什么?¶
量化的本质是将浮点值 $ r $ 映射为整数 $ q $,核心参数是尺度因子 $ s $ 和零点 $ z $。对于 $ b $ 位量化,整数范围通常为 $ [0, 2^{b} - 1] $(非对称)或 $ [-2^{b-1}, 2^{b-1} - 1] $(对称)。
对称量化(Symmetric Quantization)¶
假设浮点分布关于零点对称,因此零点固定为0。公式为:
$$ q=round\left(\frac{r}{s}\right) $$
尺度因子 $ s = \frac{\max(|r|)}{2^{b-1}-1} $。反量化时 $ r' = s \cdot q $。
优点:计算简单高效——矩阵乘法中的零点项相互抵消,硬件实现友好(如 NVIDIA TensorRT 默认偏好对称量化);对于本身就是零均值分布的数据(如模型权重,通常呈正态分布),信息损失很小。
- X 缺点:对于非对称分布(最典型的就是 ReLU 后的激活值,全为非负数),对称量化会浪费一半的量化范围;另外,对异常离群值(Outlier)极为敏感,一个极端值会撑大 $ \max(|r|) $,导致尺度因子变大,大量正常数据的量化分辨率变低,精度显著下降。
非对称量化(Asymmetric Quantization)
允许零点偏移,更灵活地贴合数据实际分布。公式为:
$$ q=round\left(\frac{r}{s}+z\right) $$
尺度 $ s = \frac{r_{\max} - r_{\min}}{2^{b} - 1} $,零点 $ z = \operatorname{round}\left(-\frac{r_{\min}}{c}\right) $。反量化时 $ r' = s(q - z) $。
优点:能精确覆盖偏斜分布(如激活值),量化区间利用率高,精度损失小。
- ✗ 缺点:计算开销增加——矩阵乘法中需要补偿零点项(即多一次额外的矩阵运算),推理速度略慢;存储时需同时保存尺度和零点,参数开销略增。
大模型实践指南:在实际工程中,为了追求极致速度和硬件亲和,权重通常使用对称量化(因为它天然分布对称),激活值则视情况而定:如果追求精度且能接受轻微延迟,用非对称量化;如果要求低延迟,则统一用对称量化并配合校准技术(如KL散度校准)来尽量减少精度损失。我遇到过一个例子:某对话模型激活值使用对称量化后,回复质量明显下降,改为非对称量化后问题消失,但推理延迟增加了约5%,最后我们决定接受这个代价,因为用户体验更重要。

3. 为什么大模型量化常用逐通道量化而不是逐张量化?¶
量化粒度决定了多少个参数共享同一个尺度因子。粒度从粗到细有三种:
· 逐张量(Per-Tensor):整个张量(例如一个权重矩阵的所有元素)使用一个尺度。
逐通道(Per-Channel):对权重矩阵的每个输出通道(即卷积核的每个filter或线性层的每行)分别计算一个尺度。
逐组(Per-Group):将通道分成若干组,每组使用一个尺度,是更细粒度的折中。
为什么大模型普遍采用逐通道量化?¶
主要原因是 Transformer 结构不同通道之间的权重分布差异巨大。例如,LLaMA-7B 的某个 FFN 层,其4096个输出通道的权值范围可能从 0.01 跨越到 0.5,相差数十倍。如果使用逐张量量化,一个统一的尺度会被幅度最大的通道所支配,导致小幅值通道的权值大部分被量化为 0 或者损失精细度;反过来,如果幅度最大的通道恰好是离群值,又会撑大尺度,造成信息丢失。而逐通道量化为每个通道独立设置尺度,就像为每个人量身定制衣服,能最大程度保留每个通道的独特信息。
为什么不是逐组量化?¶
逐组量化(比如 GPTQ 的 group size 128)精度更高,但需要存储更多的尺度因子(每 128 个权重一个尺度),会增加模型体积和推理时的小量计算。在权重上,逐通道以极低的额外存储(每个通道一个浮点数,对于 7B 模型只增加几 MB)换来了显著精度提升,是当前精度-效率的最佳平衡点。
实践经验:我曾在部署一个13B模型时尝试过逐张量量化,结果发现生成的文本包含大量无意义重复——这正是因为某些关键通道的权值被破坏。切换到逐通道量化后,生成质量恢复正常,显存占用几乎不变。所以现在我的默认配置就是权重逐通道量化。

4. LLM.int8() 为什么要把离群特征单独用 FP16 计算?什么是离群特征?¶
LLM.int8() 是 Dettmers 等人在 2022 年提出的混合精度量化方法,专门解决大语言模型中激活值离群特征导致的量化灾难。
离群特征(Outlier Features)¶
在大模型的 Transformer 层中,研究发现某些隐藏维度(约占全部维度的 0.1%)的激活值会系统性地比其他维度大 20 倍以上,甚至 100 倍。这些离群值并非随机出现,而是固定出现在某些特定的特征通道上,并且往往承载着重要的语义信息(例如分隔符、标点、否定词等)。例如,某个 token 的第 2048 号特征几乎总是特别大,而其他特征值相对平坦。
为什么离群特征对量化是灾难性的?¶
如果对整个激活张量使用统一的量化尺度,离群值会迫使尺度因子变得很大,导致绝大多数正常特征在量化后被压缩到极小的整数范围,甚至全部被映射为0,造成灾难性的信息丢失。你可以想象一个房间里有一个2米高的人和一群1米高的人,如果按最高的人来定天花板高度,那么矮个子的人的活动空间就会被严重浪费。而如果把离群值直接截断(clamp),又会丢失这些维度上的关键信息,影响模型性能。
LLM.int8() 的解决方案:¶
-
分离:对输入矩阵 X,识别出包含离群特征的那些行(即对应那几个特殊的特征维度)。
-
混合精度:对绝大多数正常特征 (>99.9%) 使用 INT8 矩阵乘法,享受量化的速度与显存优势。
-
极小部分离群特征:保留 FP16 精度进行计算。由于这部分维度极少(通常只有几十个),额外的 FP16 计算开销几乎可忽略不计。
-
最后将两部分结果相加。
这一设计精妙之处在于以极小的额外计算代价,彻底规避了离群值对量化精度的破坏。LLM.int8()的提出,首次让千亿参数大模型能在消费级显卡上以可接受的精度运行,是量化领域的一个里程碑。我在自己的实验中用该方法对OPT-13B量化,困惑度下降几乎不可察觉,但显存占用减少了近50%。
5. GPTQ 是怎么做量化的?它基于 OBQ 做了哪些改进?¶
GPTQ (Frantar et al., 2023) 是针对超大规模生成式预训练 Transformer 的一种高效权重量化方法,能在几小时内完成 175B 模型的 3-bit/4-bit 量化,精度损失很小。
基础算法:OBQ (Optimal Brain Quantizer)
OBQ 将权重量化问题看作逐权重的剪枝:每次量化一个权重,然后利用该层的 Hessian 矩阵(二阶导数信息)精确计算出如何调整同一行中剩余未量化的权重,以补偿刚量化造成的输出误差。它通过解一个小型线性系统,最小化输出特征的平方误差,属于贪心算法。OBQ 的精度很高,但计算量巨大——它需要逐元素处理,无法直接用于大模型。
GPTQ 的关键改进:¶
批量量化(Block-wise Quantization):不再逐元素处理,而是将权重矩阵按列分成若干块(例如每128列一块)。块内所有列对应的权重同时被量化,然后利用该块内累积的量化误差,对块外尚未量化的权重进行一次性补偿更新。这大幅减少了迭代次数。
延迟更新与 Cholesky 分解:GPTQ 利用 Hessian 矩阵的结构特性(对称正定),预先计算其逆矩阵或进行 Cholesky 分解,使得补偿更新的步骤可以高效地批量执行,避免了 OBQ 中反复求解线性系统的高昂开销。
列重排(Column Reordering):在量化前,根据 Hessian 信息(例如对角线元素的大小)对权重矩阵的列进行重新排序,将“难以量化”的列(对输出影响大的)放到前面优先处理,以进一步降低量化误差。
分组量化(Group-wise Quantization):支持将权重通道分成若干组,每组独立计算尺度因子,提供更细粒度的压缩,提升低位宽(如3-bit)下的精度。
实践中,GPTQ能在单张GPU上用几小时处理完LLaMA-70B的量化,生成质量比之前的逐通道四舍五入方法好非常多。我们团队在部署70B对话模型时,用GPTQ4-bit量化后,模型回复的连贯性和准确性几乎与FP16持平,而显存需求降低到原来的四分之一左右。
6. GPTQ 中的“二阶信息”指的是什么?为什么能提升量化精度?¶
二阶信息在这里特指 Hessian 矩阵,即目标函数(通常是该层权重的输出误差)关于权重的二阶偏导数。具体来说,GPTQ 定义的目标是最小化量化前后该层输出特征的平方误差:
$$ E=|W X-\widehat{W}X|_{F}^{2} $$
其中 W 是原始权重, $ \widetilde{W} $ 是量化后的权重,X 是该层的输入(校准数据)。对这个目标关于权重进行泰勒展开,一阶项在最优权重处为零,主导的误差项就是二阶项,其系数恰好是 Hessian 矩阵 $ H = 2X X^{T} $。
为什么二阶信息能提升精度?¶
简单地将每个权重四舍五入到最近的量化值,是一阶或零阶的贪心方法——它只考虑单个权重的舍入误差,完全忽略不同权重之间的相关性。而二阶信息(Hessian)则刻画了权重之间的相互影响:改变一个权重 $ w_{i} $会对哪些输出维度产生多大影响,以及这种影响如何与另一个权重 $ w_{j} $的改变相互叠加。
GPTQ 利用这个 Hessian 矩阵,在每次量化一个(或一组)权重后,能够精确计算出应该如何微调同行的其他未量化权重,来抵消刚刚引入的量化误差。这就像调整精密天平:你不仅要知道放上一个砝码带来的偏差,还要知道如何调节其他砝码来保持平衡。这种全局补偿策略是 GPTQ 能以极低位宽保持高精度的核心原因。
直观理解:如果只用量级大小来决定量化的取舍(一阶信息),你可能会忽略那些数值虽小、但对输出影响很大的“关键小权重”。而 Hessian 捕捉的正是“参数重要性”,它会告诉你哪些权重的微小变动会引起输出剧烈变化,从而在量化时给予这些权重更精细的处理。
7. AWQ 的核心思想是什么?它是如何保护重要权重通道的?¶
AWQ (Activation-aware Weight Quantization) 的核心洞察是:并非所有权重都对模型输出同等重要。只有大约 1% 的权重通道(对应输入特征中激活值幅值特别大的那些通道)承载了绝大部分关键信息,如果这些通道的权重量化不当,会直接导致模型性能显著下降。而保护这些“重要通道”的量化精度,就可以用极低的成本换来整体效果的巨大提升。
如何保护重要权重通道?¶
AWQ 发现,可以通过一个数学上等价的缩放变换来实现保护。具体来说,对于输入 X 和权重 W 的矩阵乘法 Y = XW,如果你将权重 W 的某一列 i(对应输入通道 i)乘以一个缩放因子 $ s_{i} $,同时将输入 X 的该通道除以同一个 $ s_{i} $,则输出 Y 完全不变。
基于此,AWQ 的做法是:
-
统计激活值分布:使用少量校准数据,观察输入 X 每个通道的平均激活幅度(例如计算每个通道的绝对值的均值或最大值)。
-
确定重要通道:激活幅度最大的那部分通道(如1%)即为“重要通道”。这些通道的权重量化误差会被输入的放大效应加倍放大。
-
计算缩放因子:对这些重要通道,通过一个简单的搜索或启发式算法(如根据激活幅值比例),找到一个大于1的缩放因子 $ s_i $,将权重 $ W_{:,i} $除以 $ s_i $(缩小权重),同时将输入 $ X_i $乘以 $ s_i $(放大激活)。
-
效果:经过缩放后,该重要通道的权重量级变小,量化时相对误差显著降低;而输入激活虽然变大了,但激活本身是浮点计算的,可以承受更大的数值范围。这就将量化的“难度”从权重转移到了激活,从而在无需重新训练的情况下,大幅保护了关键信息的精度。
最终,AWQ 将权重被缩放的部分(即除以 $ s_{i} $ 后的值)进行量化,推理时再在激活端乘以相应的 $ s_{i} $,完成等效还原。这种方法简单、高效、无需反向传播,却能将 4-bit 量化的精度提升到接近甚至超越 GPTQ 的水平。
8. AWQ 为什么只需要观察激活值分布,而不需要反向传播?¶
因为 AWQ 的核心优化完全基于数学等价变换,而不是梯度优化。它不足义一个需要最小化的损失函数,不需要计算梯度,更不需要通过反向传播更新参数。
具体来说,AWQ 的整个流程是:
第一步:用校准数据跑一次前向,统计每个输入通道的激活幅值分布(例如求 mean(|X|) 或 max(|X|) 等)。这一步纯粹是数据统计,没有梯度。
第二步:基于统计结果,通过一个封闭形式的搜索算法(例如为每个通道在有限候选集中尝试不同的缩放因子,选择使量化后输出误差最小的那个)来确定缩放因子 $ s_{i} $。这个搜索过程虽然涉及前向计算,但同样不需要反向传播。
- 第三步:将权重通过等效变换(乘/除 $ s_i $)后,应用标准的 PTQ 量化(如 min-max 量化)得到量化权重。推理时,只需在激活的对应通道上乘以 $ s_i $ 即可。
整个过程中,AWQ 的核心在于利用激活的幅值作为“重要性指标”,通过缩放将量化误差从敏感通道转移到不敏感通道。因为激活幅值是可以直接从校准数据获取的,不需要模型输出标签,也不需要计算损失,所以反向传播就成了多余。正是这种简洁性,使得 AWQ 的量化速度非常快(通常只需要几十分钟),同时对硬件和校准数据的要求极低,非常易于部署在自动化流水线中。
9. SmoothQuant 是如何通过数学等价变换来量化激活值的?写出核心公式。¶
SmoothQuant 的核心思想是将激活值的量化难度“平滑”到权重上。它观察到,在大模型中,激活值往往存在极端的通道级离群值,导致直接量化激活时误差极大;而权重分布相对平坦,更容易被量化。于是提出通过一个数学上等价的变换,重新分配激活和权重的数值范围。
核心公式推导:¶
对于一个线性层 $ Y = X \cdot W $,我们引入一个平滑向量 $ s \in \mathbb{R}^{C_{\text{in}}} $(每个输入通道一个平滑因子)。利用对角矩阵 $ \text{diag}(s) $ 进行等价变换:
$$ \boldsymbol{Y}=\boldsymbol{X}\cdot\boldsymbol{W}=(\boldsymbol{X}\cdot\operatorname{diag}(s)^{-1})\cdot(\operatorname{diag}(s)\cdot\boldsymbol{W}) $$
定义新的激活 $ \widetilde{X} = X \cdot \mathrm{diag}(s)^{-1} $,新的权重 $ \widetilde{W} = \mathrm{diag}(s) \cdot W $。
对于原来的 X,某些通道值极大(离群值),导致量化困难。
对于变换后的 $ \bar{X} $,由于除以了 $ s_{i} $(对应通道的平滑因子),离群值被压低了,整体分布变得更平滑,量化精度损失大大减小。
与此同时,新的权重 W 对应通道被乘以 $ s_{i} $,数值可能变大,但因为权重本身分布范围窄、更容易量化,这种“转移”对总体的量化损失影响很小。
这个变换是严格的数学等价,不改变任何层的输出。SmoothQuant 将量化激活的难点从“激活离群值”转移为“权重微调”,从而实现了对激活值的高效低位宽量化(如 INT8)。该公式简单优雅,已成为 LLM 推理加速的关键技术之一。我在实际应用中发现,对于某些激活值离群特别严重的模型(如 GLM-130B),SmoothQuant 几乎是唯一能让 INT8 推理保持可用性的方法。

10. SmoothQuant 的“平滑因子”如何确定?它转移了谁的量?¶
平滑因子 \(s\) 的确定是 SmoothQuant 效果的关键。其原则是:让变换后激活 \(X\) 和权重 \(W\) 的量化难度尽可能均衡。直观上,我们想找到一个 \(s\),使得在迁移后,激活的离群值被充分抑制,而权重的数值又不至于被过度放大。
实践中,平滑因子通常通过以下公式计算:
$$ \boldsymbol{s}{j}=\max(|\boldsymbol{X} $$ }|)^{\alpha}\cdot\max(|\boldsymbol{W}_{j,:}|)^{(1-\alpha)
其中 \(j\) 表示输入通道索引,\(\alpha \in [0,1]\) 是一个超参数,称为“迁移强度”。当 \(\alpha = 1\) 时,\(s_j = \max(|X_{:,j}|)\),相当于把激活的所有量化难度全部转移给权重;当 \(\alpha = 0\) 时,\(s_j = \max(|W_{j,:}|)\),则是把权重的所有量化难度转移给激活。通常 \(\alpha\) 取 0.5 左右,即两者均匀分担。
它转移了谁的量?¶
平滑因子 s 的作用是重新分配数值范围:
对激活 X,除以 $ s_{j} $ 相当于压低了它的幅度,尤其是对于那些原本值很大的通道(离群值),被大幅降低,使得激活整体变得“温顺”,易于量化。
对权重 W,乘以 $ s_{j} $ 相当于放大了对应通道的权值。这种放大会稍微增加权重的量化难度,但因为权重通常没有极端的通道间差异,其量化原本就比激活容易,所以这部分的代价很小。
因此,SmoothQuant 实际上是把激活值通道间的“量化难度差异”转移了一部分到权重上,实现两边的平衡,让整体的量化误差最小化。
调参经验:我一般会在校准数据集上尝试几个不同的 $ \alpha $(如 0.3, 0.5, 0.7),用困惑度或下游任务得分来评估量化损失,选择最优的 $ \alpha $。对于大多数 Transformer 模型,默认的 0.5 就能工作得不错;但对于某些激活分布特别陡峭的模型,可能需要增大 $ \alpha $(如 0.7)来更强势地压制激活离群值。
11. 为什么激活值比权重更难量化?离群值对量化有什么影响?¶
激活值(Activations)是神经网络每一层的输出,它们会随着输入数据的不同而动态变化。在量化时,激活值远比权重难以处理,根本原因在于其数值分布的高度不规则性和离群值(Outliers)的普遍存在。
激活值与权重的分布差异¶
权重(Weights):通常是静态的、可事先获得的参数。经过训练后,权重的分布通常比较平滑,近似于高斯分布或拉普拉斯分布,数值范围相对集中。例如,一个卷积核的权重可能集中在[-0.5, 0.5]之间,极少出现极端值。
- 激活值:是输入数据经过网络层层计算后的结果,其分布取决于输入数据和模型结构。激活值的分布可能是高度非对称的(例如 ReLU 之后所有值都 $ \geq 0 $)、长尾的,甚至在不同通道(Channels)之间差异巨大。更麻烦的是,激活值中经常出现比平均值大几十倍甚至上百倍的离群值。
$ ^{*} $ 离群值对量化的破坏性影响¶
离群值是激活值量化中最头疼的问题。想象一下,你有一个包含1000个数值的张量,其中999个值都在[0.0,1.0]范围内,但有一个值是100.0。如果你对这个张量做对称量化:
1. 尺度因子被离群值撑大¶
对称量化的尺度因子 $ s = \frac{\max |V|}{2^{b-1}-1} $。那个 100.0 的离群值会使得 s 变得很大,导致量化后的整数表示范围 [-127, 127] (INT8)被用来覆盖 [-100, 100]。
2. 绝大多数正常值被压缩到零点附近¶
对于 $ [0,0,1,0] $ 范围内的数值,除以巨大的尺度因子后,它们会被映射到极小的整数范围(例如 $ \theta $ 到 $ 1 $ 之间),甚至可能全部被舍入为 $ \theta $。这些值携带的细微信息就此彻底丢失。这就是量化噪声,它会严重破坏模型的精度,尤其对于那些依赖于精细激活值的 Transformer 层。
3. 非对称量化也无济于事¶
非对称量化虽然能更好地利用量化区间,但如果离群值与正常值之间的差距过大,它依然无法为正常值提供足够的分辨率。唯一的办法是采用逐通道量化(Per-Channel Quantization),为每个通道单独设置尺度,但即便这样,同一个通道内也可能存在离群token(例如某些特定token的特征值在所有通道上都异常大),这被称为逐token离群值。
离群值的成因与类型¶
通道级离群值(Channel-wise Outliers):在大语言模型的Transformer层中,某些特定的隐藏维度(例如第2048维)会系统性地出现比其他维度大几十倍的激活值。这些离群维度往往固定出现在少数几个特征通道上,并且承载着关键信息(如标点符号、否定词等)。
- Token 级离群值(Token-wise Outliers):某些特定的 token(比如句首的
或分隔符)会在几乎所有通道上产生异常大的激活值。这些“注意力汇聚点”在 StreamingLLM 等研究中已被证实对模型至关重要。
工程中的解决方案¶
· LLM.int8(): 将离群特征通道分离出来,单独用 FP16 计算,其余部分用 INT8 量化。这是一种混合精度的方法,牺牲一点点额外的计算来换取无损的精度。
SmoothQuant:通过数学等价变换,把激活值的量化难度“平滑”一部分到权重上。它对激活值除以一个平滑因子(缩小离群值),同时对权重乘以相同的因子(放大权重),使得两者都更容易量化。
· KV Cache 量化:对于推理中的 KV Cache,由于其分布同样存在离群值,常使用逐通道量化或专门的校准策略(如 INT8 量化加异常值截断)。
实践直觉:权重量化就像是给一本厚度均匀的书设计包装盒,你很容易找到一个合适的尺寸。激活值量化则像是给一堆形状怪异的石头找盒子,总有一两块特别大的石头把盒子撑得很大,导致其他小石子在盒子里咣当,信息丢失。解决思路要么是把大石头单独拿出来(混合精度),要么是把大石头切小(平滑迁移)。
12. 什么是 NF4?它在 QLoRA 中如何和双重量化配合?¶
NF4(4-bit NormalFloat)是一种专门为神经网络权重量化设计的信息理论上最优的数据格式。它由QLoRA的作者Dettmers等人提出,核心思想是:既然模型权重通常服从零中心的正态分布,那么量化时应该让量化区间(即量化台阶)在概率密度高的区域更密集,在概率密度低的尾部更稀疏。换句话说,NF4是一种非均匀量化,它根据正态分布的累积分布函数(CDF)来确定量化值的位置,从而在相同位宽下最大化保留信息。
NF4 的构造原理¶
-
假设权重服从标准正态分布 $ \mathcal{N}(0,1) $。
-
将该分布的概率质量等分为 $ 2^{b} = 16 $ 个区间(对于 4-bit)。
-
计算每个区间的 CDF 分位数,这些分位数就是 NF4 的量化值。由于尾部概率密度低,区间更宽;中心概率密度高,区间更窄。
-
实际权重值被映射到距离最近的 NF4 量化值上。
这就像给一本书做索引时,经常被查阅的章节(高概率区)索引更密集,不常被查阅的附录(低概率区)索引稀疏。这样可以用有限的位数表达更多的有效信息。
与 INT4 的对比¶
· INT4:均匀量化,量化台阶是等距的。对于正态分布,这种均匀分配会在中心区域分辨率不足(因为大部分权重集中在这里),而在尾部浪费分辨率。
NF4:非均匀量化,以信息理论最优的方式分布台阶。在同样的4-bit位宽下,NF4的量化误差显著小于INT4,尤其当数据严格服从正态分布时。
QLoRA 中的双重量化¶
QLoRA 是一种结合量化与参数高效微调(PEFT)的技术。它首先将预训练模型的权重用 NF4 量化到 4-bit,从而将显存占用降至原来的约 1/4。然后,在量化后的模型上附加 LoRA 适配器(低秩矩阵),训练时仅更新 LoRA 的参数,保持量化权重冻结。
然而,NF4 量化本身需要存储量化常数(每个量化块需要独立的尺度因子和零点),当采用极小的块大小时(例如 64 个参数一个块),这些常数的总存储量不可忽视(对于大模型可能达到数 GB)。双重量化(Double Quantization)正是为了解决这个问题:它对第一次量化的量化常数本身再进行一次量化(通常使用 FP8 或 INT8),从而将这些常数的存储开销压缩到几乎可以忽略的程度。

效果与价值¶
通过 NF4 + 双重量化 + LoRA,QLoRA 使得在单张 24GB 消费级显卡(如 RTX 3090)上微调 65B 参数模型成为可能。在我的一次实验中,用 QLoRA 微调 LLaMA-65B,显存峰值仅 21GB,而用 FP16 LoRA 会直接 OOM。虽然训练速度略有下降(由于量化/反量化的开销),但这是用有限资源撬动超大模型的唯一途径。
👎 直觉:NF4 就像是一个聪明的图书管理员,知道哪些书被借阅最多(高概率区),于是把那些书放在伸手可及、分类极细的书架上;而那些冷门书则堆在远处的仓库里,偶尔需要时再去取。双重量化则是连书架标签都做了缩写,进一步节省空间。
13. GGUF 格式中的 k-quant 是什么?它如何平衡精度和大小?¶
GGUF 是 llama.cpp 等 CPU/边缘推理框架使用的一种模型文件格式,专门为低资源、跨平台的推理设计。而 k-quant 是该格式中一种特定的混合精度量化策略,旨在在模型体积、推理速度和精度之间取得最佳平衡。
k-quant 的核心思想¶
k-quant 的全称是“基于块的量化”(block-wise quantization)。它将模型权重切分成固定大小的块(通常每 32 或 256 个参数为一个块),然后为每个块独立地计算量化尺度因子。这种逐块量化的粒度比逐通道更细,但又不像逐组量化那样产生过多的元数据开销。
关键点在于,k-quant 使用不同的位宽来量化不同类型的层和不同的参数组:
对于大多数权重:使用 4-bit 或 5-bit 量化,以最大化压缩率。
对于关键的少数权重(例如每个块的超级离群值)或特别敏感的层:使用6-bit甚至8-bit量化,以减少精度损失。
对于激活值:推理时通常保持 FP16 或 FP32,不量化。
这种“好钢用在刀刃上”的策略,使得 k-quant 在保持与全精度模型相近的困惑度的同时,将模型体积压缩到 FP16 的 1/4 到 1/5。
常见的 k-quant 变种¶
以 LLaMA 模型为例,常见的 k-quant 类型包括:
Q4_K_M:中等大小,平衡型。使用 4-bit 为主,关键层用 6-bit。这是最常用、推荐的选择。
Q4_K_S:小体积,牺牲少量精度换取更小模型。所有层强制 4-bit。
Q5_K_M:稍大,精度更高。使用 5-bit 为主。
Q6_K:更大,精度接近无损。
Q8_0:8-bit 量化,精度几乎无损,但体积减半。
每个变种背后,作者 TheBloke 等人通过大量的困惑度测试和人工评估,精细调整了哪些层用多少位、块大小如何设置、如何处理离群值等超参数。
平衡的艺术¶
k-quant 之所以能成功,是因为它认识到了模型内部参数的异质性:
-
注意力层 vs. 前馈层:注意力层的权重量化通常比前馈层对精度更敏感,因为注意力需要精确的 Q、K、V 投影。
-
嵌入层:通常保持较高精度(如 FP16),因为词嵌入对细微语义差异非常敏感。
-
输出层:同样需要较高精度,以免影响最终预测。
通过在模型的不同部分分配不同的“量化预算”,k-quant 在模型大小、推理速度和输出质量之间找到了一个sweet spot。对于普通用户来说,只需要选择合适的 k-quant 变体(如 Q4_K_M),无需手动调整任何参数,就可以获得一个“开箱即用”的高效模型。
实践建议:如果你不确定选哪个,就用 Q4_K_M。它几乎总是在所有维度上表现最好。只有当你的磁盘空间特别紧张时,才考虑 Q4_K_S;而如果你有足够的 RAM 且追求零精度损失,Q6_K 或 Q8_0 是更好的选择。
14. INT4 和 INT8 量化通常会带来多少模型体积和显存的缩减?¶
量化最直接的收益就是模型体积和推理时显存占用的下降。我们以 FP16(半精度浮点)为基准,来对比INT8和INT4量化的压缩效果。
模型体积缩减(磁盘存储)¶
FP16:每个参数占用2字节。
· INT8:每个参数占用1字节。体积缩减至原来的50%。
• INT4:理论上每个参数占用0.5字节,但实际中因为需要存储量化元数据(尺度因子、零点等),实际体积约为原来的25%-30%。例如,一个7B的FP16模型约14GB,INT8版约7GB,INT4版约3.5-4.5GB。
推理显存缩减¶
显存占用不仅要算权重,还要算 KV Cache、激活值等。但权重的压缩通常是最立竿见影的。
仅权重量化(W4A16 或 W8A16):权重被量化为 INT4/INT8,激活值保持 FP16。
INT8 权重:权重显存占用减半。总显存通常从权重 + KV Cache 变为(权重/2)+ KV Cache。如果 KV Cache 占比不大,总显存可降低约 40%-50%。
INT4 权重:权重显存占用降至 1/4。总显存从权重 + KV Cache 变为(权重/4)+ KV Cache。对于短文本,总显存可降低 50%-70%。
· 全量化(W8A8 或 W4A8):权重和激活值都量化。
W8A8(INT8 权重 + INT8 激活):理论上,不仅权重减半,激活值的显存和带宽需求也减半。在Decode 阶段,由于每次需要从显存读取整个 KV Cache 和激活值,A8 可以将该部分数据量减半,带宽压力下降,延迟降低。但对于自回归生成,激活值量化带来的额外精度损失可能更大。
W4A8:权重4-bit,激活8-bit。这是极致的压缩,但工程实现复杂,目前主要在部分边缘设备或专用ASIC上采用。
实际案例¶
以 LLaMA-7B、单张 A100 推理为例:
| 配置 | 权重显存 | 总显存 (短文本) | 总显存 (长文本) |
| FP16 | 14 GB | ~16 GB | ~30 GB |
| INT8 (W8A16) | 7 GB | ~9 GB | ~23 GB |
| INT4 (GPTQ) | ~3.5 GB | ~5.5 GB | ~19.5 GB |
可见,INT4 量化的权重显存降到了 FP16 的 1/4,但总显存降幅取决于 KV Cache 的大小。在长文本场景,KV Cache 才是大头,此时权重压缩的贡献相对变小,但仍至关重要——它为你腾出了更多空间来容纳更长的 KV Cache。
关键洞察:量化主要节省的是权重的存储空间和读取带宽,并不能直接减少激活值或KV Cache 的显存(除非你也量化它们)。但压缩后的权重占更少的显存,意味着你可以把宝贵的显存用在更大的 batch size 或更长的上下文上。
15. 量化后的模型推理速度一定会变快吗?什么情况下反而变慢?¶
直觉上,量化后模型变小了,推理应该更快。但现实远比这复杂:量化通常能提升吞吐、降低延迟,但并非在任何情况下都能加速,有时甚至会变慢。
为什么会变快(主要收益)¶
-
显存带宽压力降低:在Decode阶段(自回归生成),推理是显存带宽受限的。每次生成一个token,需要将整个模型权重从显存读入计算核心。以A100为例,显存带宽为2TB/s。一个FP16的7B模型(14GB)加载需要约7ms;而INT8版(7GB)只需要约3.5ms。这个时间直接构成了每token延迟的下限。因此,权重量化能直接降低Decode阶段的延迟。
-
更大的有效 batch size:压缩后的模型占用更少显存,可以在同一张 GPU 上同时服务更多的用户请求(更大的 batch)。由于 GPU 的并行计算能力强大,增加 batch size 可以显著提升整体吞吐(tokens/s)。
-
专用的整数计算单元:现代 GPU(如 NVIDIA 的 A100、H100)拥有专门用于 INT8 矩阵乘法的 Tensor Core,其吞吐量理论上是 FP16 的 2 倍以上。如果推理引擎(如 TensorRT)能够将量化的模型映射到这些硬件单元,计算速度本身也能大幅提升。
什么情况下反而变慢?¶
-
激活值未量化(W4A16)且 batch 很小:如果只量化了权重,激活值保持 FP16,那么在计算矩阵乘法时,需要将 INT4 的权重反量化回 FP16,然后与 FP16 的激活值相乘。这个反量化过程会引入额外开销。当 batch size 极小(如 batch=1)时,计算量很小,反量化开销占比变大,可能抵消甚至超过权重大小减少带来的带宽收益。这就是为什么有些用户发现 INT4 模型在单条查询时速度反而不如 INT8 模型。
-
硬件不支持低精度计算:老款 GPU(如 T4、V100)对 INT4 计算的硬件支持有限,无法充分发挥 INT4 的理论加速比。此时 INT4 推理完全依赖 FP16 反量化后的计算,速度提升有限,甚至可能变慢。
-
KV Cache 成为新瓶颈:如果你量化了一个7B模型,使其权重显存降到3.5 GB,但你设置了一个超长的上下文(如32k),那么KV Cache可能会膨胀到16 GB。此时,推理延迟完全由KV Cache的读取时间主导(显存带宽瓶颈),权重的压缩对整体延迟的贡献变得微乎其微。
-
低质量的量化实现:如果你使用的是一个未优化的量化推理框架(例如简单的 PyTorch 自定义 kernel,而不是 TensorRT 或 vLLM),反量化操作可能没有被融合到算子中,导致大量的额外 GPU kernel 启动和内存搬运,严重拖慢速度。
实践对比(以 LLaMA-7B 为例,batch=1,A100)¶
| 配置 | 每 token 延迟 | 吞吐 (tokens/s) | 备注 |
| FP16 (基准) | ~15 ms | ~65 | - |
| INT8 (W8A16, vLLM) | ~10 ms | ~100 | 稳定加速,显存减少 |
| INT4 (GPTQ, ExLlama) | ~8 ms | ~120 | 更快,但批处理增大效果更佳 |
| INT4 (原生 PyTorch) | ~20 ms | ~50 | 反量化开销过大,反而更慢 |
所以我的建议是:不要想当然认为“量化 = 加速”。在正式部署前,务必在你自己的硬件上、用你最常使用的 batch size 和上下文长度,实测不同量化策略的延迟和吞吐。工具上,如果追求极致性能,优先选用 TensorRT-LLM 或 vLLM;如果只是本地玩玩,ExLlamaV2 和 llama.cpp 是不错的选择。
16. 如何评估量化模型的精度损失?只看困惑度(PPL)够吗?¶
困惑度(Perplexity,PPL)是衡量语言模型预测下一个 token 的不确定度的指标,通常越低越好。量化后 PPL 的上升幅度,常被用来快速衡量量化精度损失。但只看 PPL 是远远不够的,甚至会误导你。
✓ PPL 能告诉你什么¶
PPL 对模型输出概率的整体分布变化很敏感。如果量化导致大量 token 的概率被扭曲,PPL 会明显上升。因此,PPL 是一个很好的初步筛查工具:如果你量化后 PPL 暴涨(例如从 8 升到 80),说明量化肯定出了问题,不用再继续评估了。
× PPL 不能告诉你什么¶
-
下游任务的实际表现:PPL 是一个无监督的、内在的指标。它不能直接反映模型在特定任务上的能力变化,如阅读理解、代码生成、多轮对话、安全性等。你可能会看到 PPL 几乎不变,但模型在数学推理或事实回忆上明显变差。
-
长尾知识保持度:量化可能会微妙地“抹掉”模型在预训练中学到的某些长尾知识(例如某个冷门历史事件的细节)。这种损失在 PPL 上几乎不会体现,因为长尾 token 对整体困惑度的贡献极小,但对你需要精确事实的场景却是致命的。
-
生成文本的多样性与连贯性:量化可能使模型的输出分布变得更“尖锐”(低熵),导致生成文本重复、模板化、失去创造力。PPL 无法捕捉这种风格和多样性的变化。
-
安全对齐的退化:权重的微小变化可能影响模型的安全对齐效果,使其更容易被越狱或产生有害内容。PPL 完全无法衡量这一点。
更全面的评估体系¶
除了 PPL,你至少应该补充以下评估:
• 标准化基准测试:在与你业务相关的公开基准上跑分。例如,MMLU(综合知识)、HellaSwag(常识推理)、GSM8K(数学)、HumanEval(代码)。对比量化前后的得分变化。
特定任务的自建测试集:如果你用模型来做客服、摘要或翻译,构建一个你自己的黄金测试集,用自动化指标(如ROUGE、BLEU)和人工评估来对比。
生成样本的人工评估:这是最可靠的方法。随机抽取100-200个实际prompt,让量化模型和原模型分别生成回答,然后进行盲评。从有用性、流畅性、事实正确性、无害性等维度打分。
长文本与多轮对话测试:如果你的场景涉及长上下文或多轮交互,必须在这些条件下测试,因为量化对长程记忆的影响可能在短文本中不显现。
安全与对齐测试:用红队提示集(如 HarmBench)检查量化是否降低了模型的安全拒绝能力。
我的评估流程通常是:先看 PPL,如果上升超过 5%,直接排查量化配置;如果 PPL 正常,跑 MMLU 和自建测试集;如果都 OK,最后做一轮人工评估。不要因为 PPL 没变就掉以轻心。
17. 🔥 什么是“权重量化”和“权重+激活量化”?后者为什么更难?¶
权重量化(Weight-only Quantization):只将模型的权重(参数)从高精度转换为低精度,而激活值(Activations)在推理时仍然保持高精度(如 FP16)。这是目前大模型量化中最主流的做法,因为实现简单、精度损失小、对延迟的改善主要体现在显存带宽上。
权重+激活量化(Weight and Activation Quantization):同时将权重和激活值都进行低精度转换,例如W8A8(INT8权重 + INT8激活)。这需要在计算矩阵乘法时,直接从低精度的权重和低精度的激活值进行整数运算,理论上能够充分利用硬件(如Tensor Core的INT8单元)实现计算加速,并将带宽需求降到最低。
为什么“权重+激活量化”难得多?¶
1. 激活值更难校准¶
权重是静态的,你可以在量化前彻底分析其分布,并离线确定最优的量化参数。激活值是动态的,依赖于输入数据。你需要在推理前用校准数据集来统计激活值的范围,但校准数据毕竟只是真实数据的一个子集,无法保证覆盖所有可能的输入分布。一旦线上出现校准集未见过的新分布,激活值的量化参数可能不再合适,导致精度严重下降。
2. 激活值的离群值更棘手¶
如前所述,激活值中经常存在极端的离群通道和离群 token。权重的离群值通常可以通过逐通道量化缓解,但激活值的离群值往往需要更复杂的处理(如 SmoothQuant 的数学变换,或混合精度将离群 token 剥离)。在推理时动态处理这些离群值的开销也更大。
3. 累积误差与层间漂移¶
每一层的激活值都是下一层的输入。当所有层的激活值都被量化时,量化误差会在层与层之间累积和放大。这可能导致深层网络的实际输入分布与校准时的统计完全偏离,产生所谓的“量化漂移”。要缓解这种漂移,通常需要在量化后进行微调(QAT)或使用更复杂的校准策略(如逐层误差补偿)。
4. 硬件与算子支持有限¶
虽然 A100/H100 等现代 GPU 支持 INT8 的矩阵乘法,但生态尚不如 FP16 成熟。许多高效的 Transformer 算子(如 FlashAttention、PagedAttention)目前对低精度激活值的支持还不完善或仍在开发中。要实现 W8A8 推理,往往需要对模型代码做较大的适配,工程成本较高。
所以现状是:对于99%的大模型部署场景,W4A16或W8A16(仅权重量化)是性价比最高的选择。只有在极致的边缘计算、专用推理芯片或对吞吐有极端要求的场景下,才会投入巨大的工程努力去实现权重+激活的全球化。
18. 为什么大模型的量化常常只量化权重,而保持激活为 FP16?¶
这不仅是一个技术问题,更是一个工程经济学问题。
1. 精度损失与收益的不对等¶
权重量化(尤其是逐通道的 INT4/INT8)通常只会带来微小的困惑度下降(<0.5),对大多数下游任务的影响几乎不可察觉。而激活值量化,即使是简单的 INT8,也可能导致 PPL 上升 1-3 个点,并且在长文本生成中容易出现不稳定的重复、遗忘等问题。要弥补激活值量化带来的损失,通常需要 QAT 或大量微调,这动摇了 PTQ“快速、低成本”的根本优势。
2. Decode 阶段的瓶颈是带宽,而非计算¶
在自回归生成中,每生成一个 token,主要时间花在从显存读取模型权重和读取整个 KV Cache 上。权重量化直接减少了从显存读取权重的数据量,从而缓解了这一带宽瓶颈,带来可观的延迟下降。而激活值量化虽然能进一步减少计算量和部分数据搬运,但在 Decode 阶段,激活值本身的数据量(每次只产生一个新 token 的激活值)相对于权重和 KV Cache 来说非常小,量化激活值带来的额外带宽节省十分有限,却要承担上述精度风险。
3. 工程复杂性与生态成熟度¶
权重量化可以离线一次性完成,生成一个量化后的模型文件,推理时直接加载。而激活值量化需要在校准数据上统计激活分布,推理引擎必须支持动态量化/反量化,适配不同算子的低精度版本。目前 vLLM、TensorRT-LLM 等主流框架对 W4A16 和 W8A16 的支持已经非常成熟,但对 W8A8 的支持仍在快速迭代中(尤其在长上下文和动态批处理下)。对于大多数团队来说,优先使用成熟稳定的权重量化方案是降低风险、快速上线的明智之举。
4. 例外情况¶
当模型部署在算力极强、带宽相对较弱的硬件上(例如某些移动端 NPU 或边缘设备),或者模型权重本身已经压缩到极致(如 2-bit),而计算成为新瓶颈时,激活值量化的优先级就会上升。另外,对于非自回归的模型(如编码器 BERT),由于一次性处理整个输入,计算量巨大,此时激活值量化的收益也更明显。
一句话总结:在目前的大模型推理中,权重量化是“雪中送炭”,解决了最痛的显存和带宽问题;激活值量化是“锦上添花”,在特定硬件和场景下有价值,但对大多数通用场景来说,风险和成本暂时高于收益。
19. 量化时是否需要校准数据集?需要多少数据?怎么选?¶
绝对需要。校准数据集是 PTQ 的“眼睛”,它让量化算法能够看到真实世界中激活值和权重的分布,从而计算出合适的量化参数。
1 /3 需要多少数据?¶
经验上,100到500个样本通常就足够了。更多的校准数据(如几千个)并不会显著提升量化精度,反而会增加校准时间。关键是样本的代表性和多样性,而非绝对数量。
如何选择校准数据?¶
-
与部署任务匹配:如果你部署的是一个客服对话模型,就用真实的客服对话数据作为校准集;如果是代码生成模型,就用多样化的代码片段。校准数据的分布应与线上实际输入尽可能接近。
-
覆盖多种长度和格式:对于大语言模型,确保校准集中包含短问题、长文档、多轮对话等不同长度的样本,以及可能的多语言、特殊符号、代码块等。
-
避免高度重复或偏斜:不要只用某个特定主题的数据(例如全是科技新闻),否则模型在该主题之外的表现可能会变差。
-
数据质量:使用干净、无乱码的文本。如果校准数据中包含大量噪声或格式错误,会导致量化参数统计不准确。
校准的具体操作¶
对于权重量化(如 GPTQ、AWQ),校准数据被用来:
• GPTQ:运行一批校准数据,计算每一层的 Hessian 矩阵(二阶信息),用于指导权重的补偿更新。校准样本通常以 128 条为一批,一次输入。
• AWQ:运行校准数据,统计每个输入通道的激活幅度(如 mean(|x|)),用于确定缩放因子。通常需要几百条数据。
对于激活值量化(如 SmoothQuant),校准数据被用来:
统计激活值的最大值、最小值,以确定量化尺度。
· 计算平滑因子(迁移强度 $ \alpha $),平衡激活和权重的量化难度。
常见误区¶
“用训练集的一部分做校准”:这通常是可以的,但要确保这部分数据没有被用来更新过模型(即不是QAT),否则就失去了PTQ的意义。
“只用几条数据”:极少量数据(例如10条)可能会导致某些通道的激活值未被充分激活,统计出的范围过小,导致推理时出现溢出,输出乱码。
“校准集与测试集高度重叠”:这会导致你对量化精度的评估过于乐观,无法反映线上真实效果。
我的做法:通常从线上日志中随机采样256条真实的用户prompt,确保涵盖最常见的意图和长度,然后固定这个校准集,用于该模型所有版本的量化。这样可以保证实验的可复现性。
20. 如果量化后模型精度下降明显,你应该排查哪些因素?¶
量化后精度严重下降,意味着你的量化设置或数据存在严重问题。以下是我总结的排查清单,按优先级排序:
1. 检查量化位宽和粒度¶
位宽过低:如果你尝试2-bit或3-bit,大多数模型在没有专门训练的情况下会严重退化。先回到4-bit或8-bit,确认是否是位宽的问题。
粒度不匹配:确保权重使用的是逐通道量化(per-channel),而不是逐张量(per-tensor)。逐张量量化大模型几乎必然失败。
2. 检查校准数据集¶
校准数据量不足:尝试将校准样本增加到256或512条,看看是否有改善。
校准数据分布偏差:校准集是否与你的测试/实际使用场景匹配?如果校准集全是英文,而测试集是中英混合,量化参数可能不适合。
校准数据中包含异常值:是否有乱码、过长的 token 序列、特殊字符等?这些会破坏激活值统计。
3. 检查量化算法配置¶
- GPTQ: 检查 group_size 是否设置得当(通常 128)。过大的 group_size 会降低精度。检查是否开启 desc_act(按 Hessian 排序),这对某些模型有帮助。
AWQ:确认缩放因子的搜索范围足够,且没有对重要通道的缩放造成负面效应。尝试微调 alpha 参数。
• SmoothQuant:确认 $ \alpha $(迁移强度)是否合适,如果激活值离群特别严重,需要增大 $ \alpha $(如 0.7)。
· LLM.int8(): 确认是否遗漏了对离群特征的处理。如果模型有大量离群值,混合精度策略是必须的。
4. 检查推理引擎与算子实现¶
- 推理引擎版本:不同的 vLLM、TensorRT-LLM、ExLlamaV2 版本可能对同一量化格式的实现有细微差异。尝试用官方提供的推理脚本测试。
反量化精度:某些引擎可能在反量化时使用较低精度(如 FP16 而非 FP32),累积误差可能更大。尝试切换精度。
- KV Cache 精度:如果你同时量化了 KV Cache(如 INT8),这可能是额外的误差来源。先保持 KV Cache 为 FP16,排除这个变量。
5. 人工抽查输出样本¶
看模型是否在生成重复的无意义 token?这通常意味着某些关键层的权重被过度压缩。
看模型是否在特定 token 上出现乱码?这可能是激活值离群值未被妥善处理。
模型是否丧失了多语言能力?可能校准数据语言单一。
6. ☒ 与原始模型对比,逐项排除¶
在同一个硬件、同一套推理代码上,跑原版 FP16 模型,确认不是推理环境本身的问题。
· 换一个已知表现良好的量化版本(如 TheBloke 发布的 Q4_K_M),如果他的版本没问题,说明问题在你自己的量化配置或流程上。
最后的大招¶
如果上述排查无果,可以尝试用更精细的方法——比如用 QLoRA 的思路,对量化后的模型进行极少量微调(几百步),让模型适应量化噪声。这通常能挽回大部分精度损失,但需要额外的算力。
记住:量化是一门工程手艺,不是魔法。耐心地调试每一个参数,用数据和实验说话,总能找到问题的根源。