AI学习者 · 6月11日

LLM PTQ量化经典研究解析

本文主要对近年流行和经典的LLM PTQ量化算法论文进行一些汇总和分析。由于每篇详解的文章很多,本文不会逐篇做非常细致的讲解,主要对LLM量化算法的发展演进和核心思想方法做一些归纳,希望能触发一些思考和讨论。

GPTQ

GPTQ: ACCURATE POST-TRAINING QUANTIZATION FOR GENERATIVE PRE-TRAINED TRANSFORMERS (https://arxiv.org/abs/2210.17323)

Code: https://github.com/IST-DASLab...

Type:W4A16

image.png

  1. 舍弃了筛选参数进行量化的贪心策略,直接顺序方式对所有参数进行量化。
  2. 在量化-更新-量化-更新的迭代中使用批处理更新从而延迟一部分参数的更新,缓解 I/O 压力。
  3. 用 Cholesky 分解求海森矩阵的逆,在增强数值稳定性的同时,不再需要对海森矩阵做更新计算,进一步减少了计算量。

最终算法描述如下,详细的代码解析可以参考进击的Killua:GPTQ & SmoothQuant & AWQ 代码解析 (https://zhuanlan.zhihu.com/p/...)。GPTQ很好地解决了weight优化的问题,所以在开源社区多数大模型都有其对应的GPTQ 量化实现,但是它没有涉及解决异常值问题和 Activation 量化(给后人留了空间),而且利用calibration set进行量化的过程中存在一定过拟合风险。

image.png
GPTQ算法流程

LLM.int8()

LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale (https://arxiv.org/abs/2208.07339)

Code: https://github.com/TimDettmer...

Type:W8A8

然后出自NeurIPS 2022的LLM.int8(),也是里程碑式的一篇文章,它没有复杂的计算公式,但提出的关于离群点的发现和度量具有深远的意义,影响了后续一系列的优化,基于此它以近乎无损的精度而闻名于业界。值得一提的是这篇文章的作者Tim Dettmers是模型量化压缩方向的大牛,出品了多篇高质量论文,有时间可以仔细阅读。

LLM.int8()发现LLM规模变大后会出现少量非常重要的离群点(即异常值),这些点对attention效果有较大影响,同时对量化带来挑战

论文的核心思想非常简单直接,就是分而治之。通过离群(Outlier)检测,把输入X和权重W中包含异常值的行、列挑选出来直接做fp16的浮点矩阵乘法,然后剩下的正常点用矢量化方法(X每一行用absmax进行量化、W每一列用absmax进行量化)量化后进行int8乘法再反量化回fp16,最后把它们累加起来作为最终结果输出,如下图所示。

image.png

这种简单的处理方式当然也会带来一些问题,比如离群点的检测、拆分以及合并会带来一些额外的计算开销,同时随着离群点增多混合精度的计算复杂度会显著提升,对性能提升的幅度会明显下降。当然这只是个开端,后面有很多研究是围绕这些优化展开的。

SmoothQuant

SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models (https://arxiv.org/abs/2211.10438)

Code:https://github.com/mit-han-la...  、https://github.com/Guangxuan-...

Type:W8A8

SmoothQuant是MIT 韩松老师实验发表的,已经集成到Pytorch、TensorRT-LLM等框架中成为W8A8的业界主流。它发现权重比较容易量化,激活值不易量化,因为有前文提到的离群值,激活值中某些channel异常地高。那么对激活值用per-channel的方式进行量化精度下降可能会比较小,但是这样就无法很好地使用TensorCore进行硬件加速了。于是作者就提出先用smooth的方式对weight和channel维度activation进行调整,平滑后就比较容易量化了,如下图所示。

image.png

猜测作者可能是借鉴了Cross Layer Equalization (https://arxiv.org/abs/1906.04721)论文的思想在LLM上也撸了一遍,这种平滑的处理方式其实在做常规PTQ量化的同学已经想到过了,只不过面向的场景不太一样,CLE是在不同layer之间做smooth,而这里是在权重和激活值上做smooth。平滑的具体做法如下所示,在激活值上进行缩放,同时在权重上进行扩增,这样总的结果是保持不变的,但是计算时候激活值的波动就变小了,这里还有个超参用来调整缩放的大小。详细的代码解析可以参考进击的Killua:GPTQ & SmoothQuant & AWQ 代码解析(https://zhuanlan.zhihu.com/p/...)

image.png

AWQ

AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration (https://arxiv.org/abs/2306.00978)

Code:https://github.com/mit-han-la...

Type:W4A16

AWQ是一种LLM低比特权重量化方法,MLSys 2024的best paper,也是韩松老师实验室发表的,可以认为是当前W4A16的SOTA,已经被应用到很多低比特量化框架中,如TensorRT-LLM、FastChat、vLLM、TGI、LMDeploy。它和SmoothQuant有些像,只是SmoothQuant侧重于对matrix multiplication场景的weight和activations进行INT8量化(W8A8),而AWQ关注在low bit(INT4) weight量化(W4A16),主要被应用在linear layer(包含最多的参数),详细的代码解析可以参考进击的Killua:GPTQ & SmoothQuant & AWQ 代码解析 (https://zhuanlan.zhihu.com/p/...)

image.png

它核心的贡献:

  1. 发现weight对模型的重要程度存在极强的不均衡性,1%的参数可能主导的量化过程中损失的性能,假如我们在量化中保护这1%的参数,就能极大程度保护模型性能不受影响,但是混合精度(FP16+低比特)对硬件不友好。
  2. 那么如何发现重要weight?不用权重!用激活值来发现重要的weight
  3. 不用混合精度的话如何保护重要weight?对weight进行per-channel的scale同时对激活值除以scale
  4. 如何确定最合适的scale?量化误差函数不可微,没法用梯度下降求解,所以退而减少搜索空间。取和激活值相关的值进行grid search,找到那个让量化误差最小的scale

image.png

ZeroQuant系列

ZeroQuant: Efficient and Affordable Post-Training Quantization for Large-Scale Transformers(https://arxiv.org/abs/2206.01861)

ZeroQuant-V2: Exploring Post-training Quantization in LLMs from Comprehensive Study to Low Rank Compensation(https://arxiv.org/abs/2303.08302)

ZeroQuant-FP: A Leap Forward in LLMs Post-Training W4A8 Quantization Using Floating-Point Formats(https://arxiv.org/abs/2307.09782)

ZeroQuant-HERO: Hardware-Enhanced Robust Optimized Post-Training Quantization Framework for W8A8 Transformers(https://arxiv.org/abs/2310.17723)

Code:https://github.com/microsoft/...

ZeroQuant系列其由微软DeepSpeed团队于2022年推出,是一个端到端的量化推理流水线,具有很强的工程实践特性,至今已经发展成了一个系列量化算法,应用还是比较广泛的。

第一版的ZeroQuant主要包含以下三个方法:

  1. 对weight进行per-group量化,对activiation应用per-token的动态量化,兼顾了性能和精度。
  2. 使用了逐层知识蒸馏来提取量化网络,降低了显存开销。
  3. 使用cutlass prelogue进行量化算子fuse,使用epilogue进行反量化算子fuse,降低量化带来的性能损失。

image.png

第二版ZeroQuant-V2更多的是一些分析和总结,它分析了权重量化和激活值量化对精度的敏感性,比较了常用PTQ算法的模型效果,最后引入了一种称为低秩补偿(LoRC)的优化技术,它可以与 PTQ 的协同工作,以最小的模型参数大小的增加来改善整个模型质量的恢复,但这种方法的扩展性似乎不是很好。

第三版ZeroQuant-FP主要探索了浮点(FP)量化的可行性,特别关注FP8和FP4格式。对于LLM,FP8激活在性能上优于INT8,而在权重量化方面,FP4在性能上与INT4相比具有可比性,甚至更优越;LoRC有助于提升W4A8的整体表现。同时为了解决由权重和激活之间的差异(从FP4到FP8)引起的挑战,ZeroQuant-FP要求所有缩放因子为2的幂,并将缩放因子限制在单个计算组内。

image.png

第四版ZeroQuant-HERO是一种新的硬件增强型训练后 W8A8 量化框架,它考虑了内存带宽限制和计算密集型运算,总体偏工程方向,将transformer中更多子模块进行了量化改造,分别是:Embedding层量化、Attention模块量化、MLP 模块量化,同时采用不同量化精度对各个模块进行量化组合,按需选取量化等级。

image.png

SpQR

SpQR: A Sparse-Quantized Representation for Near-Lossless LLM Weight Compression(https://arxiv.org/abs/2306.03078)

Code: https://github.com/Vahe1994/SpQR

Type: W4A16

SpQR和LLM.int8()是同一作者,也是Tim Dettmers提出的,它有点像AWQ+GPTQ+LLM.int8()的混合体,整体上还是比AWQ复杂很多。它也像AWQ一样发现了weight对模型的重要程度存在极强的不均衡性,1%的参数可能主导的量化过程中损失的性能这一事实。但是它对识别敏感weight和保护敏感weight的做法和AWQ不一样,更像是GPTQ和LLM.int8()的做法。

首先它用类似OBC(Optimal Brain Compression)的方式来计算参数的敏感度,求解结果如下所示。

image.png

通过统计发现了敏感weight位置分布的一些特性,大多具有特定的结构(行、列、注意力头、非结构化等),为此SpQR对两类weight进行特殊处理:敏感值group和单个异常值,然后将它们存储在更高的精度中;将所有其他权重压缩为3-4比特。利用这些发现提出一个压缩表示,可以支持所有这些不同的离群值类型。

image.png

该压缩表示的内容为:

  1. dense的普通权重(低比特量化)
  2. group的量化敏感权重值(高精度)
  3. sparse的离群单点(高精度)

下图是单个weight张量的 SpQR 表示的高级概述,右侧描述了所有存储的数据类型及其维度。作者还为 SpQR 格式设计了一个基于 GPU 的高效解码实现。SpQR效果还是挺好的,在某些大模型上的效果比AWQ还要好一些,但它比AWQ复杂性高出很多,所以应用广泛度不及AWQ。

image.png

OWQ

OWQ: Outlier-Aware Weight Quantization for Efficient Fine-Tuning and Inference of Large Language Models (https://arxiv.org/abs/2306.02272)

Code: https://github.com/xvyaward/owq

Type: W4A16

OWQ也是延续了LLM.int8()和GPTQ的思想,weight的某些channel特别敏感最好使用fp16来存储,但是OWQ的筛选的方法是使用类似GPTQ的海森矩阵,而不是LLM.int8的outlier feature统计。OWQ对交叉维的每个channel计算敏感度指标如下:

image.png

其中是海森矩阵的第j个对角线元素。选择敏感度最大的top-k看成weak columns转化为fp16存储,其余部分用GPTQ的低比特方案存储(例如4比特),本质上也是混合精度的方式。具体操作如下:

  • 把原始 𝑊 转换成全量的低比特矩阵,weak column(敏感列)用0填充。
  • 单独额外存储fp16的weak columns列,并且把列号附在最后一个元素后面。

论文同时提出对特定任务的finetune采取对低比特矩阵冻结,仅对weak column微调的方式来进行,能够做到在保持精度的同时节省内存开销的目的。

image.png

SqueezeLLM

SqueezeLLM: Dense-and-Sparse Quantization(https://arxiv.org/abs/2306.07629)

Code:https://github.com/SqueezeAIL...

Type: W4A16

SqueezeLLM也是一个权重量化算法,它基于的事实也已成为标准,即

  1. LLM模型推理的主要瓶颈是带宽,存在内存墙。
  2. 权重存在不同敏感度,少量权重非常敏感需要针对性进行量化。

和之前的AWQ、SpQR等的区别体现在:

  1. 它采用近似的Fisher information来度量敏感度,这是一种新的度量方式。然后基于敏感度进行低比特非均匀量化,使用kmeans聚类来生成靠近敏感值的量化定点,其它点以MSE最小来安置,从而最小化量化误差。

image.png

  1. 稠密和稀疏分解,高效的稀疏格式来存储outlier和敏感权重(FP16),稠密格式来存储大量的低比特常规权重值。分别开发了kernel来处理稠密和稀疏的矩阵向量乘kernel。

在困惑度方面,战胜了RTN,GPTQ,AWQ这些权重量化的方法,但是在加速与内存节省方面稍逊于GPTQ。

RPTQ

RPTQ: Reorder-based Post-training Quantization for Large Language Models(https://arxiv.org/abs/2304.01089)

Code: https://github.com/hahnyuan/R...

Type: W4A4/W4A8/W4A4KV

RPTQ主要研究的是激活值的量化,它发现即使除去outlier不同channel的range变化还是很大,如果用per-tensor的方式去量化误差较大,而per-channel的方式执行效率低,所以采取折中的方式per-group量化。

RPTQ的主要思想是对激活值的channel进行kmeans聚类重排,把(min,max)近似的channel聚成一个group,在这个基础上进行量化

image.png

内存重排的开销还是比较大的,为了减少这部分开销提出了一些工程优化:

  1. 把重排操作融入到了layernorm层中,这个想法比较简单,直接在layernorm刷回内存时按新排序的index进行写入。
  2. 调整了weight顺序,允许线性层直接接受重排的激活值,同时自身也输出重排的激活值。
  3. 矩阵乘和线性层也都需要input channel对齐。

transformer block的reorder如图所示。整个流程稍微有点绕,真正要落地到LLM大规模工程实践还有一些工作要做。

image.png

ATOM

ATOM: LOW-BIT QUANTIZATION FOR EFFICIENT AND ACCURATE LLM SERVING(https://arxiv.org/pdf/2310.19102)

Code: https://github.com/efeslab/Atom

Type: W4A4

ATOM几乎是W4A4类型的SOTA,也是之前各项工作的集大成者,提出了一系列针对LLM特性的量化策略和工程实践:

  1. 进行混合精度量化,outlier activation值使用INT8,normal值使用INT4,复用了RPTQ的reorder方法对outlier进行重排并进行了算子融合。

image.png

  1. 对weight和activation中的normal值使用group量化,由于各group scale不一致,所以先分别计算各group的中间结果,再反量化为fp16计算最终结果。为了降低计算开销也使用了融合GEMM技术。

image.png

  1. 为提高精度对激活值进行动态量化,减少计算开销的方式也是采用了前算子融合的技术。
  2. 对KVCache进行低比特非对称量化,在FP16计算前进行反量化。

image.png

OliVe

OliVe: Accelerating Large Language Models via Hardware-friendly Outlier-Victim Pair Quantization(https://arxiv.org/abs/2304.07493)

Type:W4A4

Olive从硬件层面上对离群值的计算进行了优化,之前的离群值感知量化方案采用的基本都是稀疏编码技术,即将离群值与正常值分开存储,其中过程需要全局协调。这将导致复杂的编码和解码硬件逻辑,它不是硬件最优的。OliVe提出了一个硬件友好地处理离群值和正常值的方式,它关键发现是离群值是重要的,而它们旁边的正常值则不太重要,因此可以牺牲这些正常值(称为受害者)以适应离群值,以本地化的方式处理离群值,提高硬件效率

OliVe首先将与离群值相邻的正常值修剪为零。这些被修剪过的正常值被称为受害者,为离群值腾出了空间。然后,我们利用受害者提供的额外空间,将异常值嵌入到低精度矩阵中,如下图所示。

image.png

Olive将这里的encoder和decoder过程做的非常精细,从硬件层面进行了架构设计,一般想要复现论文效果技术门槛很高,但这个算法和硬件架构协同设计的实现方案确实威力巨大,可以看看后续硬件架构的演进路线。

encodder时对(outlier, victim), (outlier,outlier),(normal,normal)pair进行分别处理,设计了victim的identifier, 设计了normal的数据类型(int4,fint4,int8),为outlier设计了专门的数据格式abfloat,关键思想是通过向指数上添加适当的偏差,所有编码值都可以跳过normal所在的区间,为outlier提供更多的范围。

deocder时对TensorCore等硬件特性进行了充分集成,使用Verilog设计了门电路进行解码、设计了针对(outlier,victim) pair的矩阵乘指令,优化层级非常深。

image.png

Outlier Suppression

Outlier Suppression: Pushing the Limit of Low-bit Transformer Language Models(https://arxiv.org/abs/2209.13325)

Outlier Suppression+: Accurate quantization of large language models by equivalent and optimal shifting and scaling(https://arxiv.org/abs/2304.09145)

Code:

https://github.com/wimh966/ou...

https://github.com/ModelTC/Ou...

Type: W8A8

之前的量化算法基本上都是对outlier进行保护处理以保证它对精度的影响,而outlier suppression做法相反,它另辟蹊径地想要抑制outlier对最终精度的影响。论文发现:

1.LayerNorm结构中的尺度参数γ作为一个离群值放大器,它放大了输出中的离群值。

2. 一些覆盖大面积的更激进的离群值可以被安全地剪切,不会降低精度。

于是它提出的优化手段:

  1. Gamma Migration,通过将离群值放大器γ迁移到后续模块中来产生一个更易于量化的模型,有点像smoothquant。
  2. 对outlier进行token-wise的剪切能够有效地找到一个使最终量化损失最小的剪切范围。

而outlier suppression+发现了异常值的一个新特征,即它们在不同通道间保持不对称的形状,这种离群的不对称呈现可能导致Tensor更广泛分布,更难于量化。于是它提出了通道shift+通道scale的操作来改造activation的分布,同时引入了一个统一的迁移模式,将这些操作的影响转移到后面的模块中,以维护等效的浮点运算逻辑,如下图所示。本质上其实和SmoothQuant的方向是一致的,让weight和activation做等效变化从而让它们更易于量化,只是outlier suppression+手段显得更有力一些,在多个模型和评测集上也超过了SmoothQuant的效果。

image.png

linear层和残差连接的等效变换

总结

本文提到的PTQ量化算法分类如下所示:

image.png

从这些研究可以看出LLM PTQ量化方向已经形成了不少共识性的方法和研究方向。

对于权重量化,一个共识是需要区分不同的敏感度来进行差异性量化,而敏感度的度量和处理方式各有千秋。有用激活值来进行度量,有用Hessian矩阵进行度量的,有用近似的Fisher information来度量;而处理方式上有平滑的方式,有混合精度稠密稀疏分解的表示方式,以及围绕混合精度设计不同的硬件友好的表示方式。

对于激活值量化,一个共识需要对离群值做特殊处理,处理的方式有平滑的方式、内存重排的优化方式和混合精度的处理方式,甚至还有裁剪的方式,这些都能在一定程度上降低量化的难度,进而减少离群值对精度的影响。

工程实现上也有了大量的实践,最常用的量化、反量化算子融合和重排算子融合就是其中的代表。

以上方法都能够比较好地解决权重和激活值量化的问题,然而算法应用的广泛度不仅仅取决于算法的效果,易用性和简单性也是不可忽视的重要因素,这里AWQ就是一个比较好的例子,效果不错且应用简单因而得到较为广泛的推广。

随着LLM模型体量的增大相信接下来还会有更多W4A4类型的低比特量化算法出现,同时能够基于硬件进行深度优化,在保持精度的前提下进一步降低推理耗时,让我们拭目以待。

参考

ZeroQuant: Efficient and Affordable Post-Training Quantization for Large-Scale Transformers 

ZeroQuant-V2: Exploring Post-training Quantization in LLMs from Comprehensive Study to Low Rank Compensation

ZeroQuant-FP: A Leap Forward in LLMs Post-Training W4A8 Quantization Using Floating-Point Formats

ZeroQuant-HERO: Hardware-Enhanced Robust Optimized Post-Training Quantization Framework for W8A8 Transformers

GPTQ: ACCURATE POST-TRAINING QUANTIZATION FOR GENERATIVE PRE-TRAINED TRANSFORMERS

LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale

SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models

AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration

SpQR: A Sparse-Quantized Representation for Near-Lossless LLM Weight Compression

OWQ: Outlier-Aware Weight Quantization for Efficient Fine-Tuning and Inference of Large Language Models

SqueezeLLM: Dense-and-Sparse Quantization

RPTQ: Reorder-based Post-training Quantization for Large Language Models

ATOM: LOW-BIT QUANTIZATION FOR EFFICIENT AND ACCURATE LLM SERVING

OliVe: Accelerating Large Language Models via Hardware-friendly Outlier-Victim Pair Quantization

Outlier Suppression: Pushing the Limit of Low-bit Transformer Language Models

Outlier Suppression+: Accurate quantization of large language models by equivalent and optimal shifting and scaling

QServe: W4A8KV4 Quantization and System Co-design for Efficient LLM Serving

A Survey on Model Compression for Large Language Models

风不语:大模型量化与稀疏论文总结

孙培钦:关于大模型推理的量化算法总结

吃果冻不吐果冻皮:大模型量化技术原理-SpQR

LokLok:AWQ vs SpQR: 量化又见量化

aaronxic:【Transformer 101系列】 LLM模型量化世界观(上)

刀刀宁:量化那些事之 QServe

NULL:RPTQ 论文解读

作者:进击的Killua
来源:GiantPandaCV

推荐阅读

欢迎大家点赞留言,更多Arm技术文章动态请关注极术社区嵌入式客栈专栏欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。

推荐阅读
关注数
18676
内容数
1260
嵌入式端AI,包括AI算法在推理框架Tengine,MNN,NCNN,PaddlePaddle及相关芯片上的实现。欢迎加入微信交流群,微信号:aijishu20(备注:嵌入式)
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息