0 AWQ是什么
AWQ
AWQ(Activation-aware Weight Quantization)是一种为大语言模型设计的高效量化方法。说得直白点,它的目的就是:尽量不影响模型效果的前提下,把模型压得又小又快,让部署更轻松、成本更低。
它的设计之处在于,不是一刀切地压缩所有权重,而是压缩时会考虑激活值的分布。
模型每次推理时,权重和激活值要配对一起乘法,也就是矩阵相乘,但其实又不是所有乘积都对结果有影响,只有那些权重很大/激活值也大的组合,才真正主导了模型的输出,于是根据这个价值取向AWQ会重要的保精度,不重要的大胆压缩。
于是模型照样聪明(期望如此),但运行更快、用的显存更少,工程部署也更香了。
关键点
1. 权重和激活的乘积主导输出
模型中最核心的计算是:y = W * x
其中:
-
W 是权重矩阵(可量化)
-
x 是激活输入向量(不可控)
-
y 是输出
AWQ关注的是:哪些 (W_ij, x_j) 的乘积对最终输出影响最大。
2. 分组量化(Group-wise Quantization)
AWQ 会把参数分成多个 group,对每组设置独立的缩放因子(scale),解决全局缩放过于粗糙的问题。
就像分组的pooling得到符合当前组状况的mean值,分组缩放也让AWQ处理得相对精细。
3. 量化噪声建模
在量化中,不可避免会引入误差(称为“量化噪声”),将一个连续的浮点数(比如权重 w)映射到一个离散的低精度表示 q(w),差值 w - q(w) 就是所谓的量化误差(噪声)。
AWQ尝试最小化关键通道的误差 & 最大化不敏感部分的压缩率,目标是最小化这些噪声对输出的影响,而不是单纯去最小化w - q(w)或者量化 w,而是考虑了这个 w 在推理时乘以输入 x 后对输出的影响大小
关键思想是:不是所有的量化误差都重要,只有那些 x × (w - q(w)) 很大的才真正影响模型输出。
于是,AWQ 建立了一个近似优化目标:
Minimize: ∑ 重要通道 (w - q(w))²,其中 q(w) 表示量化后的权重值。
将“量化误差矩阵” (W - q(W)) 投影到激活向量 x 上,观察它对输出的扰动大小,让量化误差在激活向量 x 上的投影尽可能小,这才是对真实输出的影响最小。
如果这个值很小,说明量化对输出几乎没有影响;如果很大,说明这个量化方法会让模型说错话。
1 环境配置
我这里用的是autoawq呢,因为本身已经装了vLLM等依赖,也暂时不想新建环境,就直接拉AutoAWQ库了
另外显卡是NVIDIA RTX 4090,量化的是LoRA微调的Qwen2-VL-7B
依赖 | 推荐版本 | 说明 |
---|---|---|
Python | >=3.10,<3.13 | 避免 Python 3.13(cgi模块已被移除) |
CUDA | 12.1 - 12.6 | 与 vLLM / TensorRT / AutoAWQ 兼容 |
PyTorch | 2.1.0 ~ 2.3.0 | 2.4+ 一些版本存在兼容性问题 |
Transformers | 4.37.2 or 4.39.3 | AWQ 支持最佳的版本段 |
autoawq | 最新版本 | git上5月停止更新 |
vLLM | >=0.3.1,<0.9.1 | 与 AWQ 输出文件结构兼容 |
2 具体实践
安装AutoAWQ源码
git clone https://github.com/casper-hansen/AutoAWQ.git
cd ./AutoAWQ-0.2.5
pip install -e .
选择语言模块
视觉模块量化就比较复杂,我短时间应该搓不出来,所以只处理Qwen2-VL-7B的语言部分
这一步qwen对应处理文件中,根据模型结构把move embedding之类返回的model改成model.language_model
运行权重转换
4090量化Qwen2-VL-7B,所以我把采样等设置得比较小,但是也挺快的20分钟搞定
激活采样数量极少,避免OOM,且降低每个样本序列长度,节省显存:
python examples/quantize.py
–model_path your_model
–output_path output_awq
–calib-samples 4 \ –calib-seq-len 4 \
量化推理
在vLLM的参数中制定量化后的存放路径,并加入—quantization awq
References
Bian, Zhengda, et al. AWQ: Activation-Aware Weight Quantization for LLM Compression and Acceleration. arXiv preprint arXiv:2306.00978, 2023.