随着大模型的出现,大家越来越意识到大模型的优势,相比传统的模型,缺点和不可用也显而易见,其中比较明显的就是算力的需求,这是很多公司可望而不可及的。为减少显存的占用,在训练阶段,主权重采用fp32,而推理时,fp16通常能提供与fp32相似的精度,这意味着,在使用大模型时,通过将模型转化为fp16,采用一半的显存就可以获取相同的效果,即使这样,显存的占用仍是巨大的,接着人们发现可以采用我们今天介绍的主角量化技术,来进一步减少显存的消耗。
基本原理
Int8量化即将浮点数xf通过缩放因子scale映射到范围[-128,127]范围内。
Scale=max(abs(xf))/127
量化公式:xq=clip(round(xf/scale))
round是取整函数,clip是将离群值截断到int8范围内。
当进行矩阵乘法时,可以通过组合各种技巧,例如逐行或逐向量量化,来获取更精确的结果。对矩阵乘法,常规量化方式,即用整个张量的最大绝对值对张量进行归一化。但一般不采用常规量化方式,而使用向量量化方法,找到 A 的每一行和 B 的每一列的最大绝对值,然后逐行或逐列归一化 A 和 B 。最后将 A 与 B 相乘得到 C。最后,我们再计算与 A 和 B 的最大绝对值向量的外积,并将此与 C 求哈达玛积来反量化回 FP16。
LLM.int8 量化的特点与优化
A=[-0.10, -0.23, 0.08, -0.38, -0.28, -0.29, -2.11, 0.34, -0.53, -67.0]
去掉反量化:
[-0.10, -0.23, 0.08, -0.38, -0.28, -0.28, -2.11, 0.33, -0.53]
不去掉反量化结果:
[ -0.00, -0.00, 0.00, -0.53, -0.53, -0.53, -2.11, 0.53, -0.53, -67.00]
可以看出A有一个离群值-100.0,去掉该值的反量化和不去掉的反量化,差异较大,其中不去掉大部分的信息会丢失。
LLM.in8() 论文中发现:激活中存在一些离群值,它们的绝对值明显更大;并且这些离群值分布在少量的几个特征 (features) 中,称为离群特征 (Emergent Features)。
采用混合精度分解的量化方法:将包含了Emergent Features的几个维度从矩阵中分离出来,对其做高精度的矩阵乘法;其余部分进行量化。如下图所示:
采用上述方式量化不会造成模型性能的下降,但是采用vector-wise(向量量化)方法进行量化会使模型性能有非常大的下降。
(说明:vector-wise 量化:为矩阵内积中独立的行、列向量设置各自的 scaling constant。这种量化方式引入了更多的量化参数,量化的结果相比常规量化方法更加精确。)
大模型的实现代码:
转化为半精度
model = AutoModelForCausalLM.from_pretrained("...", torch_dtype=torch.bfloat16, device_map="auto")
Int8量化和int4量化
model = AutoModelForCausalLM.from_pretrained("...r", load_in_8bit=True)
model = AutoModelForCausalLM.from_pretrained("...r", load_in_4bit=True)