写点什么

模型量化与量化在 LLM 中的应用 | 得物技术

作者:得物技术
  • 2024-04-30
    上海
  • 本文字数:5537 字

    阅读完需:约 18 分钟

模型量化与量化在LLM中的应用 | 得物技术

一、模型推理优化

随着模型在各种场景中的落地实践,模型的推理加速早已成为 AI 工程化的重要内容。而近年基于 Transformer 架构的大模型继而成为主流,在各项任务中取得 SoTA 成绩,它们在训练和推理中的昂贵成本使得其在合理的成本下的部署实践显得愈加重要。

大模型推理所面临的挑战主要有以下两点:

  • 巨大的内存(显存)需求,主要来自于模型本身参数和推理的即时需求。对于一个 LLaMA2-30B 的模型,载入显存其模型本身需要约 60GiB 的显存,推理过程中,单个 token 的 KV cache 需要 1.6MiB 左右的显存:6656(layer dim) * 52(layer num) *2 (K & V) * 2(fp16, 2bytes);对于一个 2048 个 token 的请求则需要 3.3GiB 的显存。

  • 并行性较差,因为生成过程通常在时序上是一个串行的过程,导致 decoding 的过程较难并行,成为计算的瓶颈。

常见的推理优化方式有知识蒸馏(Knowledge Distillation,KD),剪枝(Pruning)和量化(Quantization),以及针对 LLM 的内存优化而提出的各种方案(如 Flash Attention、Paged Attention 等)。

蒸馏指通过直接构造小模型,作为学生模型,通过软标签与原标签结合的方式监督学习原模型的知识,从而使小模型具备与原模型相当的性能,最终用小模型代替大模型从而提高推理效率。


【图片出处:Knowledge Distillation: A survey,2021,p2】

剪枝则是通过靠剪除模型中不重要的权重从而给模型“瘦身”,提高模型的推理效率,为了保证模型的能力,通常剪枝过程也需要伴随着模型基于训练数据的微调。根据剪除权重的维度不同,可以分为结构化剪枝(structured pruning)和非结构化剪枝(unstructured pruning)。

  • 结构化剪枝:通常按权重张量的某一或多个维度成块剪除不重要的通道,并保持正常的矩阵乘法;但因剪除的通道影响上下层的推理,需要检查网络的逻辑准确性。

  • 非结构化剪枝:随机剪除权重张量中的不重要的元素,因而它通常会保持原本的权重结构,而造成稀疏的乘法计算,但并不能适配于通用的硬件,因而需要专用的硬件才能实现加速。

目前剪枝在 LLM 中的应用较少,如以下基于 Activation-aware 的剪枝工作[1],主要是基于权重本身的的绝对值大小和输入张量的绝对值大小做非结构化剪枝,使权重张量本身稀疏化,而模型的精度损失也并不能达到工程化的要求。


【图片出处:A simple and effective pruning approach for large language models,2021,p2】

再如下图最近结构化剪枝的工作[2],通过搜索的方法寻找模型中的子结构,并通过重训练以保持模型精度,剪枝后的模型的精度相比原模型有很大的降低,只能跟同等参数量(剪枝后)的其他较小模型比较以显示其方法的意义。


【图片出处: Sheared LLaMA: accelerating language model pre-training via structured pruning,2023,p3】


【图片出处: huggingface/Sheared-llama-1.3B】

而量化之所以会成为神经网络以及 LLM 的首选,主要有以下的优点:

  • 降低显存的直观体现。一般 LLM 权重用 FP16 存储,而权重量化为 int4 之后,则直观上体积减小为原本的 1/4(实际可能由于 embeddings 不量化,内存分配等一些原因会稍多一些),对显存的资源需求大大降低。

  • W4A16、W8A16 等算子的加速,从而提升计算速度。

二、量化简介

base

量化的本质通常是将模型的参数,或整个模型的推理过程从浮点转化为整型。

量化参数通常由 scale 和 zero-point 两个值构成,前者为浮点,后者为整型。设 x 为一个张量(它可以为权重,也可以是推理的中间变量),其量化过程可以表示如下,


用 b 表示量化位宽,q{min}与 q{max}分别表示整型值域的范围,例如 int-8 量化可以取[-128,127],即 q{min}=-2^(b-1)=-128,q{max}=2^(b-1)-1=127,clamp(a;q{min},q{max})表示输入值 a 基于[q{min}, q{max}]范围的截断操作,x{int}表示量化后的结果,s 和 z 表示量化参数 scale 和 zero-point。



【图片出处:A Survey of Quantization Methods for Efficient Neural Network Inference,2021,p5;An Introduction to Quantization of Large Language Models,p12】

而从整型到浮点的反量化过程如下,


关于量化参数,有很多算法基于搜索,最优化,LKD(layer-by-layer 蒸馏)等各类算法计算其较优解,从而尽可能减少量化引起的精度损失;而最直接的计算 scale 和方法即是基于张量元素 min/max。


以下是一段简单的代码表示张量 x 从 fp32 量化到 int8 整型,再反量化回 fp32 的示例:

x->x{int}->x_hat 的过程的一个示例如下:


量化前 x:


量化后 x_hat:


对称/非对称

相比于非对称量化,对称量化的定义是量化所映射的整型值域基于 0 值对称,即上述公式的 zero-point 为 0,qmax = -qmin,从而使量化的表达形式更为简化。

非对称量化有利于充分利用量化范围。例如 Conv+ReLU 输出的激励张量,其值皆为正值,若使用对称量化,则浮点将全部映射到[0~127]范围,有一半的范围未使用,其量化精度不如非对称量化。


【图片出处:A Survey of Quantization Methods for Efficient Neural Network Inference,2021,p5】

实际中往往选择对权重张量做对称量化,而对输入张量做非对称量化。以下是来自 qualcomm 的量化白皮书中的分析,如权重和输入都选择非对称量化时,以 Linear 层的矩阵乘法为例,将表达式展开如下:


  • 第一项是整型张量的乘法操作,是必须的即时操作;

  • 第三、四项的操作包含了 scale,zero 和整型权重的乘法,这些都是提前预知的,因而可以事先计算作为偏置加上;

  • 第二项的计算依赖 x{int},是每次推理需要即时计算的,而这会造成额外算力。

因而当我们将权重量化改为对称量化时(zW=0),则上式简化为如下,即时计算时,只需要计算第一项的矩阵乘法,第二项是预先算好的偏置项:


而当两者都是对称量化时的表达式,则简化如下:


对比原模型中的浮点计算 W{x},W{int}x{int}是整型与整型之间的乘法,后者在 Nvidia GPU 上的运算速度远快于前者,这是量化模型的推理速度大大加快的原因。

三、LLM 的量化

Challenges in LLM Quantization

从模型表现的角度来讲,量化自始至终要解决的一个前提是,如何保持量化后模型的精度,即让模型的使用者觉得量化后的模型在推理效率提高的同时,还能保持原来的性能。

神经网络中需要量化的操作主要是卷积层 Conv(x;W)和全连接层 Wx,即主要是按上一部分描述的操作分别对 W 和 x 做的权重量化(Weight Quantization,WQ)和激励量化(Activation Quantization,AQ)。

而不同于 CNN 模型或者小型 Transformer 模型,基于 Transformer 的大模型的矩阵乘法产生的激励张量通常有较多的离群值(outliers),即离值分布的大多数点形成的点群较远的值, 这些绝对值较大但占比较低的元素值增加了量化难度。而如何取舍 outliers 通常是量化工作中的一大难点,若过分考虑之,则会因量化范围过大而降低量化的表达范围,若过分截断之,通常会因这些绝对值较大的值,在模型推理中对结果有较大影响,而导致模型效果变差,而后者在 LLM 的量化则尤为明显。

下图分别是 Resnet18 与 Opt-13B 的某层输入张量的元素值统计,sigma 表示各自分布的标准差,Resnet18 输入的极大值约为 28sigma,且绝对值 6sigma 以外的比例在 0.05%;而 Opt-13B 网络输入的极大值越为 325sigma,且绝对值 6sigma 以外的比例在 0.2%。从量化效果而言,Resnet18 的 int-8 精度基本无损失,而 Opt-13B 的 int-8 模型的精度已崩塌。


【图片出处:An Introduction to Quantization of Large Language Models,p20 】

在应对激励量化的挑战这方面,有一些方案尝试降低量化精度,比如 SmoothQuant 提出的思路。



【图片出处:SmoothQuant,p4】

在矩阵乘法中,他们通过按比例缩小输入张量 X 的值,而将缩小的比例补偿给权重张量 W,即把问题从量化 X 和 W 转化为了量化 X·diag(s^(-1))和 diag(s)·W。从而在保证乘法运算的积保持不变的前提下,降低张量 X 的量化难度。而在实际工程中,这种量化方案引起的量化误差对大模型的推理效果仍然有比较明显的影响,即使在 int-8 精度量化亦有明显的误差。如以下对 Llama2-7B 的 SmoothQuant 应用结果显示其 perplexity 非常糟糕,难以在实际中应用。


所以在目前工程部署中的实用方案,大多以 weight-only 的量化方案为主,即放弃 activation 的量化。

GPTQ

GPTQ 是最早被工程化部署所接受的量化方案,W8A16 或 W4A16 的量化效果在多数场景中都有与原模型较为接近的表现,而且其量化过程非常快。

量化过程

以矩阵乘法的基本单元操作为例,基于 weight-only 量化前后的乘积的均方差,可以写出如下优化函数,


W 是在 Transformer 中的 Linear 层权重,X 表示其对应的输入。离线量化的过程是逐模块(Transformer)逐层(Q,K,V,O,Fc1,Fc2)做量化。

参数和数据定义如下:

  • W∈R^{K×M},X∈R^{M×N},Y=W×X∈R^{K ×N}

  • calibrate set:部分数据用作推理,用于查看各层输入张量的值范围,并基于此量化。

具体量化过程如下:

  • 计算 Hessian(上述优化函数对于 W_hat 的 Hessian,而非反向传播中的 Hessian),加入扰动项:


  • act order sort(desc_act,值范围相近的 column 一起做量化),基于 diag(H)对 W 基于 M 维度作列重排,同理,对应地 H 在两个维度上重排。

  • 求逆 H^(-1)(cholesky 分解)。

  • 对 W 沿维度 M,从左到右逐块量化,block size B=128,其右侧还未量化部分基于 H^(-1)更新,以补偿量化损失。


  • (inner loop)针对每个 block 内部,逐列量化,计算误差,并对该 block 内部未量化的列,基于误差更新。



  • (outer loop)操作完该 block,更新其后面的所有列:


group_size

  • 若不指定 group size,默认 g=-1,以所有列为单位统计量化参数,并对每一行的权重做量化,对于 W∈R^{K×M},量化参数的数量为 K×1。


  • 若指定 group size,例如 g=128,则会以每 128 列为单位统计量化参数,并对每一行的权重做量化,对于 W∈R^{K×M},量化参数的数量为 K×(M/g)。


重排 desc_act

根据 Hessian Matrix H,基于 diag(H)对 W 基于 M 维度作列重排。其目的是优先量化绝对值较大的 activaiton 对应的 weight 的列,这些列在推理中被视为更为影响结果的重要的列,因而希望在量化这些列时尽可能产生较小的误差,而将更多的量化误差转移到后面相对不重要的列中。

部分实验表明 desc_act 对量化损失的效果在多数的任务中是有效的 trick。


Perplexity of Pygmalion-7B with GPTQ [7]

【图片出处:https://huggingface.co/reeducator/vicuna-13b-free/discussions/22

算子

严格来说基于 weight-only 的 W4A16 相比于原本的 W16A16 并没有太多效率的提升,而且推理中还加入了 quant/dequant 过程;而随着 weight-only 成为 LLM 量化的主流且应用越来越多,有很多开源的工作基于 W4A16 高效算子的编写为量化算法的推理提速赋能,比如 GPTQ 的 python package AutoGPTQ 已集成于开源工具 exllama,后者基于 triton 和 CUDA 重写了量化乘法的并行计算。在 exllama/exllama_ext/matrix.cuh 可以看到 dot_product8_h 对 out=W_hat·x=(W{int}-z)s·x=(W{int}-z)x·s 的实现。


【图片出处:https://github.com/turboderp/exllama/blob/3b013cd53c7d413cf99ca04c7c28dd5c95117c0d/exllama_ext/matrix.cuh#L86

AWQ

相比于 GPTQ 从最优化问题出发设计方案,AWQ 是基于搜索提出的量化方案。

用 Q(·)表示量化反量化过程,则修改前的量化过程如下:


修改后,量化过程如下,加入了对 W 的缩放:


搜索

AWQ 的全称为 Activation-aware Weight Quantization, 即对 Weight 的量化过程考虑 Activation 的值的影响。其出发点也是基于在 Weight 的各个通道中,处理对应的 Activtion 的值较大的通道则相对重要,反之则相对不重要,进而通过乘以一个缩放系数Δ去体现其重要性,而Δ的值和范围则通过输入的 activation 的张量值设计。


搜索的衡量标准依据 Linear 层量化前后输出结果的比较,取 MSE 结果最小者为最优解。


效果

从模型表现效果方面,通过逐层 scale search 寻找最优的缩放系数,从而取量化误差最小的解,以下来自 AWQ paper 的效果比较,从 Perplexity 的角度,显示在两代 Llama 的测试上其量化结果稍优于 GPTQ 及 GPTQ 的排序版。


【图片出处:AWQ, p6】

从实际任务的准确率来看,AWQ 的准确率与 GPTQ 的 act_order 版本(GPTQ-R)相当,而速度优于后者。


【图片出处:AWQ, p5】

从模型的计算性能方面,GPTQ 因为有 reorder 操作,矩阵乘法是 MV(matrix×vector),为不连续的内存访问,而 AWQ 不存在 reorder 操作,矩阵乘法为(matrix×matrix),速度更快。

四、总结

关于 LLM 的量化工作目前的 SOTA performance,基本上都是基于 weight-only 的量化模式,模型在 GPU 运行所需的显存降低是其主要的贡献。

从模型的表现来看,因为存在不可避免的量化损失,且 LLM 模型通常比传统的 CNN 模型对量化要敏感得多,虽然在很多任务上量化后的 LLM 表现与量化前差距不大,但是在一部分任务上可能依然无法胜任。

从模型的加速来看,weight-only 的量化促使底层加速的工作基本上都在 W4A16、W3A16、W8A16 等乘法算子上的加速,从 paper 上提供的理论数据上来看通常相较于 FP16 模型只有 1.x ~3.x 倍速度的提升,而实际部署效果可能低于此数值,其加速效果远不如传统量化方法的 W4A4、W8A8 等全整型的乘法算子。

总体来说,LLM 领域的量化工作还很初步,若在实际任务中对模型的表现精度要求十分高,更推荐单纯基于 KV cache 等方向提高单位显存吞吐量的算法和工具,如 Flash Attention-2、Paged Attention 等。

五、Reference

1. A Simple and Effective Pruning Approach for Large Language Models, 2023.

2. Sheared LLaMA: Accelerating Language Model Pre-training via Structured Pruning, 2023.

3. A White Paper on Neural Network Quantization, 2021.

4. SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models, 2023.

5. GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers, 2023.

6. AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration, 2023.

7. Some evaluation on GPTQ performance.


*文/xujiong


本文属得物技术原创,更多精彩文章请看:得物技术官网


未经得物技术许可严禁转载,否则依法追究法律责任!

发布于: 2024-04-30阅读数: 26
用户头像

得物技术

关注

得物APP技术部 2019-11-13 加入

关注微信公众号「得物技术」

评论

发布
暂无评论
模型量化与量化在LLM中的应用 | 得物技术_算法_得物技术_InfoQ写作社区