文章标题:SmoothQuant: 面向大型语言模型的准确高效的训练后量化方法
作者/机构:Guangxuan Xiao, Ji Lin, Mickael Seznec, Hao Wu, Julien Demouth, Song Han


A1 主要贡献

本文旨在解决大型语言模型(LLM)因模型规模巨大而带来的计算和内存密集问题。现有量化方法在保持准确性和硬件效率方面难以兼顾:例如,ZeroQuant在处理超过一定规模(如OPT-175B)的模型时精度下降,而LLM.int8()虽然能保持精度,但其混合精度分解方案难以在硬件上高效实现。

为解决这一挑战,本文提出了SmoothQuant,一个无需训练、保持精度且通用的训练后量化(PTQ)解决方案,旨在为LLM启用8位权重和8位激活(W8A8)量化。其核心贡献基于一个关键观察:权重易于量化,而激活因存在异常值而难以量化。SmoothQuant通过一个数学上等价的变换,在离线阶段将量化难度从激活迁移到权重,从而“平滑”激活中的异常值。这一方法使得LLM中所有的矩阵乘法(包括线性层和注意力机制中的BMM)都能进行INT8量化。该方案成功应用于OPT、BLOOM、GLM、MT-NLG、Llama-1/2、Falcon、Mistral和Mixtral等多种模型,实现了高达1.56倍的加速和2倍的内存减少,同时精度损失可忽略不计。值得注意的是,SmoothQuant使得在单个节点内部署530B参数的LLM成为可能,为降低硬件成本和普及LLM提供了一个交钥匙解决方案。

A3 背景知识/关键Observation/设计原则

量化背景

整数均匀量化。本文研究整数均匀量化,特别是INT8,因为它能获得更好的硬件支持和效率。量化过程可表示为:


其中,$X$是浮点张量,$\bar{X}$是量化后的张量,$\Delta$是量化步长,$\lceil\cdot\rfloor$是取整函数,$N$是位数(本文为8)。为简化讨论,这里假设张量关于0对称。该量化器使用最大绝对值来计算$\Delta$,以保留激活中的异常值,这被发现对模型准确性至关重要【索引7,LLM.int8(): 8-bit matrix multiplication for transformers at scale,2022,arXiv】。$\Delta$可以通过校准样本的激活进行离线计算(静态量化),也可以利用激活的运行时统计数据动态获取(动态量化)。

量化粒度。如图3所示,量化有不同的粒度级别。
- 逐张量(Per-tensor)量化:为整个矩阵使用单一的步长。
- 逐令牌(Per-token)量化:为与每个令牌关联的激活使用不同的量化步长。
- 逐通道(Per-channel)量化:为权重的每个输出通道使用不同的量化步长。
- 分组(Group-wise)量化:一种更粗粒度的逐通道量化,为不同的通道组使用不同的量化步长【索引32, Q-bert: Hessian based ultra low precision quantization of bert, 2020, AAAI; 索引46, Zeroquant: Efficient and affordable post-training quantization for large-scale transformers, 2022, arXiv】。

硬件友好的量化。对于Transformer中的线性层 $Y = X \cdot W$(其中$Y \in \mathbb{R}^{T \times C_o}$, $X \in \mathbb{R}^{T \times C_i}$, $W \in \mathbb{R}^{C_i \times C_o}$),为了利用高效的整数计算核心(如INT8 GEMM),需要同时对权重和激活进行INT8量化(即W8A8)。为了高效利用INT8 GEMM核心,缩放因子只能来自外维度(即激活的令牌维度$T$和权重的输出通道维度$C_o$),而不能来自内维度(即输入通道维度$C_i$)。

图3:逐张量、逐令牌和逐通道量化的定义。逐张量量化实现效率最高。对于向量级量化,为了高效利用INT8 GEMM核心,我们只能使用来自外维度(即令牌维度T和输出通道维度Co)的缩放因子,而不能使用内维度(即输入通道维度Ci)的缩放因子。
图3:逐张量、逐令牌和逐通道量化的定义。逐张量量化实现效率最高。对于向量级量化,为了高效利用INT8 GEMM核心,我们只能使用来自外维度(即令牌维度T和输出通道维度Co)的缩放因子,而不能使用内维度(即输入通道维度Ci)的缩放因子。

LLM量化难点回顾

激活中的异常值是主要挑战。由于激活中存在异常值,LLM的量化非常困难【索引7,LLM.int8(): 8-bit matrix multiplication for transformers at scale,2022,arXiv; 索引42,Outlier suppression: Pushing the limit of low-bit transformer language models, 2022, arXiv; 索引3,Understanding and overcoming the challenges of efficient transformer quantization, 2021, EMNLP】。通过可视化一个量化误差较大的线性层的输入激活和权重(图4左侧),可以发现以下规律,这些规律启发了本文的方法:
1. 激活比权重更难量化。权重的分布相当均匀平坦,易于量化。先前的工作表明,使用INT8甚至INT4量化LLM的权重不会降低准确性【索引7,LLM.int8(): 8-bit matrix multiplication for transformers at scale,2022,arXiv; 索引46,Zeroquant: Efficient and affordable post-training quantization for large-scale transformers, 2022, arXiv; 索引48,Glm-130b: An open bilingual pre-trained model, 2022, arXiv】,这与我们的观察相符。
2. 异常值使激活量化变得困难。激活中异常值的规模比大多数激活值大约100倍。在逐张量量化中,巨大的异常值主导了最大幅值的测量,导致非异常值通道的有效量化比特/级别很低(图2)。假设通道$i$的最大幅值为$m_i$,整个矩阵的最大值为$m$,则通道$i$的有效量化级别为$2^8 \cdot m_i/m$。对于非异常值通道,这个值会非常小(2-3级),从而导致巨大的量化误差。
3. 异常值固定出现在特定通道。异常值出现在一小部分通道中。如果某个通道出现异常值,它会在所有令牌中持续出现(图4,红色部分)。对于给定的令牌,通道间的方差很大(某些通道的激活值非常大,而大多数很小),但对于给定的通道,跨令牌的幅值方差很小(异常值通道始终很大)。由于异常值的持续性和每个通道内部的小方差,如果可以对激活进行逐通道量化【索引3,Understanding and overcoming the challenges of efficient transformer quantization, 2021, EMNLP】(即为每个通道使用不同的量化步长),量化误差将远小于逐张量量化,而逐令牌量化对此帮助不大。表1验证了这一假设,即模拟的逐通道激活量化成功地将准确性恢复到FP16基线水平。

硬件限制。然而,逐通道激活量化无法很好地映射到硬件加速的GEMM核心上。这些核心依赖于高吞吐量执行的一系列操作(如Tensor Core MMA),并且不能容忍在该序列中插入低吞吐量的指令(如转换或CUDA Core FMA)。在这些核心中,缩放只能沿着矩阵乘法的外维度进行(即激活的令牌维度$T$,权重的输出通道维度$C_o$,见图3),这可以在矩阵乘法完成后应用:


因此,先前的工作都对线性层使用逐令牌激活量化【索引7,LLM.int8(): 8-bit matrix multiplication for transformers at scale,2022,arXiv; 索引46,Zeroquant: Efficient and affordable post-training quantization for large-scale transformers, 2022, arXiv】,尽管这并不能解决激活量化的困难(仅比逐张量稍好)。

表1:在不同的激活量化方案中,只有逐通道量化【索引3,Understanding and overcoming the challenges of efficient transformer quantization, 2021, EMNLP】能保持准确性,但它与INT8 GEMM核心不兼容(灰色标记)。我们报告了在WinoGrande、HellaSwag、PIQA和LAMBADA上的平均准确率。
表1:在不同的激活量化方案中,只有逐通道量化【索引3,Understanding and overcoming the challenges of efficient transformer quantization, 2021, EMNLP】能保持准确性,但它与INT8 GEMM核心不兼容(灰色标记)。我们报告了在WinoGrande、HellaSwag、PIQA和LAMBADA上的平均准确率。

A2 方法细节

SmoothQuant核心思想

通过数学等价变换平滑激活。我们不采用不可行的逐通道激活量化,而是提出通过除以一个逐通道平滑因子 $s \in \mathbb{R}^{C_i}$ 来“平滑”输入激活。为了保持线性层的数学等价性,我们相应地对权重进行反向缩放:


考虑到输入$X$通常由先前的线性操作(如线性层、层归一化等)产生,我们可以很容易地将平滑因子离线地融合到前一层的参数中,这不会因额外的缩放操作而产生核函数调用开销。在其他情况下,当输入来自残差加法时,我们可以像Wei等人【索引42,Outlier suppression: Pushing the limit of low-bit transformer language models, 2022, arXiv】一样,为残差分支添加一个额外的缩放操作。

图4:OPT-13B中一个线性层的输入激活和权重的幅值,在SmoothQuant之前和之后。观察:(1) 原始激活图中有少数通道的幅值非常大(大于70);(2) 一个激活通道内的方差很小;(3) 原始权重分布平坦且均匀。SmoothQuant将异常通道从激活迁移到权重。最终,激活中的异常值被大大平滑,而权重仍然相当平滑和均匀。
图4:OPT-13B中一个线性层的输入激活和权重的幅值,在SmoothQuant之前和之后。观察:(1) 原始激活图中有少数通道的幅值非常大(大于70);(2) 一个激活通道内的方差很小;(3) 原始权重分布平坦且均匀。SmoothQuant将异常通道从激活迁移到权重。最终,激活中的异常值被大大平滑,而权重仍然相当平滑和均匀。

将量化难度从激活迁移到权重。我们的目标是选择一个逐通道平滑因子$s$,使得 $\hat{X} = X\text{diag}(s)^{-1}$ 易于量化。为了减少量化误差,我们应增加所有通道的有效量化比特数。当所有通道具有相同的最大幅值时,总有效量化比特数将最大。因此,一个直接的选择是 $s_j = \max(|X_j|)$, $j = 1, 2, ..., C_i$,其中$j$对应第$j$个输入通道。这个选择确保了在除法之后,所有激活通道将具有相同的最大值,从而易于量化。需要注意的是,激活的范围是动态的,它随不同的输入样本而变化。在这里,我们使用来自预训练数据集的校准样本来估计激活通道的尺度【索引14,Quantization and training of neural networks for efficient integerarithmetic-only inference, 2018, CVPR】。然而,这个公式将所有的量化难度都推给了权重。我们发现,在这种情况下,权重的量化误差会很大(异常值通道被迁移到了权重),导致严重的精度下降(见图10)。另一方面,我们也可以通过选择 $s_j = 1/\max(|W_j|)$ 将所有的量化难度从权重推给激活。同样,由于激活量化误差,模型性能也很差。因此,我们需要在权重和激活之间分配量化难度,使它们都易于量化。

图5:SmoothQuant在α为0.5时的主体思想。平滑因子s是在校准样本上获得的,整个变换是离线执行的。在运行时,激活是平滑的,无需缩放。
图5:SmoothQuant在α为0.5时的主体思想。平滑因子s是在校准样本上获得的,整个变换是离线执行的。在运行时,激活是平滑的,无需缩放。

引入迁移强度超参数$\alpha$。我们引入一个超参数,即迁移强度$\alpha$,来控制我们希望从激活迁移到权重的难度大小,使用以下公式:


我们发现对于大多数模型,例如所有的OPT【索引49,Opt: Open pre-trained transformer language models, 2022, arXiv】和BLOOM【索引31,Bloom: A 176b-parameter open-access multilingual language model, 2022, arXiv】模型,$\alpha=0.5$是一个很好的平衡点,可以均匀地分配量化难度,特别是当我们对权重和激活使用相同的量化器时(例如,逐张量、静态量化)。该公式确保了相应通道的权重和激活具有相似的最大值,从而共享相同的量化难度。图5展示了当$\alpha=0.5$时的平滑变换。对于其他一些激活异常值更显著的模型(例如,GLM-130B【索引48,Glm-130b: An open bilingual pre-trained model, 2022, arXiv】约有30%的异常值,激活量化更困难),我们可以选择一个更大的$\alpha$(如0.75)将更多的量化难度迁移到权重上。

在Transformer模块中应用SmoothQuant

量化流程设计。线性层占据了LLM模型的大部分参数和计算量。默认情况下,我们对自注意力和前馈层的输入激活进行尺度平滑,并对所有线性层进行W8A8量化。我们还量化了注意力计算中的BMM(批量矩阵乘法)算子。我们在图6中设计了一个Transformer模块的量化流程。我们将计算密集型算子(如线性层和BMM)的输入和权重用INT8进行量化,而将其他轻量级的逐元素操作(如ReLU、Softmax和LayerNorm)的激活保持为FP16。这样的设计帮助我们在准确性和推理效率之间取得平衡。

图6:SmoothQuant在一个Transformer模块中的精度映射。所有计算密集型算子,如线性层和批量矩阵乘法(BMM),都使用INT8算术。
图6:SmoothQuant在一个Transformer模块中的精度映射。所有计算密集型算子,如线性层和批量矩阵乘法(BMM),都使用INT8算术。

表2:基线和SmoothQuant的量化设置。除非特别说明,所有权重和激活都使用INT8表示。对于SmoothQuant,效率从O1到O3递增(即延迟更低)。
表2:基线和SmoothQuant的量化设置。除非特别说明,所有权重和激活都使用INT8表示。对于SmoothQuant,效率从O1到O3递增(即延迟更低)。

A4 实验环境

  • 模型:评估了三个LLM家族:OPT、BLOOM和GLM-130B。后续还扩展到了MT-NLG 530B、Llama-1/2、Falcon、Mistral和Mixtral等模型。
  • 数据集
  • 评估:使用了七个零样本评估任务(LAMBADA, HellaSwag, PIQA, WinoGrande, OpenBookQA, RTE, COPA)和一个语言建模数据集(WikiText)。对于GLM-130B,使用了MMLU、MNLI、QNLI和LAMBADA。
  • 校准:使用来自预训练数据集Pile的512个随机句子一次性校准平滑因子和静态量化步长。
  • 硬件配置:NVIDIA A100 80GB GPU服务器。
  • 软件配置
  • 实现后端
    1. PyTorch Huggingface:用于概念验证。
    2. FasterTransformer:作为生产环境中高性能框架的示例。
  • 核心库:使用CUTLASS INT8 GEMM核函数实现了INT8线性模块和批量矩阵乘法(BMM)功能。
  • 基线方法
  • W8A8朴素量化
  • ZeroQuant 【索引46,Zeroquant: Efficient and affordable post-training quantization for large-scale transformers, 2022, arXiv】
  • LLM.int8() 【索引7,LLM.int8(): 8-bit matrix multiplication for transformers at scale,2022,arXiv】
  • Outlier Suppression 【索引42,Outlier suppression: Pushing the limit of low-bit transformer language models, 2022, arXiv】
  • SmoothQuant变体:提供了从O1到O3三个效率递增的量化级别(详见表2)。
  • 超参数设置:迁移强度$\alpha$对所有OPT和BLOOM模型设置为0.5,对GLM-130B设置为0.75。

A4 实验结果

1. 准确性评估
- OPT-175B:在OPT-175B上,SmoothQuant的所有量化方案(O1-O3)均能匹配FP16的精度,而W8A8、ZeroQuant和Outlier Suppression等基线方法性能严重下降,结果近乎随机(表3)。LLM.int8()能保持精度,但有显著的延迟开销。
- 不同LLM:SmoothQuant成功量化了所有超过100B参数的现有开源LLM(