探秘Transformer系列之(34)--- 量化基础
目录
- 探秘Transformer系列之(34)--- 量化基础
- 0x00 概述
- 0x01 背景知识
- 1.1 需求
- 1.2 压缩
- 1.3 如何表示数值
- 1.4 常见数据类型
- 0x02 量化简介
- 2.1 深度神经网络的稀疏性
- 2.1.1 权重稀疏
- 2.1.2 激活稀疏
- 2.1.3 梯度稀疏
- 2.2 量化机制
- 2.2.1 基本操作
- 2.2.2 范围映射
- 量化误差
- 校准
- 均匀量化 & 非均匀量化
- Affine Quantization & Scale Quantization
- MinMax 量化 & 基于截断的量化
- 2.2.3 量化比特
- 2.2.4 分类
- 2.3 量化对象
- 2.3.1 权重(和偏置)
- 2.3.2 激活
- 2.3.3 校准
- 2.3.3 量化粒度
- 逐张量量化
- 逐通道量化 & 逐token量化
- 逐组量化
- 混合精度量化 (Hybrid Quantization)
- 2.3.4 术语
- 2.4 量化工作流程
- 2.4.1 PTQ
- 2.4.2 QAT
- 2.4.3 推荐流程
- 2.5 加速原因
- 2.5.1 访存加速
- 2.5.2 向量化运算加速
- 2.5.3 量化算子优化
- 0xFF 参考
0x00 概述
虽然基于Transformer架构的LLMs已经取得了长足的发展,但由于LLMs的参数变得越来越多,部署基于Transformer的LLMs面临着重大挑战。例如,即使是中等规模的LLMs,如LLaMA13B,也需要大约26GB的内存来加载其所有参数的FP16格式。这样的开销不仅推高了使用成本,而且限制了它们的更广泛应用。
为了应对这些挑战,人们提出了许多针对LLMs的专业压缩方法,包括剪枝、知识传递、量化、紧凑的架构设计以及动态网络等。这些方法有助于减少模型推理过程中的内存和计算成本,以便模型可以在各种资源受限的设备上运行。模型量化(Model Quantization,也叫网络量化)则是模型压缩中的一项重要方法。模型量化过程分为两部分:将模型的单精度参数(一般 FP32-32位浮点参数)转化为低精度参数(一般 INT8-8 位定点参数),以及模型推理过程中的浮点运算转化为定点运算。模型量化技术可以降低模型的存储空间、内存占用和计算资源需求,从而提高模型的推理速度。
注:关于量化,一共有5篇,本文是第一篇。
0x01 背景知识
1.1 需求
在大语言模型的实际运行过程中,资源效率问题主要体现在显存压力和计算效率两个方面。这些问题随着模型规模的扩大和应用场景的复杂化而愈发突出。
- 显存压力:大语言模型在处理长文本时面临着严重的显存压力。这种压力体现在两个方面:
- 模型参数规模的增加。大型语言模型之所以得名,是因为它们包含的参数数量。这些模型通常拥有数十亿个参数,存储这些参数可能相当昂贵。在推理过程中,激活值是输入和权重的乘积,同样可能非常庞大,通常需要配备大量显存的GPU来加速推理过程。
- KV Cache的特性是随着输入序列长度的增加,所需显存呈线性增长。例如,在处理一个32K长度的文本序列时,仅KV Cache就可能占用10-15GB显存,这与模型本身的权重参数需要共享有限的显存空间。这种显存压力直接限制了模型处理超长文本的能力,也影响了系统的整体扩展性。
- 计算效率:显存资源的限制进一步导致了计算效率的下降。具体表现在三个层面:
- 批处理能力受限:由于显存占用,系统难以同时处理多个大批量请求。
- 响应延迟增加:特别是在处理长序列时,模型的推理时间显著延长。
- 系统吞吐量下降:受限于显存容量,服务器能够同时处理的请求数量大幅减少。
另外,不同的应用场景也带来了独特的挑战:
- 边缘计算环境下,需要在有限的计算资源中实现模型的高效运行。
- 移动设备应用要求模型能够适应严格的内存限制。
- 实时交互场景对模型的响应延迟提出了更高要求。
对于模型小型化,人们关注的是模型的平均推理时间和功耗, 平均推理时间可以用latency 或 throughput 来衡量, 而功耗则可以用参考生成token过程中所用到GPU的功耗。这两个指标都与模型参数量紧密相关, 特别是LLMs的参数量巨大, 导致部署消耗GPU量大。
综上所述,在部署过程中如何使得模型变得更小更轻,且保持模型能力尽可能不下降就成了一个重要的研究话题。
1.2 压缩
模型压缩算法可以将一个庞大而复杂的预训练模型转化为一个精简的小模型,减少对硬件的存储、带宽和计算需求,以达到加速模型推理和落地的目的。按照压缩过程对网络结构的破坏程度,有研究人员将模型压缩技术分为“前端压缩”和“后端压缩”两部分:
- 前端压缩,是指不改变原网络结构的压缩技术,主要包括知识蒸馏、轻量级网络(紧凑的模型结构设计)以及滤波器(filter)层面的剪枝(结构化剪枝)等;
- 后端压缩,是指包括低秩近似、未加限制的剪枝(非结构化剪枝/稀疏)、参数量化以及二值网络等,目标在于尽可能减少模型大小,会对原始网络结构造成极大程度的改造。
近年来主流的模型压缩方法包括:数值量化(Data Quantization,也叫模型量化),模型稀疏化(Model sparsification,也叫模型剪枝 Model Pruning),知识蒸馏(Knowledge Distillation), 轻量化网络设计(Lightweight Network Design)和 张量分解(Tensor Decomposition)。
1.3 如何表示数值
让我们首先看看在计算机中如何表示数值。因为神经网络的推理和训练都是计算密集型的。所以,数值的有效表示就显得尤为重要。
在计算机科学中,一个给定的数值通常表示为浮点数(或称为浮点),即带有小数点的正数或负数。这种表达方式利用科学计数法来表达实数。即用一个尾数(Mantissa,尾数,它实际上是有效数字的非正式说法),一个基数(Base),一个指数(Exponent)以及一个表示正负的符号来表达实数。具体参见下图。
定点是另外一种数值的表示,它和浮点的区别在于,将整数(integer)部分和小数(fractional)部分分开的点在哪里。定点保留特定位数整数和小数,而浮点保留特定位数的有效数字(significand)和指数(exponent)。
由上图可知,尾数和指数由“位”或二进制数字表示,不同数据类型的尾数和指数不同,我们用越多的位来表示一个值,它通常就越精确。这些位的一个巧妙特性是,我们可以计算设备存储给定值需要多少内存。由于一字节内存中有8位,我们可以为大多数形式的浮点表示创建一个基本公式。
\[memory = \frac{number\_of\_bits}{8} \times number\_of\_params\]
现在假设我们有一个模型,包含700亿个参数。大多数模型默认使用32位浮点数(通常称为全精度)表示,仅加载模型就需要280GB的内存。
\[64\text{-}bits = \frac{64}{8} \times 70B \approx 560GB \\32\text{-}bits = \frac{32}{8} \times 70B \approx 280GB \\16\text{-}bits = \frac{16}{8} \times 70B \approx 140GB \\\]
模型参数的位数(包括在训练期间)变得非常重要,因为其决定了模型占据的内存大小。但是随着精度的降低,模型的准确性通常也会下降。所以我们希望在保持准确性的同时减少表示数值的位数。
1.4 常见数据类型
我们再来看看常见的数据类型以及使用它们替代32位(称为全精度或FP32)表示的影响。
- 常规精度模型把模型权重数值格式表示为 FP32(32位浮点,单精度)。
- 混合精度(Mixed precision)在模型中同时使用 FP32 和 FP16 的权重数值格式。FP16 减少了一半的内存大小,但有些参数或操作符必须采用 FP32 格式才能保持准确度。
- 低精度模型把模型权重数值格式表示为 FP16(半精度浮点)或者 INT8(8位的定点整数),目前业界正努力追求INT4和INT1的精度,而INT32或FP16的性能改进并不显著,所以INT8的量化是主要的选择。
另外,当我们在特定数据类型(如 INT8)中进行计算时,我们需要另一种数据类型的结构来保存结果,以便处理溢出,这叫做。累加数据类型(accumulation data type),比如INT8的accumulation data type是INT32。累加数据类型指定了相关数据类型值的累加(加法、乘法等)结果的类型。 例如考虑两个 int8 值 A = 127、B = 127,并将 C 定义为 A 和 B 的和:这里的结果 C 远大于 int8 的最大可表示值 127,因此,我们需要一种精度更高的数据类型,以避免巨大的精度损失。比如bfloat16的累加数据类型就是float32。
下图给出了不同数据类型对应的累加数据类型、数学操作和带宽优化率。
0x02 量化简介
量化的核心思想是:在可接受的精度损失范围内,用更紧凑的数据格式来表示原始数据。
量化概念源自数字信号处理领域,指将信号的连续取值(或者大量可能的离散取值)近似为有限多个(或者较少的)离散值的过程。神经科学中与神经网络量化的研究表明,以连续形式存储的信息将不可避免地受到噪声的破坏,而且离散表示具有更高的泛化能力,以及在有限资源下具有更高的效率。所以人们普遍认为,人脑是以离散/量化形式存储信息,而不是以连续形式存储信息。
在机器学习中,模型量化是指将神经网络的浮点算法转换为低精度的整数以节省计算开销,比如使用 8 位整数(int8)等低精度数据类型来表示权重和激活度,而不是通常的 32 位浮点。减少比特数意味着生成的模型尺寸会减少、进而在推理时所需的内存存储更少,能耗更低。而且矩阵乘法等运算可以用整数算术更快地完成。因此,量化是一种降低推理计算和内存成本的有效技术。
神经网络模型可以量化有几点关键因素:
- 首先,神经网络的推理和训练都是计算密集型的。因此,数值的有效表示就显得尤为重要。
- 其次,大多数当前的神经网络模型都严重过度参数化,因此有足够的机会在不影响精度的情况下降低比特精度。
- 再次,神经网络对激进量化和极端离散化非常鲁棒。在量化模型与原始非量化模型之间具有较高的误差/距离的同时,仍然可以获得非常好的泛化性能。
- 最后,神经网络模型的分层结构提供了一个额外的维度来探索。神经网络中不同的层对损失函数有不同的影响,这激发了混合精度量化方法。
2.1 深度神经网络的稀疏性
根据深度学习模型中可以被稀疏化的对象,深度神经网络中的稀疏性主要包括权重稀疏,激活稀疏和梯度稀疏。
2.1.1 权重稀疏
在大多数神经网络中,通过对网络层(卷积层或者全连接层)对权重数值进行直方图统计,可以发现,权重数值分布很像正态分布(或者是多正态分布的混合),且越接近于 0,权重越多,这就是权重稀疏现象。有研究人员认为,权重数值的绝对值大小可以看做重要性的一种度量,权重数值越大对模型输出贡献也越大,反正则不重要,删去后对模型精度的影响应该也比较小。
2.1.2 激活稀疏
激活函数会造成激活的稀疏性。我们以ReLU 激活函数为例,其定义为:\(ReLU(x)=max(0,x)\) ,该函数使得负半轴的输入都产生 0 值的输出,这可以认为激活函数给网络带了另一种类型的稀疏性。即无论网络接收到什么输入,大型网络中很大一部分神经元的输出大多为零。
2.1.3 梯度稀疏
大多数深度神经网络模型参数的梯度其实也是高度稀疏的,论文“DEEP GRADIENT COMPRESSION: REDUCING THE COMMUNICATION BANDWIDTH FOR DISTRIBUTED TRAINING”发现,在分布式 SGD 算法中,99.9% 的梯度交换都是冗余的。
2.2 量化机制
我们接下来介绍一些量化相关知识点。
量化原理如下图所示。量化的主要目标是在尽可能保持原始参数的精度的同时,减少表示原始参数所需的位数。具体如下图所示,[-R, R] 是量化前的数据范围,[-127, 127] 是量化后的数据范围。这样就把模型权重等参数的精度从高位宽连续取值(通常为float32或者大量可能的离散值)降低到有限多个低位宽离散值(通常为int8)的过程。
下图给出了量化公式。其中 X 是浮点张量,X¯是量化后的整数张量,Δ 是缩放系数,⌊⋅⌉ 表示四舍五入函数,N 为量化位数(此处为 8 位)。这里假设张量围绕 0 对称。该量化方法基于浮点数绝对值最大值来计算缩放系数 Δ,这会保留激活中的异常值,而这些异常值对模型的准确性至关重要。我们可以基于部分校准样本集的激活值离线计算缩放系数 Δ,这称为静态量化;也可以在模型运行时根据激活统计数据来动态计算缩放系数,这称为动态量化。
2.2.1 基本操作
量化有两个基本操作:
- 量化(quantization):将数据转换为较低精度,比如将一个实数转换为一个量化的整数(float32 变成int8)。
- 反量化( de-quantization):将数据转换为较高精度。比如将一个数从一个量化的整数表示形式转换为一个实数(int8变成float32)。
具体如下图所示。我们会在接下来进行细致分析。
也可以进一步细化。下面(1)式是量化,(2)式是反量化。Q(·)表示量化操作,X代表输入tensor,S即为scale,Z即为zero-point,b为量化比特,round(⋅)和clip(⋅)分别表示取整和截断操作,\(q_{min}\)和\(q_{max}\)是量化后的最小值和最大值。S和Z统称为量化参数。多数的量化算法可以理解为就是为了找到更好的S和Z,使得量化模型的结果尽可能逼近原模型的结果.。
\[Q(X) = clamp(\lfloor\frac{X}{S}\rceil + Z, 0, 2^b -1)\tag {1}\\\]
\[\hat X = (Q(X) - Z) \times S \tag{2}\]
假设r表示量化前的浮点数,量化后的整数q可以表示为:
\[q = clip(round(\frac{r}{s} + z), q_{min},q_{max})\]
2.2.2 范围映射
量化过程的核心就是找到一个合适的映射关系,将浮点数映射到整数空间。这个映射需要保证:
- 能够覆盖原始数据的完整范围。
- 尽可能保持数值的相对关系。
- 保证量化后的数值都落在某个表示范围内,比如INT8是0-255。
在范围映射中,必须将范围[A1, A2]的数据转换为B位整数的范围。具体而言,是将范围[A1, A2]中的所有元素映射到目标范围中,超出[A1, A2]范围的元素将被剪切到最接近的边界。比如,我们需要将FP32映射到int8范围内,int8 只能表示 256 个值,而 float32 可以表示的值范围更广。而一般神经网络层权重的值分布范围很窄,但是在这值域中数值点数量却很大。所以需要仔细调整范围映射,才能更好地将float32值范围 [a, b] 投射到 int8 空间。
量化误差
大部分模型量化的使用者或者研究者,更关注的是量化模型的精度问题。模型量化将更高数值精度的浮点模型转换为少数的离散定点,不可避免会引入误差。而在神经网络模型中,每一层的量化误差传递放大,就会导致量化模型精度过低。一般定义量化操作为: \(\hat{X} = Round( clamp(\frac{X}{s}, Q_{min}, Q_{max}) )\),其中 Round 表示舍入操作,clamp 截断超过量化域范围 \(\left [ Q_{min}, Q_{max} \right ]\) 的异常值。Round 和 Clamp 操作都会导致数值精度的不可逆损失,简单来说,一个tensor 的量化误差可以表示为截断误差和舍入误差之和。而这两者又是相关联的,s 表示缩放因子,定义为 \(s = \frac{X_{max} - X_{min} }{2^{bit}-1 }\) ,也就是说它是通过截断的上下界来决定。综合两者可以得到一个经验公式 \(\sigma ^{2} ~ \frac{s^{2} }{12}\),即量化误差正比于 \(s^{2}\) 。
校准
为了计算 scale 和 zero_point,我们需要知道 FP32 weight/activation 的实际动态范围。校准就是选择一个最优范围的过程,即找到一个能包含尽可能多的值,同时又能最小化量化误差的范围。校准对有效的量化至关重要。对于推理过程来说,weight 是一个常量张量,动态范围是固定的,activation 的动态范围是变化的,它的实际动态范围必须经过采样获取(数据校准)。如果量化过程中的每一个 FP32 数值都在这个实际动态范围内,我们一般称这种为不饱和状态;反之如果出现某些 FP32 数值不在这个实际动态范围之内我们称之为饱和状态。
均匀量化 & 非均匀量化
从范围映射角度来看,根据量化数据表示的原始数据范围是否均匀,可以将量化方法分为均匀量化&非均匀量化。实际的深度神经网络的权重和激活值通常是不均匀的,因此理论上使用非线性量化导致的精度损失更小,但在实际推理中,非线性量化的计算复杂度较高,所以我们通常使用线性量化。
- 非均匀量化(也称为非线性量化)。非均匀量化定义如下图所示,当实数 r 的值落在量化步长 \(\Delta_i\) 和\(\Delta_{i+1}\) 之间时,量化器Q将其投影到相应的量化级别\(X_i\),\(X_i\)和\(\Delta_i\)的间距都是不均匀的。对于固定位宽,非均匀量化可以实现更高的精度,因为可以通过更多地关注重要值区域或找到适当的动态范围来更好地捕获分布。例如,许多非均匀量化方法是针对权重和激活的钟形分布而设计的,这些分布通常涉及长尾。典型的基于规则的非均匀量化是使用对数分布,其中量化步长和级别呈指数增长而不是线性增长。
- 均匀量化(也称为线性量化)。线性量化采用均匀分布的聚类中心,原始浮点数据和量化后的整数存在一个简单的线性变换关系。因为卷积、全连接等网络层本身只是简单的线性计算,因此线性量化中可以直接用量化后的数据进行直接计算。均匀量化将实数值范围划分为均匀的有限区间,然后,同一区间内的实数值被映射到相同的整数。其实,均匀量化得到的量化值(又称量化级别)也是均匀的。
下图给出了均匀量化(左)和非均匀量化(右)之间的比较。连续域 r 中的实数值被映射到量化域Q中的离散、较低精度值,这些值用橙色点来标记。请注意,在均匀量化中,量化值(量化级别)之间的距离是相同的,而在非均匀量化中它们可以变化。
神经网络的权重通常不是均匀分布的,因此非均匀量化是可行的。一般来说,非均匀量化使我们能够通过非均匀地分配比特和离散化参数范围来更好地捕获信号信息,可以提供更高的精度和更低的量化误差。然而,非均匀量化方案可能会因为涉及耗时的查找操作而效率低下,通常难以在通用计算硬件(例如 GPU 和 CPU)上有效部署。因此,均匀量化由于其简单性和到硬件的高效映射而成为目前事实上的标准方法。
Affine Quantization & Scale Quantization
均分量化即Uniform quantization分两步:
- 选择要量化的数值(浮点)的范围并截断,截断的意义是:大于数值范围的就让其为数值范围的最大值,小于数值范围的就变成数值范围的最小值。
- 将截断后的数值映射到整数上,这一步有round的操作。
设\([\beta,\alpha]\)是为量化选择的可表示实值的范围,b是带符号整数表示的位宽(bit-width)。均匀量化将输入值\(x\in[\beta,\alpha]\)变换到\([-2^{b-1}, 2^{b-1}-1]\)内,其中范围外的输入被截断到最近的边界。
由于我们只考虑均匀变换,因此根据量化前后浮点空间中的零的量化值是否依然是 0,可以将浮点数的线性量化分为两类:对称量化 Symmetric Quantization 和非对称量化 Asymmetric Quantization。我们将这两种选择分别称为scale和affine。对应变换函数也是两种选择:f(x) = s · x + z及其特例 f(x) = s · x。
<ul>Scale Quantization:变换函数是 f(x) = s · x, 即对称量化,s 是缩放因子。Scale Quantization的特点如下:<ul>
对称量化就是将一个张量中的 [−
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |