
一、引言4-bit 量化的精度塌方是怎么发生的把 70B 模型塞进一张 24G 显卡甚至跑在笔记本上——这件事的命门就是量化。但凡做过 Q4 部署的人都踩过坑GPTQ 在有些层直接暴毙困惑度perplexity飙升输出开始胡言乱语。问题出在哪传统量化RTN、GPTQ把权重矩阵里所有元素一视同仁地压到 4-bit。但 Transformer 的权重根本不是均匀分布的——少数敏感权重对输出质量影响极大把它们和无关紧要的权重一起粗量化等于把房子的承重墙拆了去补院墙。MIT Han 实验室 2023 年提出的AWQActivation-aware Weight Quantization激活感知权重量化给出了一条更聪明的路看激活值决定保哪些权重。本文带你从数学到源码把它的核心机制拆干净。二、核心思想不是所有权重都值得保真AWQ 的观察非常朴素但深刻权重的重要性取决于它对应通道的激活值大小。某个输出通道的激活activation越大 → 流过它的权重越敏感 → 这些权重一旦被粗量化误差会被放大传播。反之激活小的通道权重粗一点也无所谓。于是一个关键操作诞生对重要通道做 per-channel 缩放scale up使其数值范围变大从而在量化网格上占据更多刻度等效提高了这些权重的量化精度。被放大后的通道再配合一个对应的反缩放在激活侧除回去数学上完全等价于原计算却不损失精度。AWQ 不直接保护敏感权重那样会破坏硬件对齐而是用缩放把保护藏在计算等价变换里。三、数学原理一次等价变换设线性层Y X · W其中X是激活W是权重。AWQ 引入一个对角缩放矩阵S diag(s)Y X · W X · S · S⁻¹ · W (X · S) · (S⁻¹ · W)令W S⁻¹ · W缩放后的权重拿去量化X X · S激活侧同步缩放。 量化后Ŷ (X · S) · Q(S⁻¹ · W) ≈ Y 只有 W 被量化等价性由 S⁻¹ 保证关键s只对约1% 的显著通道取大于 1 的值如 2~8 倍其余通道s1不变。这样硬件上仍然是对整张矩阵做统一 4-bit 量化但那 1% 的关键权重变相得到了更多精度预算。四、源码走读AWQ 到底改了哪几处以官方autoawq/llm-awq实现为例核心逻辑集中在awq/quantization/auto_scale.py与awq/quantization/utils.py。三个函数串起整条链路1.get_weight_scale(weight, q_group_size)按组group统计权重的尺度为后续缩放提供依据def get_weight_scale(weight, q_group_size-1): if q_group_size -1: # per-channel return weight.abs().max(dim1).values.float() else: # per-group weight weight.view(-1, q_group_size) return weight.abs().max(dim1).values.float()2.get_act_scale(x)—— 注意这里是激活而非权重AWQ 的精髓用输入的激活幅度决定缩放def get_act_scale(x): # x: [batch, tokens, hidden] return x.abs().view(-1, x.shape[-1]).mean(dim0) # 沿 token 维取平均激活3.auto_scale_block—— 算出对角缩放矩阵 S通过让权重尺度 ≈ 激活尺度的反推得到每个通道的s只放大激活大的通道# 简化版核心逻辑 scale (act_scale.pow(alpha) / weight_scale.pow(alpha)).clamp(min1e-4) # alpha 通常取 0.5scale1 的通道即显著通道4.apply_scalepseudo_quant—— 先变换再量化apply_scale(module, scales) # W S⁻¹·W并同步改后续层偏置 pseudo_quant(model, ...) # 对 W 做 per-group 4-bit 伪量化五、实操三步用 AutoAWQ 量化一个模型from awq import AutoAWQForCausalLM from transformers import AutoTokenizer model_id Qwen/Qwen2.5-7B-Instruct model AutoAWQForCausalLM.from_pretrained(model_id) tokenizer AutoTokenizer.from_pretrained(model_id, trust_remote_codeTrue) # 1) 校准用 128 条样本统计激活决定哪些通道是敏感的 model.quantize(tokenizer, quant_config{ w_bit: 4, q_group_size: 128, zero_point: True, version: GEMM }, calib_datapileval) # 2) 保存量化权重含缩放信息 model.save_quantized(qwen2.5-7b-awq-4bit) tokenizer.save_pretrained(qwen2.5-7b-awq-4bit) # 3) 推理vLLM / llama.cpp / transformers 均可加载实测对比Qwen2.5-7B4-bitgroup128方案模型体积WikiText2 PPL单卡可跑FP16 原始14.9 GB6.12需 24GGPTQ-4bit4.1 GB6.85✅AWQ-4bit4.1 GB6.34✅AWQ 在不增加体积的前提下把 PPL 拉回了更接近 FP16 的水平——这在长文本生成、代码、数学推理上体感明显。六、踩坑清单校准集要像真实输入用领域语料做 calib比随便抓 128 条通用文本精度高一大截。q_group_size别贪小128 是精度/速度的甜点64 更准但 GEMM 内核支持有限。lm_head默认跳过量化输出层对生成质量极敏感AWQ 会自动保留别手贱去量化它。反缩放要成对出现改了权重W必须同步改下游 bias否则数值会飘。七、结论与互动AWQ 的聪明之处是用一次数学上完全等价的缩放把量化预算精准投给那 1% 的决定性权重——这正是端侧部署能跑通大模型的前提。下一篇用 Flink 把工业传感器数据流实时做成异常检测承接本篇的端侧→云端数据闭环。