这里写自定义目录标题
- AutoRound V0.3 特性
- 原理浅析
- 其他工作
- AutoRound 原理
AutoRound(https://github.com/intel/auto-round)在Llama3.1-8B-Instruct上效果明显优于AWQ/GPTQ等方法,在10个任务的平均准确率上我们以63.93%由于AWQ的63.15%和GPTQ的63.04%,具体数据可参考在 低比特开源LLM排行榜。
AutoRound V0.3 特性
支持了更多的设备
AutoRound格式支持CPU、HPU和CUDA推理,并且解决了2-bit kernel精度问题
模型量化recipe
在低比特开源LLM排行榜上发布了,另外发布了少量QWEN2的量化模型。由于公司政策问题,发布模型都要很长时间的审核,因此大部分的量化模型不能发布。
实验性功能
引入了包括激活量化和mx_fp
数据类型在内的多个实验性功能,但是目前不支持实际部署。我们发现AutoRound这这些场景中也有很大的作用。
多模态模型支持
支持了Llava, phi3-vision, Qwen-vl的tuning和推理
其他
另外我们也实现了对low_cpu_mem_usage
、auto_awq
格式、校准数据集连接以及带有chat_template的校准数据集的支持。
接下来我们也会尝试整合不同的算法来提升类似2bit和W4A4等场景的精度,欢迎关注。
觉得我们的工作有帮助的话, 麻烦github上加个小星星。
原理浅析
其他工作
post traning量化如GPTQ和AWQ在业界已经非常出名了,但是在有些模型上还是有不小的损失,另外各有各的缺点(所有算法都有自己的缺点,包括AutoRound). GPTQ相当于伤了左脑补右脑,并且由于hessian矩阵的存在,有时候会不正定。 AWQ相当于转移问题,将量化的难度转移到activation或者不敏感的weight上,它需要插入一个op,这个op大部分可以融合到 layernorm,但是有些只能融合到其他weight上或者只能放弃处理,对精度有一定的影响。此外一些框架会为提速支持compute_dtype为int8,也就是说激活也会量化,AWQ模型一般在这些上面就容易掉点。最后 GPTQ/AWQ共有的缺点就是标定数据不能很多,不然会很慢,因为基本上是相当于batch_size等于数据集大小。
类似于QAT的方法也有很多,不少论文证明的效果非常好。但是个人不太喜欢这样的算法,主要有两点原因,
1 一般速度明显更慢并且需要调学习率和epoch. 虽然我个人也有点训练的经验,但是在调学习率和epoch上感觉还是门外汉,如果大家有好的调参资料可以分享一下。
2 有overfit的风险。一般QAT用的微调数据其实也不是很多,但是大模型训练的数据明显要高几个数量级并且instruct模型或者chat模型都是经过特殊数据(一般拿不到)训练过的来提升安全性等能力。 而QAT的算法或者其他的训练算法一般都会用Adam 优化器,但是Adam优化器对weight的调整是不可空的,有可能经过训练后模型跟原来的差别很大。大部分的论文只会报少量任务的数据,我个人理解就是就算在这些任务上表现比较好,如果模型改动挺大,那没测的一些能力有可能跟原始模型差别比较大。
AutoRound 原理
AutoRound主要是用signSGD也就是在梯度上去正负号来微调网络,微调的参数主要包括两个部分,一个是rouding的值,一个是weight clip,用来控制scale和zp
这里引入一点简单的公式来说明
W
~
=
s
∗
c
l
i
p
(
⌊
W
s
+
z
p
⌉
,
n
,
m
)
,
n
,
m
∈
N
\widetilde{W} = s*clip(\left\lfloor\frac{W}{s}+zp \right\rceil,n,m),n,m \in \mathbb{N}
W
=s∗clip(⌊sW+zp⌉,n,m),n,m∈N
s = m a x ( W ) − m i n ( W ) 2 b i t − 1 s = \frac{max(W)-min(W)}{2^{bit}-1} s=2bit−1max(W)−min(W)
如上面的公式,一般想把一个浮点的权重W量化成一个整数的公式如上,搜一下网上资料很多,不赘述。
我们综合之前的工作在这上面加了两个可调整的参数,一个是V用来控制up-down rounding值,V一般是在[-0.5,0.5],一个是alpha/beta用来控制s和zp , 一般是在[0.5, 1], 有些模型用[0,1]更好些
W
~
=
s
∗
c
l
i
p
(
⌊
W
s
+
z
p
+
V
⌉
,
n
,
m
)
,
n
,
m
∈
N
s
=
m
a
x
(
W
)
∗
α
−
m
i
n
(
W
)
∗
β
2
b
i
t
−
1
\widetilde{W} = s*clip(\left \lfloor\frac{W}{s}+zp +V \right \rceil,n,m),n,m \in \mathbb{N} \\ s = \frac{max(W)*\alpha-min(W)*\beta}{2^{bit}-1}
W
=s∗clip(⌊sW+zp+V⌉,n,m),n,m∈Ns=2bit−1max(W)∗α−min(W)∗β
区别于其他的工作,我们采用signSGD来微调这么参数而不是常用的Adam.
为什么这么设计
1 为什么只允许调up-down rounding
一个是为了防止overfit的问题,让调整后的模型还是接近原始模型;另外一个我们也测过放开这个限制,印象中在我们测试的场景中没有优势;第三个是如果范围扩大用SignSGD不好微调,具体原因可以看下面。
2 为什么用SignSGD
2.1 上面提到了,V/alpha/beta都是有界的,所以用SignSGD可以快速的为每一个参数快速的探索整个空间。因为SignSGD是这么调整权重的
W
=
W
−
S
i
g
n
(
g
r
a
d
)
∗
l
r
W = W-Sign(grad)*lr
W=W−Sign(grad)∗lr
如果我们控制所有iter下lr的和, 那在一定步数下,我们就能遍历整个空间。比如我们的默认参数是200步,然后初始lr是1.0/200, 然后用的是linear decay,那这200步lr的和是200*1.0/200 *0.5 = 0.5,刚好是0.5, 由于sign有正负,所有它搜索的范围是[-0.5, 0.5]刚好是我们想要的区间。
2.2 搜索精度够足够用
V: V的最优解空间很大,比如原始是4.6,本来是要往上rounding,如果最优解是向下rounding,那么V的取值可以是[-0.5, -0.1),所以只要搜到其中的任何一个值就可以,因此不需要很精确的搜索
alpha, beta:由于我们的lr是线性下降的,虽然没有数学证明或者实际测过,我们用signround能搜到理论的解还是很多的,所以两点的间隔应该不会很大,就算最优解刚好落到这两点之间,实际上损失也不大。
2.3 节省显存和提速。
Adam会存下不少的state,有momentum和variance. 不要小看这些临时变量,因为在AMP训练中,这些都是FP32的,具体可以参考ZeRO: Memory Optimizations Toward Training Trillion Parameter Models