AWQ 完全拆解:只保护 1% 的显著权重,4-bit 量化如何接近无损

8464 字
42 分钟
AWQ 完全拆解:只保护 1% 的显著权重,4-bit 量化如何接近无损

引言:模型装不下的问题#

把一个大语言模型部署到用户的设备上,第一道坎永远是内存。GPT-3 有 1750 亿参数,FP16 精度下每个参数占 2 字节,一共 350 GB;而 2023 年最强的 H100 也只有 96 GB 显存,更不用说手机、Jetson 这类边缘设备。端侧部署 LLM 的动机很实在:数据不出设备(隐私)、不依赖网络(离线可用)、没有按 token 计费的推理成本(省钱),但前提是模型必须塞进设备里。

压缩模型的主流手段是量化:把权重从 FP16(16 位)压到 INT4(4 位)甚至 INT3,显存直接除以 4。量化方法分两大类——量化感知训练(QAT)训练后量化(PTQ)。QAT 在训练时就模拟量化误差、用反向传播更新权重,效果好,但要在 175B 参数的模型上重新训练一遍,成本几乎不可接受;PTQ 则是训练完成后拿着权重直接压,不碰训练,是 LLM 场景唯一现实的选择。PTQ 里又有两条路线:W8A8(权重和激活都量化到 8 位,代表工作是 SmoothQuant)和低比特 weight-only 量化(只压权重,如 W4A16,代表工作有 GPTQ、LLM.int8() 等)。AWQ 属于后者。

2023 年 6 月,MIT Han Lab 联合上海交大、NVIDIA、清华等团队在 arXiv 上发表了 AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration(arXiv:2306.00978),并于 2024 年获得 MLSys 最佳论文奖。它解决的问题非常具体:当时最强的 weight-only 量化方法 GPTQ 需要用二阶信息对量化后的权重做逐列”重建”来补偿误差,效果好但容易过拟合校准集,而且实现复杂;而朴素的最邻近舍入(RTN)虽然简单,4-bit 以下精度掉得厉害。AWQ 的答案出人意料地简单——不重建、不训练、不求梯度,只做一件事:按通道缩放权重,就做到了与 GPTQ 相当甚至更好的精度,还顺带实现了一套端侧推理框架 TinyChat,把 70B 模型塞进了 Jetson Orin 显卡。

这篇文章会从”权重为什么不等价”讲起,推导 AWQ 的按通道缩放为什么能降低量化误差,再讲缩放系数怎么搜出来,最后拆解 TinyChat 如何把”省下来的显存”变成”实打实的加速”,并用论文实验数据逐一验证。

核心观察:LLM 的权重并不等价#

AWQ 的出发点是一个反直觉的实验结论:LLM 的权重中只有很小一部分(0.1%~1%)对模型性能起决定性作用,而且——这是最关键的——这部分”显著权重”不能通过看权重本身找出来,必须看激活(activation)分布

论文用 OPT 系列模型做了这样一组实验(论文 Table 1):对模型做 INT3 量化(组大小 128,后面解释组量化),然后把一部分通道的权重”免于量化”——保留 FP16,看困惑度(PPL,越低越好)怎么变。结果如下(WikiText-2 困惑度,OPT-6.7B,INT3-g128):

保留方式保留 0.1%保留 1%保留 3%
基于激活幅度选择(AWQ 的主张)11.5811.3911.36
基于权重范数选择22.3722.4523.41
随机选择24.2324.2223.54

对照 FP16 原模型 PPL 10.86、全部 RTN 量化 23.54:只把激活幅度最大的 1% 通道留在 FP16,PPL 就从 23.54 拉回 11.39,几乎无损;而按权重范数选、甚至随机选,保留 1% 的通道几乎毫无帮助(22.37 和 24.22 相比 23.54 没有实质改善)。

论文 Figure 2:基于激活分布找到 1% 的显著权重(中),保留为 FP16 能把 OPT-6.7B 在 INT3-g128 下的困惑度从 43.2(左,RTN)降到 13.0;AWQ(右)改用按通道缩放保护显著权重,避免混合精度的硬件不友好问题(来源:arXiv:2306.00978 图 2)
论文 Figure 2:基于激活分布找到 1% 的显著权重(中),保留为 FP16 能把 OPT-6.7B 在 INT3-g128 下的困惑度从 43.2(左,RTN)降到 13.0;AWQ(右)改用按通道缩放保护显著权重,避免混合精度的硬件不友好问题(来源:arXiv:2306.00978 图 2)

这个结果初看很违反直觉——我们习惯用”权重本身大不大”来判断重要性(这也是剪枝领域几十年来的通行做法,比如 Han et al. 2015 的经典剪枝工作),为什么在 LLM 里行不通了?论文给出的解释是:权重的重要性取决于它处理的输入特征。如果某个输入通道的激活幅度普遍很大,说明这个特征在模型里承载着重要信息,那么与它相乘的权重一旦量化出错,误差会被放大、传播得也更远。反之,一个权重本身数值很大、但它对应的特征几乎不被激活使用(激活幅度小),量化它造成的伤害就小。也就是说,显著性不在权重里,而在”权重 × 激活”这个组合里。

还有个更细的原因:深度神经网络(比如 CNN)的权重分布往往是长尾的——少数权重远大于平均值,按范数挑就能挑出”大头”;而 LLM 的权重经过 LayerNorm、残差连接和多层堆叠后,分布整体变得相当均匀,用权重范数区分不出显著通道。论文作者在 Table 1 里专门对比了这一点:基于权重的选择效果和随机选择差不多,恰恰说明 LLM 权重分布里没有”数值上的离群大权重”可挑。

不过,把 1% 的权重留在 FP16 会引入混合精度的问题:同一层里既有 FP16 又有 INT3 的权重,硬件做矩阵乘法时要么拆成两次计算、要么把 FP16 的那部分也降精度,无论哪种都牺牲效率。表 1 里 AWQ 拿到 11.39 的 PPL 用的是”保留 1% FP16”这个不现实的设置——AWQ 的真正贡献是找到了一种纯 INT3 存储、却能达到同等精度的替代方案:按通道缩放。

原理详解:按通道缩放为什么能降低量化误差#

先复习量化函数#

在做推导前,先把量化的记号定下来。对称均匀量化把一个浮点权重 ww 映射到整数:

Q(w)=ΔRound(wΔ),Δ=max(w)2N1Q(w) = \Delta \cdot \mathrm{Round}\left(\frac{w}{\Delta}\right), \quad \Delta = \frac{\max(|w|)}{2^{N-1}}

其中 NN 是量化位宽(如 4 位),Δ\Delta 是量化步长(scale),由这组权重(一个 group)里的绝对最大值决定。直觉上就是把 [maxw,+maxw][-\max|w|, +\max|w|] 这个区间切成 2N2^N 格,每格宽 Δ\Delta,权重落到最近的一格上。Round\mathrm{Round} 是四舍五入,量化误差 RoundErr(w/Δ)\mathrm{RoundErr}(w/\Delta) 的绝对值上界是 0.5——这就是”RTN(Round-to-Nearest,最邻近舍入)“基线。

这里出现了一个关键设计维度:Δ\Delta 按多大范围算?按整个矩阵算一个 Δ\Delta 叫 per-tensor 量化,实现最简单,但一个矩阵里所有权重共享一个步长——数值范围小的权重组被迫用粗格子,浪费精度;按每个输出通道算一个叫 per-channel 量化,精度好,但反量化时每个通道要乘不同的 Δ\Delta,对 kernel 访存模式不友好;折中方案是组量化(group quantization):把权重矩阵按连续 128 个元素(也可以 32、64)分一组,每组独立算一个 Δ\Delta。组越小,量化越精细、误差越小,但每组要多存一个 FP16 的 Δ\Delta 和零点——以 4-bit g128 为例,每 128 个权重(64 字节)额外多 2 字节,存储开销约 3%,可忽略。论文全文统一用 group size = 128(记为 g128)。这背后有个经验规律:LLM 权重的数值范围在不同组之间差异很大(比如 attention 输出投影和 FFN 中间层的范围可能差一个数量级),per-tensor 的单一 Δ\Delta 会浪费大量量化精度,而 g128 能在精度和存储开销之间取得好平衡。

量化误差分析:缩放如何救显著权重#

现在分析量化误差。考虑一组权重 w\mathbf{w} 和一个输入 xx(为了清晰先看单个元素),线性层输出 y=wxy = wx,量化后的输出是 Q(w)xQ(w)x。单个权重的量化误差可以写成:

Err(Q(w)x)=ΔRoundErr(wΔ)x\mathrm{Err}(Q(w)x) = \Delta \cdot \mathrm{RoundErr}\left(\frac{w}{\Delta}\right) \cdot x

这个式子的意思是:四舍五入最多偏半格,即 RoundErr\mathrm{RoundErr} 的绝对值不超过 0.5,所以单个权重的绝对误差上界是 Δ/2\Delta/2,再乘以输入 xx 放大。直观理解:量化误差和步长 Δ\Delta 成正比——量化格越粗(Δ\Delta 越大),误差越大;输入越大,误差被放大得越厉害。而 Δ\Delta 由这组权重里绝对值最大的那个决定。这立刻暴露了问题:如果一组里有一个”大个”权重,Δ\Delta 就被顶得很大,组里其他权重全部跟着承受大误差——RTN 在 4-bit 以下精度崩掉,很大程度就是这个原因。

AWQ 的招数是给显著通道乘一个缩放因子 s>1s > 1,同时给激活除以 ss。因为:

wx=(ws)(xs)wx = (w \cdot s)\left(\frac{x}{s}\right)

数学上完全等价,什么也没变——但如果我们先缩放再量化,情况就不同了。设缩放后量化的步长为 Δ\Delta',则缩放后权重的量化误差为:

Err(Q(ws)(xs))=ΔRoundErr(wsΔ)x1s\mathrm{Err}\left(Q(w \cdot s)\left(\frac{x}{s}\right)\right) = \Delta' \cdot \mathrm{RoundErr}\left(\frac{w s}{\Delta'}\right) \cdot x \cdot \frac{1}{s}

对比两式,误差比值为:

ΔΔ1s\frac{\Delta'}{\Delta} \cdot \frac{1}{s}

直觉拆解:把权重乘 ss 后,wsws 在整数网格上的位置更”靠中间”了吗?不一定,但关键在 Δ\Delta'——组里那个决定 Δ\Delta 的”大个”权重如果也被放大了,Δ\Delta' 会跟着变大,这反而有害。论文 Table 2 用 OPT-6.7B 的实测数据展示了这个权衡(对激活幅度最大的 1% 通道乘 ss,INT3-g128):

ssΔΔ\Delta' \neq \Delta 的通道比例平均 Δ/Δ\Delta'/\Delta平均 (Δ/Δ)(1/s)(\Delta'/\Delta) \cdot (1/s)WikiText-2 PPL
1(RTN)0%1.0001.00023.54
1.252.8%1.0050.80412.87
1.54.4%1.0130.67612.48
28.2%1.0380.51911.92
421.2%1.2130.30312.36

读这张表要抓住两件事。第一,s=2s = 2 时显著通道的相对误差降到了原来的 0.519 倍,PPL 从 23.54 直接干到 11.92——只乘一个缩放系数,几乎追平了”1% 通道留 FP16”的效果(11.39)。第二,s=4s = 4 时事情开始变坏:21.2% 的组因为被放大的权重改写了组的 Δ\DeltaΔ/Δ=1.213\Delta'/\Delta = 1.213,平均步长被顶高了 21%),非显著通道的误差被整体放大,PPL 回升到 12.36。也就是说,缩放保护显著通道的同时,会牺牲非显著通道——过大的 ss 得不偿失。所以缩放系数不能拍脑袋定,得搜。

数据驱动的最优缩放搜索#

把上面的单元素分析推广到整层:权重矩阵 W\mathbf{W}Cout×CinC_{out} \times C_{in}),输入 X\mathbf{X},per-input-channel 缩放向量 s\mathbf{s}。AWQ 的目标是让”先缩放再量化”的层输出尽可能接近原始输出:

s=argmins  L(s),L(s)=Q(Wdiag(s))(diag(s)1X)WX\mathbf{s}^{*} = \arg\min_{\mathbf{s}}\; \mathcal{L}(\mathbf{s}), \quad \mathcal{L}(\mathbf{s}) = \left\| Q\left(\mathbf{W} \cdot \mathrm{diag}(\mathbf{s})\right)\left(\mathrm{diag}(\mathbf{s})^{-1} \cdot \mathbf{X}\right) - \mathbf{W}\mathbf{X} \right\|

其中 QQ 是量化函数(INT3/INT4,g128),X\mathbf{X} 是从校准集缓存下来的输入激活。注意缩放是作用在输入通道维上的:每个输入通道一个 ssdiag(s)1X\mathrm{diag}(\mathbf{s})^{-1} \cdot \mathbf{X} 相当于把激活的每个通道除以对应的 ss。这一步在推理时可以融合进前一个算子(LayerNorm 或者前一个线性层)的权重/参数里,于是推理时零额外开销——这是”free lunch”能成立的关键。具体怎么融合:如果前一个算子是 LayerNorm,输出 y=γxμσ+βy = \gamma \odot \frac{x - \mu}{\sigma} + \beta 是逐元素仿射变换,整体除以 ss 等价于把 γ\gammaβ\beta 除以 ss;如果前一个算子是线性层(如注意力里的 WQW_Q 之前没有 LN 时),就把 1/s1/s 乘进它的权重矩阵。无论哪种,激活流在推理时保持标准 FP16,缩放对计算路径完全透明。

这个优化问题有个麻烦:量化函数 QQ 不可微(Round 的导数几乎处处为 0),没法直接反向传播。论文提到尝试过用直通估计器(STE)这类近似梯度的方法,但收敛不稳定,于是改用一种更稳的做法——手工定义一个小的搜索空间:既然显著通道由激活幅度决定,缩放系数就设为激活幅度的幂:

s=sXα,α=argminα  L(sXα)\mathbf{s} = \mathbf{s}_{\mathbf{X}}^{\alpha}, \quad \alpha^{*} = \arg\min_{\alpha}\; \mathcal{L}\left(\mathbf{s}_{\mathbf{X}}^{\alpha}\right)

其中 sX\mathbf{s}_{\mathbf{X}} 是校准集上每个输入通道的平均激活幅度1njXij\frac{1}{n}\sum_j |X_{ij}|),α\alpha 是一个全局超参数,在 [0,1][0, 1] 区间做网格搜索:α=0\alpha = 0 表示不缩放,α=1\alpha = 1 是搜索空间里最激进的缩放。为什么一个标量 α\alpha 就够?因为所有通道共享同一个”缩放强度”,只是不同通道的基准幅度不同——这个设计既把搜索维度压到一维,又保持了 per-channel 的精细度。校准集也很省:论文 5.3 节报告,只用 16 条序列就能达到 GPTQ 用 192 条序列的效果(10 倍数据效率),因为 AWQ 只需要从校准集上估计每通道的平均幅度,不需要拟合任何复杂目标。

除此之外,AWQ 还叠加了权重裁剪(weight clipping):把每组的权重裁剪到 [Δ2N1,+Δ2N1][-\Delta \cdot 2^{N-1}, +\Delta \cdot 2^{N-1}] 范围内,即丢弃组内最极端的离群值,让 Δ\Delta 变小、多数权重的量化格更细。论文在实验里统一使用了裁剪(表格里标 AWQ 的结果均含裁剪)。

现在可以把整条流程串起来(对应论文 Figure 2 的右侧分支):

  1. 从校准集(预训练数据里随机抽十几条序列)前向跑一遍模型,缓存每一层的输入激活 X\mathbf{X}
  2. 对每个线性层,算出每通道平均激活幅度 sX\mathbf{s}_{\mathbf{X}}
  3. α[0,1]\alpha \in [0, 1] 做网格搜索(步长如 0.05),选出使 L(sXα)\mathcal{L}(\mathbf{s}_{\mathbf{X}}^{\alpha}) 最小的 α\alpha,得到 s\mathbf{s}
  4. s\mathbf{s} 缩放权重(Wdiag(s)\mathbf{W} \cdot \mathrm{diag}(\mathbf{s}))后做 g128 量化;
  5. 1/s1/\mathbf{s} 融合进前一个算子(LayerNorm 或前一层的偏置/权重),推理时对激活零开销。

整个过程没有反向传播、没有误差重建——这正是 AWQ 与 GPTQ 最本质的分野,也是它泛化能力好的根源,下一节细说。llm-awq 官方仓库的这张总览图把”量化(左侧:激活感知缩放 → 4-bit 量化)→ 部署(右侧:TinyChat 推理)“的完整链路画在了一张图里:

AWQ 官方 GitHub 仓库的总体流程示意图:从激活感知的按通道缩放量化,到 TinyChat 端侧推理部署(来源:mit-han-lab/llm-awq 仓库 README)
AWQ 官方 GitHub 仓库的总体流程示意图:从激活感知的按通道缩放量化,到 TinyChat 端侧推理部署(来源:mit-han-lab/llm-awq 仓库 README)

与 GPTQ 的分野:为什么”不重建”反而更好#

AWQ 的基线对手是 GPTQ(Frantar et al., ICLR 2023),当时 LLM weight-only 量化的 SOTA。先花点篇幅把 GPTQ 的机制讲清楚,后面才好对比。GPTQ 建立在经典的 OBS(Optimal Brain Surgeon,最优脑外科手术)框架之上:量化一个权重 wqw_q 造成的输出误差,可以用权重的 Hessian 矩阵(校准集上损失对权重的二阶导数)定量刻画,并且误差可以分摊——量化 wqw_q 后,把 δ=wq[H1]qq(H1):,q\delta = -\frac{w_q}{[H^{-1}]_{qq}} (H^{-1})_{:,q} 加到其余尚未量化的权重上,就能在二阶近似下完全抵消 wqw_q 的量化误差。GPTQ 把它改造成逐列、逐层的流式算法:从校准集(128 条序列)缓存激活、计算该层权重 Hessian 的二阶矩近似,然后对权重矩阵按列做”量化一列 → 更新剩余列”的迭代,直到整层量化完。这个重建过程很强大,代价有两个。

第一是过拟合校准集。GPTQ 的补偿过程是在校准数据上做最小化,本质是一种重建(reconstruction),它会扭曲模型在校准集分布之外的特征表达。LLM 是通用模型,部署后遇到的输入分布五花八门(代码、数学、医学、多模态……),过拟合校准集就意味着在其他分布上掉精度。论文 Figure 8 的右侧子图给出了直接证据:用 Pile 数据集的 PubMed 子集做校准、在 Enron 邮件子集上评估(反之亦然),AWQ 的 PPL 只涨 0.5~0.6,GPTQ 涨 2.3~4.9——分布漂移对 GPTQ 的伤害是 AWQ 的 5~8 倍。原因很直白:AWQ 从校准集上只学”每通道平均幅度”这一个统计量,它几乎不含具体任务的信息,自然也不会有任务相关的过拟合。

论文 Figure 8:左——AWQ 只需 GPTQ 十分之一的校准数据就能达到更好效果(16 条 vs 192 条序列);右——校准集与评估集分布不同(PubMed↔Enron)时,AWQ 的 PPL 只增加 0.5-0.6,而 GPTQ 恶化 2.3-4.9(来源:arXiv:2306.00978 图 8)
论文 Figure 8:左——AWQ 只需 GPTQ 十分之一的校准数据就能达到更好效果(16 条 vs 192 条序列);右——校准集与评估集分布不同(PubMed↔Enron)时,AWQ 的 PPL 只增加 0.5-0.6,而 GPTQ 恶化 2.3-4.9(来源:arXiv:2306.00978 图 8)

第二是实现脆弱。GPTQ 的 Hessian 反演在部分模型上会数值退化:个别列的对角元异常小,导致 H1H^{-1} 爆炸、误差分配失真,LLaMA-7B、OPT-66B 必须配合特殊的”列重排”(reorder)技巧才能正常工作,即论文里的 GPTQ-R 基线。而 AWQ 完全回避了这个问题——没有重建、没有重排、没有二阶信息,任何 Transformer 模型拿来就能量化。

当然,天平的另一端是:GPTQ 的重建能力在下限场景更硬。在 INT2 这种极端低位下,AWQ 纯靠缩放救不回来的误差,GPTQ 的重建还能再掰回来一点。论文 Table 9 专门做了正交性实验:AWQ 和 GPTQ 组合(先用 AWQ 缩放再套 GPTQ 重建)在 INT2-g64 下进一步缩小了与 FP16 的差距——两者的能力是互补的,不是替代关系。

与 SmoothQuant 的对照:同一个恒等式,两个相反的目标#

AWQ 的缩放(Wdiag(s)\mathbf{W} \cdot \mathrm{diag}(\mathbf{s})diag(s)1X\mathrm{diag}(\mathbf{s})^{-1} \cdot \mathbf{X})很容易让人联想到另一篇著名工作 SmoothQuant(Xiao et al., 2022)——两者用的是同一个矩阵乘恒等式YX=(Ydiag(s))(diag(s)1X)YX = (Y \cdot \mathrm{diag}(s))(\mathrm{diag}(s)^{-1}X)。但目标恰恰相反:

  • SmoothQuant 面向 W8A8:它发现激活分布里有少数离群通道,导致激活量化(W8A8 需要把激活也压成 INT8)误差巨大。于是把激活的量化难度”迁移”给权重——激活除以 ss 变小好量化,权重乘 ss 变大。ss 的选取目标是均衡激活与权重的量化难度
  • AWQ 面向 W4A16:激活保持 FP16 不用管,问题在权重——显著通道的误差主导量化损失。于是把权重乘 ss 放大、让显著通道的相对误差变小,激活除以 ss 只是为了保持数学等价。ss 的选取目标是最小化权重量化误差

两者还有一个共同点:ss 都能免费融合进前一层(SmoothQuant 原文也把它融进 LayerNorm 的 γ\gammaβ\beta),所以”缩放”在推理侧都是零成本的。理解这个对照有助于把握量化方法的整体地图:W8A8 路线处理的是”激活离群值”(SmoothQuant、LLM.int8()),W4A16 路线处理的是”权重非均匀重要性”(AWQ),两条路线后来在 W4A8 等混合精度设置里合流。

为什么 weight-only 量化能加速端侧推理#

量化省显存好理解,但”省显存”为什么自动变成”省时间”?论文 4.1 节用 RTX 4090 上的剖析回答了这个问题,结论对任何 GPU 都适用。下面这张图是论文 Figure 3,拆成三块看:

论文 Figure 3:Llama-2-7B 在 RTX 4090 上的瓶颈分析。左——生成阶段(20 tokens 需 310ms)比上下文阶段(200 tokens 只需 10ms)慢一个数量级;中——生成阶段算术强度只有约 1,远低于 4090 的内存受限阈值 165,W4A16 量化能把算术强度提升 4 倍;右——内存访问中权重访问量比激活访问量大几个数量级(来源:arXiv:2306.00978 图 3)
论文 Figure 3:Llama-2-7B 在 RTX 4090 上的瓶颈分析。左——生成阶段(20 tokens 需 310ms)比上下文阶段(200 tokens 只需 10ms)慢一个数量级;中——生成阶段算术强度只有约 1,远低于 4090 的内存受限阈值 165,W4A16 量化能把算术强度提升 4 倍;右——内存访问中权重访问量比激活访问量大几个数量级(来源:arXiv:2306.00978 图 3)

  • 左图:瓶颈在生成阶段。 批大小 1(端侧场景)下,用 FasterTransformer 以 FP16 跑 Llama-2-7B:总结 200 个 token 的提示(上下文/prefill 阶段,可并行计算)只要 10ms,而生成 20 个 token(自回归解码,逐 token 串行)要 310ms——差 31 倍。端侧交互应用里用户感知的延迟主要来自生成阶段,优化重心应该放在这。
  • 中图:生成阶段是内存受限的。 4090 的峰值算力 165 TFLOPS、显存带宽 1 TB/s,按 Roofline 模型,算术强度(每字节内存访问对应的浮点运算次数)低于 165 的负载就是内存受限。解码时的算术强度约等于 1——每个权重只被用一次(batch=1 时没有复用),算一次乘加就读一次内存。这个”算术强度 ≈ 1”可以算出来:解码一个 token 要把全部权重从显存读一遍(访存 Nparams×bit/8N_{params} \times \text{bit}/8 字节),对每个权重做一次乘加(2Nparams2 N_{params} FLOPs),两者一比:
AI=2NparamsNparamsbits/8=16bits\mathrm{AI} = \frac{2 N_{params}}{N_{params} \cdot \text{bits}/8} = \frac{16}{\text{bits}}

FP16(bits=16)时 AI = 1,INT4(bits=4)时 AI = 4——量化位宽每减半,算术强度翻倍。Roofline 告诉我们:内存受限的负载,提升算力没用,唯一的出路是减少内存流量。FP16 权重每个 2 字节,压成 4-bit 后 0.5 字节,权重内存流量直接除以 4,算术强度升到约 4——所以 weight-only 量化把理论上限抬了 4 倍。把 AI 提到 4 意味着同样的算力能支撑 4 倍的解码速度(在带宽不成为新瓶颈的前提下),这就是”省显存 = 省时间”的定量来源。

  • 右图:权重访问主导内存流量。 把解码阶段的内存访问拆开看,权重访问量比激活访问量大几个数量级(Llama-2-7B 每 token 要读约 14 GB 权重,激活只有几十 MB 量级)。因此只量化权重就抓住了主要矛盾,这也是 AWQ 选 W4A16 而不是 W8A8 的根据:W8A8 的激活量化对减少权重流量没有贡献,反而引入激活量化的精度损失和额外的量化开销。

一句话总结:端侧推理是”内存墙”压顶的场景,而权重是内存流量的绝对主体——把权重压到 4-bit,等于把墙凿宽 4 倍。顺便交代一下这条赛道的大背景:2023 年前后,端侧 LLM 推理框架群雄并起——llama.cpp 用 GGUF 格式 + C++ 单文件把 LLaMA 跑进消费级 CPU/GPU,MLC-LLM 用 TVM 的编译器路线把模型部署到几乎所有平台(论文里明确提到 MLC-LLM 是同期并行工作,在多个边缘 CPU/GPU 上成绩出色),AutoGPTQ 是 GPTQ 的社区工程化实现。TinyChat 是这条赛道里以”量化算法(AWQ)+ 推理系统(TinyChat)协同设计”见长的一支——算法端保证 4-bit 精度,系统端保证 4-bit 的带宽红利不被反量化开销吃掉。

TinyChat:把”理论省显存”变成”实测加速”#

理论省 4 倍内存和实测快 4 倍之间,隔着工程实现。W4A16 有个特有的麻烦:存储和计算用的精度不一样——内存里是 4-bit 整数,而 GPU/CPU 的矩阵乘指令(FP16 乘加)不认识 INT4,必须先把权重反量化回 FP16 再算。W8A8 没有这个问题(内存和计算都是 INT8,反量化可以放在 kernel 尾部统一做);W4A16 的反量化如果每读一批权重就做一遍,反量化本身的开销就可能吃掉省下来的带宽。AWQ 团队为此实现了端侧推理框架 TinyChat(PyTorch 前端 + 设备特定后端的混合),用三个技巧把省显存变成真加速。

技巧一:边加载边反量化(on-the-fly dequantization)#

反量化后的权重绝不落回 DRAM,而是在矩阵乘 kernel 的主循环里完成”读 INT4 → 反量化为 FP16 → 乘加”的流水。虽然数学上反量化就是乘上组步长 Δ\Delta、减去零点,但把它融合进 GEMM 主循环而不是单独写一个反量化 kernel,就省掉了一整轮”写回 DRAM 再读出来”的内存往返。论文明确说,矩阵-矩阵(MM)和矩阵-向量(MV)两种 kernel 都做了这个融合。

技巧二:SIMD-aware 权重打包(weight packing)#

反量化在 CPU 上尤其贵:解包一个 4-bit 权重需要 1 次移位、1 次位与、1 次缩放乘加,而解包出来的权重只参与 1 次乘加——反量化的开销和计算本身同量级。ARM NEON 这类 SIMD 架构偏爱向量化指令,于是 TinyChat 按设备 SIMD 位宽重新打包权重:

论文 Figure 4:面向 ARM NEON 128-bit SIMD 单元的权重打包。原始权重重排后交错打包,运行时用 128-bit 掩码配合 AND 与移位指令一次解包为字节(来源:arXiv:2306.00978 图 4)
论文 Figure 4:面向 ARM NEON 128-bit SIMD 单元的权重打包。原始权重重排后交错打包,运行时用 128-bit 掩码配合 AND 与移位指令一次解包为字节(来源:arXiv:2306.00978 图 4)

具体来说,128-bit 寄存器能装 32 个 4-bit 权重。朴素打包按顺序 w0,w1,,w31w_0, w_1, \ldots, w_{31} 排列,解包时要对每个权重单独做移位和掩码——32 个权重就是 32×3 条标量指令。TinyChat 的打包顺序是交错式的:w0,w16,w1,w17,,w15,w31w_0, w_{16}, w_1, w_{17}, \ldots, w_{15}, w_{31}。这样排列后,用一条 128-bit 掩码和几条位运算就能把 32 个权重整体解包成 16 个字节——解包 32 个权重只需要 3 条 SIMD 指令,而不是 96 条标量指令。论文报告这套打包给 ARM 端带来最高 1.2× 的额外加速。GPU 端则是另一套打包:每 8 个权重按 {0,2,4,6,1,3,5,7}\{0,2,4,6,1,3,5,7\} 的顺序排列(沿用 Kim et al. 2022 的做法),让 8 个 INT4 权重解包后正好填满 4 个 FP16 的通道布局。

技巧三:Kernel 融合#

TinyChat 对 FP16 部分也做了大量融合:QKV 三个投影合成一个 kernel、位置编码在前向里即时计算、KV cache 预分配并在 attention kernel 内更新、LayerNorm 的所有算子(乘法、除法、开方)合成一个 kernel。动机非常实际:4090 上每个 FP16 kernel 的计算时间只有约 0.01ms,和 kernel 启动开销一个量级——kernel 数量减半,时间就接近减半。论文特意举例:Falcon 和 StarCoder 的官方实现 forward 效率差,TinyChat 的融合对这类模型收益最大。

实测加速数据#

论文 Figure 9(和项目主页的 README)给出了端到端结果,这里挑几个有代表性的:

  • RTX 4090(桌面 GPU):对 Llama-2、MPT、Falcon 三个系列,TinyChat W4A16 比 HuggingFace FP16 实现快 2.7~3.9×。以 Llama-2-7B 为例,先靠 FP16 kernel 融合把 52 tokens/s 提到 62 tokens/s,再靠量化线性层额外获得 3.1×;
  • Jetson Orin(移动 GPU,64GB 版):最高 3.5×,并且能跑起 Llama-2-70B(FP16 需要 140GB,根本装不进 64GB 设备)——论文的项目主页报告 Orin 上 70B 模型达到约 38 tokens/s;
  • 笔记本 RTX 4070(8GB 显存):Llama-2-13B 跑到 33 tokens/s,而 FP16 版连 7B 都装不下;
  • Raspberry Pi 4B:7B 模型 0.7 tokens/s——树莓派是极端的算力与带宽限制场景,能跑起来本身就有意义;
  • 与同类系统对比(Figure 10,Orin 上跑 4-bit Llama 系列):比 llama.cpp 快最高 1.7×,比 AutoGPTQ 快 1.2~3.0×,且 TinyChat 支持 StarCoder、StableCode、Mistral、Falcon 等 llama.cpp/exllama 不适配的模型族。

论文 Figure 1(teaser):AWQ + TinyChat 的端侧部署全景——4-bit 量化模型跑在 Jetson Orin Nano(8GB、15W)等边缘设备上,比 FP16 快 3-4 倍;TinyChat 还支持视觉-语言模型(VILA),Orin 上 VILA-7B 从 11.5 提到 35.6 tokens/s(来源:arXiv:2306.00978 图 1)
论文 Figure 1(teaser):AWQ + TinyChat 的端侧部署全景——4-bit 量化模型跑在 Jetson Orin Nano(8GB、15W)等边缘设备上,比 FP16 快 3-4 倍;TinyChat 还支持视觉-语言模型(VILA),Orin 上 VILA-7B 从 11.5 提到 35.6 tokens/s(来源:arXiv:2306.00978 图 1)

实验效果:精度、泛化与生态#

语言建模:全家族、双精度全面占优#

论文 Table 4 是核心精度实验:LLaMA 1/2 家族 7B~70B 六个模型,INT3-g128 和 INT4-g128 两种配置,对比 RTN、GPTQ、GPTQ-R(带重排的 GPTQ)。选几行看(WikiText-2 PPL,越低越好):

模型精度FP16RTNGPTQGPTQ-RAWQ
Llama-2-7BINT3-g1285.476.666.436.426.24
Llama-2-70BINT3-g1283.323.983.883.863.74
LLaMA-7BINT3-g1285.687.018.816.536.35
Llama-2-7BINT4-g1285.475.735.695.635.60
LLaMA-65BINT4-g1283.533.673.663.663.62

两个观察:AWQ 在全部 12 组配置里一致优于 RTN 和 GPTQ(含 GPTQ-R),无一例外;LLaMA-7B 上 GPTQ 的 PPL 高达 8.81,必须靠重排技巧(GPTQ-R)才压到 6.53——而 AWQ 不需要任何特殊处理直接到 6.35。这也解释了论文里”GPTQ 在某些模型上需要 reorder”的吐槽。此外 Mistral-7B(GQA 架构)和 Mixtral-8x7B(MoE 架构)上 AWQ 同样表现出色(INT4-g128 PPL 4.30 / 6.05),说明方法对不同架构普适。

泛化:指令微调、多模态、代码与数学#

AWQ 团队把”泛化能力”作为卖点,实验也刻意覆盖了 RTN/GPTQ 容易翻车的场景:

  • 指令微调模型 Vicuna-7B/13B(Figure 5):用 GPT-4 做裁判对比量化模型与 FP16 原模型的回答质量(80 道题、双向对比共 160 次评判),AWQ 在 INT3-g128 下战胜率一致高于 RTN 和 GPTQ。
  • 多模态模型 OpenFlamingo-9B(COCO 图像描述):INT4-g128 下 32-shot CIDEr 分数,FP16 是 81.70,RTN 掉到 77.13(Δ=−4.57),GPTQ 掉到 74.98(Δ=−6.72,比 RTN 还差!),AWQ 只掉到 80.53(Δ=−1.17,退化量只有 GPTQ 的六分之一)。INT3 下差距更悬殊:AWQ Δ=−7.23,RTN/GPTQ Δ≈−16.9。GPTQ 在多模态任务上比 RTN 还差,正是”重建过拟合文本校准集、破坏视觉特征”的典型症状。
  • 视觉-语言模型 VILA-7B/13B(Table 7):11 个 VLM 基准上 AWQ 与 FP16 几乎逐项打平(如 VILA-7B VQAv2 80.3→80.1、MM-Vet 35.1→35.9),论文称之为 lossless。
  • 代码与数学(Table 8):CodeLlama-7B 的 MBPP pass@1,FP16 38.53,RTN 37.51,GPTQ 反而掉到 31.97(重建把代码能力重建没了),AWQ 40.64 甚至超过 FP16;Llama-2-70B 的 GSM8K,FP16 56.41,AWQ 56.40,几乎无损,而 RTN 只有 53.98。

GPTQ 在代码和视觉任务上翻车、AWQ 不翻车,这个对比把”是否过拟合校准集”从理论担忧变成了实测差距——校准集通常取自通用文本(如 Pile),而代码/数学/图像的数据分布与它差异巨大。

生态与后续#

AWQ 发布后被几乎所有的 LLM 推理栈采纳:vLLM、NVIDIA TensorRT-LLM、HuggingFace TGI、FastChat、LMDeploy、AMD(Quark 工具链)、Google Vertex AI、Amazon SageMaker 等。社区里最流行的实现是 AutoAWQ(casper-hansen 维护):它把 AWQ 的流程自动化成两个阶段——search-best-scale(对每个 decoder layer 做网格搜索,比较量化前后输出的 MSE,选最优缩放)和 apply-scale(把缩放因子融合进前一个算子),并配套高效的 CUDA GEMM kernel(支持 4-bit group 量化、融合旋转位置编码等),量化后模型直接生成 AWQ 格式的 safetensors 供 vLLM 加载。TensorRT-LLM 还在 AWQ 基础上叠加了 2:4 结构化稀疏——4-bit 权重 + 50% 稀疏把单次权重访存再砍一半。这些后续工作从侧面印证了 AWQ 的”缩放范式”是稳定、可组合的。

局限与边界#

把 AWQ 讲清楚之后,也值得把它放在量化地图上看清边界,避免用错场景:

  1. 只省权重的显存,不省激活。 AWQ 是 W4A16:激活仍以 FP16 存于内存。端侧解码时激活流量占比极小(Figure 3 右图),所以够用;但 prefill 阶段长上下文时 KV cache(也是激活的衍生物)会占大头,AWQ 对它无能为力——那是 KV cache 量化(如 KIVI、KVQuant)和缓存淘汰的战场。
  2. 省显存的下限由带宽决定。 4-bit 权重把算术强度提到约 4,但在 4090 上 4 FLOPs/Byte 依然远低于 165 的受限阈值——量化后的解码依然是内存受限的,只是墙变宽了。想要再进一步,需要权重稀疏(2:4 剪枝)或其他减少流量手段。
  3. 不做重建 = 不纠正已发生的误差。 AWQ 的缩放只能”预防”显著通道的误差,不能像 GPTQ 那样用重建”事后补偿”。在 INT2 这种误差大到缩放救不回来的极端场景,AWQ 单独使用不如 AWQ+GPTQ 组合(Table 9 正是这么建议的)。
  4. 仍然需要校准数据。 虽然只要 16 条序列、且分布鲁棒,但”从预训练分布采样”这个前提在闭源模型上不可得——好在实践中用模型自己的对话数据也能工作,AutoAWQ 默认就用 128 条样本。
  5. 缩放是离线静态的。 缩放系数在量化时固定,不会随输入动态调整;对激活分布剧烈变化的输入(如多模态图像 token 与文本 token 混流),静态缩放未必最优——这是后续工作(如动态量化、Outlier Suppression+ 等)的探索方向。

小结#

AWQ 的全部要点可以压缩成四句话:

  1. LLM 的权重不等价——约 1% 的通道承担着不成比例的重要性,且只能用激活分布识别,权重范数做不到;
  2. 保护显著通道不必混合精度——按通道缩放 + 融合进前一层,用纯 INT4 存储达到混合精度效果,且推理零开销;
  3. 缩放系数要搜——目标函数对量化函数不可导,退化为 s=sXα\mathbf{s} = \mathbf{s_X}^\alpha 的一维网格搜索,α[0,1]\alpha \in [0,1]
  4. 省显存要变成加速得有工程——TinyChat 的边加载边反量化、SIMD 打包与 kernel 融合,把理论 4 倍内存压缩变成实测 3.5~3.9 倍加速。

它和 GPTQ 的关系是两种范式的对照:GPTQ 用二阶信息”事后重建”,精度下限更高但过拟合校准集、实现脆弱;AWQ 用激活感知缩放”事前预防”,简单、鲁棒、可组合,代价是极端低位需要与重建方法配合。2024 年 MLSys 最佳论文的桂冠,颁给的是一个”没有新理论、只有好洞察”的工作——它再次证明,在系统领域,一个反直觉的观测加上干净的工程,常常比复杂算法走得更远。

参考资料#

  1. AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration(论文,arXiv:2306.00978)
  2. AWQ 论文 arXiv HTML 全文版(图 1-10 原图来源)
  3. MIT Han Lab AWQ 项目主页(TinyChat 演示与模型库)
  4. llm-awq 官方 GitHub 仓库(论文代码、TinyChat、AWQ 模型动物园)
  5. AutoAWQ GitHub 仓库(社区最流行的 AWQ 自动化实现)
  6. GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers(对比工作论文)
  7. SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models(W8A8 路线的对照工作)
  8. AWQ 论文阅读笔记(中文技术社区解读,含逐段公式讲解)
  9. AWQ:面向设备端大语言模型压缩与加速的激活感知权重量化——论文阅读(阿里云开发者社区)
  10. AMD Quark 工具链的 AWQ 算法文档(厂商落地实现)

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

AWQ 完全拆解:只保护 1% 的显著权重,4-bit 量化如何接近无损
https://pinghaoyang.com.cn/aigc/posts/awq/
作者
平昊阳
发布于
2026-08-26
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
平昊阳
乘长风,破巨浪, 展鸿图于未央!
--
总访问量
--
访客数
公告
欢迎来到我的个人博客!欢迎关注交流吖!
更多相关公告,见
社交-留言」。
音乐
封面

音乐

暂未播放

0:000:00
暂无歌词
站点统计
文章
86
分类
18
标签
110
总字数
726,072
运行时长
0
最后活动
0 天前

文章目录