现在考虑一个权重元素 <math xmlns="http://www.w3.org/1998/Math/MathML"> w ∈ w w\in \mathbf{w} </math>w∈w,如果我们将 w 与 s (s>1)相乘, 然后,再用 x 除以 s(其idea来源于之前的工作SmoothQuant),我们将得到 <math xmlns="http://www.w3.org/1998/Math/MathML"> y = Q ( w ) x = Q ( w ⋅ s ) ( x / s ) y=Q(\mathbf{w})\mathbf{x}=Q(w\cdot s)(x/s) </math>y=Q(w)x=Q(w⋅s)(x/s),即:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> Q ( w ⋅ s ) ⋅ x s = Δ ′ ⋅ Round ( w s Δ ) ⋅ x ⋅ 1 s Q(w\cdot s)\cdot \frac{x}{s} = \Delta^{'} \cdot \text{Round}(\frac{ws}{\Delta}) \cdot x \cdot \frac{1}{s} </math>Q(w⋅s)⋅sx=Δ′⋅Round(Δws)⋅x⋅s1
其中, <math xmlns="http://www.w3.org/1998/Math/MathML"> Δ ′ \Delta^{'} </math>Δ′ 是应用 s 后的新的量化缩放(scaler)因子。
根据经验发现:
<math xmlns="http://www.w3.org/1998/Math/MathML"> Round ( ⋅ ) \text{Round}(\cdot) </math>Round(⋅) 的预期误差(记为 <math xmlns="http://www.w3.org/1998/Math/MathML"> R o u n d E r r RoundErr </math>RoundErr)没有变化:由于舍入函数将浮点数映射为整数,误差大致均匀分布在 0-0.5 之间,平均误差为 0.25;
放大单个元素 w 通常不会改变组 w 的极值,因此 <math xmlns="http://www.w3.org/1998/Math/MathML"> Δ ′ ≈ Δ \Delta^{'}\approx\Delta </math>Δ′≈Δ;
<math xmlns="http://www.w3.org/1998/Math/MathML"> Q ( w ⋅ s ) ⋅ x s = Δ ′ ⋅ Round ( w s Δ ) ⋅ x ⋅ 1 s Q(w\cdot s)\cdot \frac{x}{s} = \Delta^{'} \cdot \text{Round}(\frac{ws}{\Delta}) \cdot x \cdot \frac{1}{s} </math>Q(w⋅s)⋅sx=Δ′⋅Round(Δws)⋅x⋅s1 的误差可表示为 <math xmlns="http://www.w3.org/1998/Math/MathML"> E r r ′ = Δ ′ ⋅ R o u n d E r r ⋅ 1 s Err^{'}=\Delta^{'} \cdot RoundErr \cdot \frac{1}{s} </math>Err′=Δ′⋅RoundErr⋅s1,与原始误差 <math xmlns="http://www.w3.org/1998/Math/MathML"> R o u n d E r r RoundErr </math>RoundErr 之比为 <math xmlns="http://www.w3.org/1998/Math/MathML"> Δ ′ Δ ⋅ 1 s \frac{\Delta^{'}}{\Delta} \cdot \frac{1}{s} </math>ΔΔ′⋅s1. 给定 <math xmlns="http://www.w3.org/1998/Math/MathML"> Δ ′ ≈ Δ \Delta^{'}\approx\Delta </math>Δ′≈Δ 和 <math xmlns="http://www.w3.org/1998/Math/MathML"> s > 1 s>1 </math>s>1, 显著权重 w 的相对误差较小。
为了验证这个想法,作者将 OPT-6.7B 模型的 1% 显著通道乘以 s > 1,并测量下表中每组的 Δ 变化。发现缩放显著通道非常有效:困惑度从s = 1(即 RTN)的 23.54 提高到 s = 2 的 11.92。
随着 s 变大,Δ 变化的百分比通常会变大,但当 s < 2 时,Δ 变化的百分比仍然很小; 随着 s 的增加,显著通道的相对误差继续变小。尽管如此,最佳 PPL 实际上出现在 s = 2 时。这是因为如果我们使用非常大的 s,当 Δ 增加时,非显著通道的相对误差将会增加 (非显著通道的误差将被放大) <math xmlns="http://www.w3.org/1998/Math/MathML"> Δ ′ Δ \frac{\Delta^{'}}{\Delta} </math>ΔΔ′。并且在 s = 4 下,21.2% 的通道的比率大于 1,这可能会损害模型的整体精度。 因此,我们在保护显著通道的同时还需要考虑非显著通道的误差。 这就需要自动获取缩放比的方法,使得减少显著权重量化损失的同时也不能增加其它权重的量化损失。
为了同时考虑显著权重和非显著权重,作者选择自动搜索最佳(每个输入通道)缩放因子,使某一层量化后的输出差最小。从形式上看,我们希望优化以下目标:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> s ∗ = arg min s L ( s ) , L ( s ) = ∥ Q ( W ⋅ s ) ( s − 1 ⋅ X ) − W X ∥ \mathbf{s}^* = \argmin_{\mathbf{s}} \mathcal{L}(\mathbf{s}), \quad \mathcal{L}(\mathbf{s})=\lVert Q(\mathbf{W}\cdot \mathbf{s}) (\mathbf{s^{-1}} \cdot \mathbf{X}) - \mathbf{W}\mathbf{X} \lVert </math>s∗=sargminL(s),L(s)=∥Q(W⋅s)(s−1⋅X)−WX∥
为了使这一过程更加稳定,我们通过分析影响缩放因子选择的因数,为最佳缩放比例定义了一个搜索空间。如前所示权重通道的显著性实际上是由激活比例(scale)决定的(即 "激活感知")。因此,我们只需使用一个非常简单的搜索空间:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> s = s X α , α ∗ = arg min α L ( s X α ) \mathbf{s}=\mathbf{s_X}^{\alpha}, \quad \alpha^*=\argmin_{\alpha}\mathcal{L}(\mathbf{s_X}^{\alpha}) </math>s=sXα,α∗=αargminL(sXα)
其中,s仅与激活 <math xmlns="http://www.w3.org/1998/Math/MathML"> s X s_X </math>sX的大小有关,作者使用单个超参数α来平衡显著通道和非显著通道的保护。我们可以通过在 [0, 1] 区间内进行快速网格搜索(grid search)来找到最佳的 α(0 表示我们不进行缩放;1 对应于最激进的缩放)。
作者还通过最小化 MSE 误差来进一步应用权重剪裁,因为剪裁权重可以进一步帮助减少 <math xmlns="http://www.w3.org/1998/Math/MathML"> Q ( w ⋅ s ) ⋅ x s = Δ ′ ⋅ Round ( w s Δ ) ⋅ x ⋅ 1 s Q(w\cdot s)\cdot \frac{x}{s} = \Delta^{'} \cdot \text{Round}(\frac{ws}{\Delta}) \cdot x \cdot \frac{1}{s} </math>Q(w⋅s)⋅sx=Δ′⋅Round(Δws)⋅x⋅s1 中的 Δ′; 从而减少量化误差。
from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer
model_path = "facebook/opt-125m"
quant_path = "opt-125m-awq"
quant_config = {"zero_point": True, "q_group_size": 128, "w_bit": 4, "version":"GEMM"}
# Load model
model = AutoAWQForCausalLM.from_pretrained(model_path)
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
# Quantize
model.quantize(tokenizer, quant_config=quant_config)
为了使量化后的模型与Transformers兼容,我们需要修改配置文件。
ini复制代码
from transformers import AwqConfig, AutoConfig
from huggingface_hub import HfApi
# modify the config file so that it is compatible with transformers integration
quantization_config = AwqConfig(
bits=quant_config["w_bit"],
group_size=quant_config["q_group_size"],
zero_point=quant_config["zero_point"],
version=quant_config["version"].lower(),
).to_dict()
# the pretrained transformers model is stored in the model attribute + we need to pass a dict
model.model.config.quantization_config = quantization_config
# save model weights
model.save_quantized(quant_path)
tokenizer.save_pretrained(quant_path)
加载量化后的模型:
ini复制代码
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("ybelkada/opt-125m-awq")
model = AutoModelForCausalLM.from_pretrained("ybelkada/opt-125m-awq").to(0)
text = "Hello my name is"
inputs = tokenizer(text, return_tensors="pt").to(0)
out = model.generate(**inputs, max_new_tokens=5)
print(tokenizer.decode(out[0], skip_special_tokens=True))