一、Mixed Precision Training [2017] [粗读]

论文:《Mixed Precision Training》

论文是关于混合精度训练的,考虑到混合精度训练的思想已经广为人知,因此这里仅做粗读。

  1. Introduction:略(参考原始论文)。

  2. 相关工作:略(参考原始论文)。

1.1 方法

  1. 我们介绍了 training with FP16 的关键技术,同时仍然匹配 FP32 training sessionmodel accuracysingle-precision master weights and updatesloss-scalingaccumulating FP16 products into FP32

    单精度浮点数为 float32、双精度浮点数为 float64

1.1.1 FP32 Master Copy Of Weights

  1. 在混合精度训练中,权重、activations 以及梯度以 FP16 格式存储。为了匹配 FP32 网络的准确率,我们维护权重的一份 FP32 master copy ,并在 optimizer step 中用 weight gradient 来更新它。在每次迭代中,使用 master weightsFP16 copy 进行正向传播和反向传播,将 FP32 training 所需的存储和带宽减半。Figure 1 说明了这种混合精度训练过程。

  2. 虽然 FP32 master weights 的需求并非普遍存在,但有两个可能的原因解释为什么许多网络需要它:

    • 一个解释是 updatesweight gradients 乘以学习率)变得太小而无法用 FP16 表示。FP16 中任何 magnitude 小于 224 的值都会变成零。如 Figure 2b 所示,约 5%weight gradient valuesexponents 小于 -24 。在 optimizer 中,这些小的梯度与学习率相乘后会变成零,并对模型准确率产生不利影响。使用 single-precision copy 进行更新可以克服这个问题并恢复准确率。

      即,weight updates 绝对很小,导致 updates 变成零。

    • 另一个解释是 weight valueweight update 的比率非常大。在这种情况下,即使 weight update 可以用 FP16 来表示,当加法操作将 weight update 右移从而将 binary pointweights 对齐时, weight update 仍然可能变成零。当 normalized weight valuemagnitudeweight updatemagnitude 大至少 2048 倍时,这种情况可能发生。由于FP1610-bit 尾数,implicit bit 必须右移 11 位或更多位才可能创建零(在某些情况下,rounding 可以恢复该值)。在比率大于 2048 的情况下,implicit bit 将右移 12 位或更多位。这将导致 weight update 变成无法恢复的零。更大的比率将对 de-normalized 数字产生这种效应。同样,这种效应可以通过在 FP32 中计算 weight update 来抵消。

      即,weight updates 相对 weight 很小,导致训练效率很低(即,每个 step 中,权重的变化幅度非常小)。

    为了说明权重的 FP32 master copy 的必要性,我们使用了 Mandarin 语音模型在约 800 小时的语音数据上训练 20 epochs 。如Figure 2a 所示,当在 FP16 forward and backward passes 之后更新 FP32 master copy of weights 时,我们匹配了 FP32 training 结果;而更新 FP16 weights 则导致 80% 的相对 accuracy loss

  3. 尽管与 single precision training 相比,维护额外的权重副本将权重的内存需求增加了 50% ,但对整体内存使用的影响要小得多。 对于训练,内存消耗主要由 activations 引起,这是由于较大的 batch size 、以及保存每层的 activations 从而在反向传播中重用。 由于 activations 也以半精度格式存储,所以整体内存消耗约减半。

    作者这里并未给出数据来说明。

1.1.2 Loss Scaling

  1. FP16 exponentnormalized value exponents 范围有偏地居中到 [-14,15] ,而实际梯度值往往以小 magnitudesnegative exponents )为主。例如,考虑 Figure 3,显示了在 FP32 训练 Multibox SSD 检测器网络过程中收集的所有层的 activation gradient values 的直方图。注意,FP16 可表示范围的大部分未被使用,而许多值低于最小可表示范围并变为零。 scaling up 梯度将使它们占用更多的可表示范围,并保留一些值(如果不 scaling up,这些值将会因为零而丢失)。

    不缩放梯度时,该特定网络会发散;但将其缩放 8 倍(对 exponents 增加 3 )足以匹配 FP32 training 达到的准确率。这表明,在 magnitude 上小于 227activation gradient values 对此模型的训练无关,但 [227,224) 范围内 magnitudeactivation gradient values 很重要。

    由于学习率通常很小,因此 [227,224) 范围内的activation gradient values 乘以学习率仍然可能小于 227 。但是,Weight Update 采用 FP32,因此不会变为零。

  2. gradient values 移至 FP16 可表示范围的一种有效方法是:在开始反向传播之前,缩放在前向传播中计算的 loss value 。通过链式法则,反向传播将确保所有梯度值被缩放相同的量。这在反向传播期间不需要额外的操作,并使相关的梯度值不会变成零。

    在权重更新之前,必须 unscale 权重梯度,从而保持 weight update magnitudesFP32 training 相同。最简单的方法是:在反向传播结束之后、但在梯度裁剪或任何其他与梯度相关的计算之前进行 unscale ,从而确保不需要调整任何超参数(如梯度裁剪阈值、weight decay 等)。

    虽然可以通过缩小学习率来间接地缩放梯度,但是梯度裁剪阈值、weight decay 等等方法的超参数也需要相应地缩放。

  3. loss scaling factor 有几种选择。最简单的一种是选择一个常量的 scaling factor 。我们用 832Kscaling factor 训练了各种网络(许多网络不需要 scaling factor )。可以经验性地选择一个常量 scaling factor ,或者如果有梯度统计信息,可以直接选择一个 scaling factor 使其与 maximum absolute gradient value 的乘积低于 65,504FP16 中可表示的最大值)。

    只要不在反向传播期间导致数值溢出,选择一个大的 scaling factor 就没有坏处。数值溢出会导致 weight gradients 中出现无穷大和 NaN ,在权重更新后会不可逆地破坏权重。请注意,数值溢出可以通过检查计算到的 weight gradients (例如在 unscale weight gradient values 的时候)来有效检测。一种解决方法是:在检测到数值溢出时跳过 weight update ,直接进入下一次迭代。

1.1.3 算术精度

  1. 在很大程度上,神经网络的算术分为三类:向量点积、reductions 、以及 point-wise 操作。这些算术类别在 reduced precision 算术方面受益于不同的处理。

    • 为了保持模型准确率,我们发现一些网络要求 FP16 vector dot-product 从而累积 partial productsFP32 值,然后在写入内存前将其转换为 FP16 。如果不这样累积到 FP32 ,一些 FP16 模型的准确率无法匹配 baseline 模型。而先前的 GPU 只支持 FP16 multiply-add 操作,而 NVIDIA Volta GPU 引入了 Tensor Core ,可以将 FP16 的 输入矩阵相乘并累积乘积结果到 FP16 outputFP32 output

    • 大型的 reductions(如向量元素之和)应在 FP32 中进行。这种 reductions 主要出现在 batch-normalization layers (累积统计信息)和 softmax layers 。在我们的实现中,这两种 layer 类型仍从内存读取和写入 FP16 张量,而在 FP32 中执行算术运算。这并没有减慢训练过程,因为这些 layers 受内存带宽限制,而对于算术速度不敏感。

    • point-wise 操作(如非线性激活函数、element-wise 矩阵乘法)受内存带宽限制。由于算术精度不影响这些操作的速度,可以使用 FP16FP32

1.2 实验

  1. 略(参考原始论文)。

二、Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference[2017] [粗读]

论文:《Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference》

论文是关于量化 CNN 模型的,这里仅做粗读,仅关注核心算法。

  1. Introduction:略(参考原始论文)。

  2. 相关工作:略(参考原始论文)。

2.1 Quantized Inference

2.1.1 量化方案

  1. 在这一节中,我们描述了通用的量化方案,也就是两种类型数值之间的对应关系: bit representation of values(这个整数记为 q ,表示"quantized value")、以及它们作为数学的实数的解释(对应的实数记为 r ,表示 "real value")。我们的量化方案在推理时只使用整数算术实现,在训练时使用浮点算术实现,两种 implementations 高度对应。我们首先数学上严格定义量化方案,然后分别采用该方案用于 integer-arithmetic inferencefloating-point training

    floating-point training 类似于量化感知训练 Quantization Aware Training,即在训练阶段就应用 “模拟” 量化操作,从而降低 integer-arithmetic inference 的量化误差。

  2. 我们量化方案的一个基本要求是,它允许只使用整数算术操作对 quantized values 进行所有算术运算的有效实现(我们避免需要 lookup tables 的实现,因为它们往往比在 SIMD 硬件上进行纯算术运算表现更差)。这相当于要求量化方案是整数 q 到实数 r 的仿射映射,即形式为:

    (1)r=S(qZ)

    其中:SZ 为某些常量。

    • 常数 S (表示 "scale" )是一个任意的正实数。它通常以软件中的浮点数形式表示,类似于实数 r 。本文后续内容描述了避免在推理工作中表示这种浮点数的方法。

    • 常数 Z (表示"zero-point" )与 quantized value q 的类型相同,事实上是对应于实数 0quantized value q 。这自动满足以下要求:实数 r=0 可以被 quantized value 精确地表示。这一要求的动机是,高效实现的神经网络算子通常需要对数组进行 zero-padding

    这个公式是我们的量化方案,常数 S 和常数 Z 是我们的量化参数(quantization parameters)。我们的量化方案对每个 activations array内的所有值、以及 weights array 内的所有值使用单组量化参数,即:不同的 array 使用独立的量化参数。

    对于 8-bit 量化,q 被量化为 8-bit 整数(对于 B-bit 量化,q 被量化为 B-bit 整数)。一些数组(通常是 bias vectors )被量化为 32-bit 整数,参见后续内容。

  3. 到目前为止的讨论被总结在以下的 quantized buffer 数据结构中,神经网络中的每个 activations arrayweights array 都有这样一个 buffer 实例。我们使用 C++ 语法是因为它可以明确地表达类型:

2.1.2 仅整数算术的矩阵乘法

  1. 我们现在考虑如何仅使用整数算术进行推理,也就是如何使用方程 r=S(qZ) 将实数运算翻译成 quantized-values 运算,以及后者如何设计为仅包含整数算术,即使 scaling 参数 S 是浮点数不是整数。

  2. 考虑两个 N×N 的实数矩阵 R1R2 的乘法,其矩阵乘积表示为 R3=R1R2 。我们将每个矩阵 Rαα=1,2,3)的项表示为 rα(i,j),其中 1i,jN。对应的 quantized 矩阵为 Qa,每一项表示为 qa(i,j)。对应的量化参数为 (Sα,Zα)。则方程 r=S(qZ) 则变为:

    (2)rα(i,j)=Sα(qα(i,j)Zα)

    从矩阵乘法的定义,我们有:

    (3)S3(q3(i,k)Z3)=j=1N[S1(q1(i,j)Z1)S2(q2(j,k)Z2)]

    这可以重写为:

    (4)q3(i,k)=Z3+Mj=1N[(q1(i,j)Z1)(q2(j,k)Z2)]

    其中乘数 M 定义为:

    (5)M=S1S2S3
  3. q3(i,k) 的方程中,唯一的非整数是乘数 M 。作为仅依赖于 quantization scales S1S2S3 的常数,它可以离线计算。我们经验性地发现它总是在区间 (0,1) 内,因此可以表示为归一化的形式:

    (6)M=2nM0

    其中:其中 M0 在区间 [0.5,1) 内,n 为非负整数。

    • 归一化的乘数 M0 现在很适合表示为定点乘数(例如根据硬件能力,采用 int16int32 )。例如,如果使用 int32 的整数乘法,表示 M0 的整数是最接近 231×M0int32 值。由于 M0>0.5 ,这个值总是至少 230 ,因此总是有至少 30-bit 的相对精度。因此,乘以 M0 的乘法可以实现为定点乘法(fixed-point multiplication)。

    • 同时,乘以 2n 的乘法可以实现为有效的移位运算(bit-shift ),尽管需要具有正确的四舍五入(round-to-nearest )行为,我们在附录 B 中讨论这个问题。

2.1.3 高效处理 ZeroPoint

  1. 为了在不执行 2N3 次减法、并且不将乘法操作数展开成 16-bit 整数的情况下,有效地实现公式 q3(i,k) 的求值,我们首先注意到通过在公式 q3(i,k) 中分配乘法,我们可以重写为:

    (7)q3(i,k)=Z3+M(NZ1Z2Z1a¯2kZ2a¯1(i)+j=1Nq1(i,j)q2(j,k))

    其中:

    (8)a¯2(k)=j=1Nq2(j,k),a¯1(i)=j=1Nq1(i,j)

    每个 a¯2(k)a¯1(i) 只需要 N 次加法来计算,所以总共只需要 2N2 次加法。

    上式的剩余成本几乎全部集中在核心的整数矩阵乘法累加上:

    (9)j=1Nq1(i,j)q2(j,k)

    这需要 2N3 次算术运算。

    的确,q3(i,k) 的新公式中的所有其他运算都是 O(N2),其中 O 中的常数很小。因此,展开成上述新公式的形式、以及分解为计算 a¯2(k)a¯1(i) ,使得对于任意 zero-points 都能以很小的开销处理,除了 N 非常小的情况;问题简化为相同的 core integer matrix multiplication accumulation,因为我们在任何其他 zero-points-free 方案中都必须计算它。

    这仅仅改善了减法操作,而没有改善乘法操作。

    • 原始方法中,对于 Q3 ,一共需要 2N3 的减法操作;但是新的方法中,计算 {a¯2(k)}k=1N 需要 N2 次加法操作。然后 a¯2 可以在不同的 q3(,k) 中共享。

    • 但是,对于乘法操作,二者之间并未改善。

2.1.4 典型 fused layer 的实现

  1. 我们继续前面的讨论,但现在显式地定义所有涉及的量(quantities )的数据类型,并修改 quantized 的矩阵乘法,从而直接将 bias-additionactivation function evaluation 合并到其中。这样将整个 layer 融合成单个操作而不仅是一个优化。由于我们必须在推理代码中重现训练中使用的相同算术,推理代码中的 fused operators 的粒度(接受 8-bit quantized input 并产生 8-bit quantized output )必须与训练图中 "fake quantization" operatorsplacement 相匹配。

    对于 ARMx86 CPU 架构,我们使用 gemmlowp 库(《gemmlowp: a small self-contained low-precision gemm library》),其 GemmWithOutputPipeline 入口点支持我们现在描述的 fused operations

    General Matrix Multiplication: GEMM :通用矩阵乘法。

  2. 我们将 Q1 矩阵设为权重、Q2 矩阵设为 activations 。权重和 activations 均为 uint8 类型(我们也可以等效地选择 int8 ,适当修改 zero-points )。uint8 值的乘积的累加需要 32-bit accumulator ,我们为 accumulator 选择带符号类型,原因很快就会变清楚。 j=1Nq1(i,j)q2(j,k) 中的求和因此具有如下形式:

    (10)int32=unit8 × unit8 

    为了得到 quantized bias-addition (将 int32 bias 添加到 int32 accumulator 上),bias-vector 被量化为:

    • 使用 int32 作为其量化数据类型。

    • 使用 0 作为其 quantization zero-point Zbias

    • quantization scale Sbiasaccumulators 的相同,即 weights scaleinput activations scale 的乘积:

      (11)Sbias=S1S2,Zbias=0

    尽管 bias-vectors 被量化为 32-bit 值,但它们只占神经网络参数的很小一部分。此外,对 bias vectors 使用更高精度满足了一个真正的需求:由于每个 bias-vector entry 被添加到许多 output activations 中,bias-vector 中的任何量化误差往往表现为一个 overall bias (即,均值不为零的误差项),这必须避免以保持端到端的神经网络准确性。

    即,对于任何样本 Xbias-vector 都添加到它的 output activation 上,因此 bias-vector 对所有样本都产生了影响。

  3. int32 accumulator 的最终值,还剩下三件事要做:

    • scale downfinal scale,这个 final scale8-bit output activations 所使用。

    • cast downunit8

    • 应用 activation function 生成 final 8-bit output activation

    下采样对应于乘数 M。如前所述,它实现为由归一化的乘数 M0 的定点乘法、以及 rounding bit-shift 组成。之后,我们执行 castuint8 ,饱和到 [0,255] 范围。

    我们仅仅关注 clamps 类型的激活函数,例如 ReLUReLU6 。数学函数在附录 A.1 中讨论,目前我们不会将它们融合到这种层中。因此,我们 fused activation functions 唯一需要做的就是进一步将 uint8 值截断到 [0,255] 的某个子区间,然后存储 final uint8 output activation。实际上,quantized training process (参考下一节)倾向于学习使用整个 output uint8 区间 [0,255] ,以致 activation function 不再起任何作用,其效果被归因于截断到区间 [0, 255] (由于 castunit8 所隐含的)。

2.2 Training with simulated quantization

在大模型时代,通常很少采用 simulated quantization 的训练,而是直接训练一个大模型,然后再进行 post-training 量化。

  1. 训练 quantized networks 的常见方法是:用浮点进行训练,然后量化所得到的权重(有时伴随额外 post-quantization training 从而进行微调)。我们发现,这种方法对具有相当表达能力的大型模型效果足够好,但对小型模型会导致明显的准确率下降。simple post-training quantization 的常见失败模式包括:

    • 1) :不同 output channels 的权重范围差异很大(大于 100 倍)。注意:前面章节中规定,同一层的所有通道必须量化到相同分辨率;这会导致权重范围较小的通道中,权重的相对误差更大。

    • 2)outlier weight values,这些异常值使得量化后所有的非异常值的权重降低了精确性。

  2. 我们提出了一种在训练的前向传播中模拟量化效应(quantization effects )的方法。反向传播仍然照常进行,所有权重和 bias 以浮点存储,以便可以轻易地略微调整。但是,前向传播模拟 quantized inference (因为 quantized inference 发生在推理引擎中),通过如下方式:以浮点算法实现我们前面介绍的量化方案中的 rounding behavior

    • 权重在与 input 执行卷积之前被量化。如果 layer 使用 batch normalization ,则在量化之前,batch normalization 参数被 “折叠”到权重中。

    • activations 在这样的时点上被量化:在推理期间 activations 被量化的点。例如:在 activation function 应用于卷积层或全连接层输出之后、或在像 ResNet 中那样多个层的输出相加或拼接的 bypass connection 之后。

    对于每一层,quantizationquantization levels 数量、以及 clamping range 的参数化,并通过 point-wise 地应用下面定义的量化函数 q 来执行:

    (12)clamp(r;a,b)=min(max(r,a),b),abs(a,b,n)=ban1q(r;a,b,n)=clamp(r;a,b)as(a,b,n)×s(a,b,n)+a

    其中:r 是要被量化的实值数;[a;b] 是量化范围;nquantization levels 数量; 表示四舍五入到最近的整数。

    在我们的实验中,n 对所有层固定,例如 8-bit 量化时 n=28=256

    即,在原始的神经网络中插入这些特定的 fake quantization layer

2.2.1 学习 quantization ranges

  1. weight quantizationactivation quantizationquantization ranges 的处理不同:

    • 对于权重,基本思想是:简单地设置 a=min(W);b=max(W),其中 W 为权重矩阵。我们对此稍作调整,使得权重一旦被量化为 int8 值,取值范围仅仅在 [-127, 127] 并且不会取值为 -128 ,因为这 enable 了一个重要的 optimization opportunity (更多细节见附录 B )。

    • 对于 activationsranges 取决于网络输入。为了估计 ranges ,我们在训练期间收集 activations 上的 [a; b] 范围,然后通过指数移动平均(exponential moving averages: EMA )聚合它们,平滑参数接近 1 ,以便 observed ranges在数千步训练中平滑。鉴于在 ranges 快速变化时,EMA 更新 activation ranges有明显延迟,我们发现在训练开始时完全禁用 activation quantization 很有用(例如前 50K 步到 2M 步)。这使网络进入更稳定状态,其中 activation quantization ranges 不会排除 values 的重要部分。

      这类似于 Batch Normalization 的思想。在训练中自动更新 activation ranges

    在两种情况下,都会调整 [a; b] 的边界,以便值 0.0 在量化后可以精确表示为整数 z(a,b,n)。因此,学到的 quantization parameters 映射到方程 r=S(qZ) 中的 scale Szero-point Z

    (13)S=s(a,b,n),Z=z(a,b,n)
  2. 下面我们假设神经网络的计算被捕获为 TensorFlow graph ,然后描述 simulated quantization 。典型的工作流程在 Algorithm 1 中描述。通过 fusing and removing operationsinference graph 的优化,超出了本文范围。用于 graph modifications 的源码(插入 fake quantization 操作、创建和优化 inference graph)、以及 low bit inference engine 已在 《Tensorflow quantized training support》 中通过 TensorFlow contributions 开源。

    公式 12 为:

    (14)clamp(r;a,b)=min(max(r,a),b),abs(a,b,n)=ban1q(r;a,b,n)=clamp(r;a,b)as(a,b,n)×s(a,b,n)+a

  3. Figure 1.1 a and b 说明了一个简单卷积层量化前后的 TensorFlow graphFigure C.3 中,更复杂的带 bypass connection 的卷积的说明,可以在 Figure C.4 中找到。

    请注意,bias 没有被量化,因为在推理过程中它们表示为 32-bit 整数,范围和精度远高于 8-bit weights and activations。此外,用于,bias 的量化参数从权重和激活的量化参数推导出来。

    使用《Tensorflow quantized training support》 的典型 TensorFlow 代码示例如下:

2.2.2 Batch normalization folding

  1. 对于使用 batch normalization 的模型,存在额外复杂性:training graphbatch normalization是单独的操作块,而 inference graphbatch normalization 参数 “折叠” 到卷积层或全连接层的权重和 bias 中,从而提高效率。为了准确模拟量化效应,我们需要模拟这种折叠,并在权重被 batch normalization parameters 缩放后再来量化权重。我们采用以下方法:

    (15)wfold=γwEMA(σB2)+ϵ

    其中:

    • γbatch normalizationscale 参数。

    • EMA(σB2)convolution resultsbatch 内方差的移动平均估计。

    • ϵ 是一个小常数用于数值稳定性。

    折叠后,batch-normalized convolutional layer 简化为 Figure 1.1a 中所示的简单卷积层,具有被折叠的权重 wfold 、以及相应的被折叠的 bias 。因此,相同的配方也适用于 Figure 1.1b 。附录中可以查阅 batch-normalized convolutional layerFigure C.5 )、相应的 inference graphFigure C.6 )、batch-norm folding 后的训练图( Figure C.7 )以及 folding and quantization 后的训练图( Figure C.8 )。

2.3 实验

  1. 略(参考原始论文)。

三、LLM.int8()[2022]

论文:《LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale》

  1. 大型 pretrained 语言模型在 NLP 中被广泛采用,但需要大量内存进行推理。对于超过 6.7B 参数的大型 transformer 语言模型,前馈层(feed-forward layer )和注意力投影层(attention projection layer)及其矩阵乘法操作占据了 95% 的参数和 65-85% 的所有计算(《High performance natural language processing》)。减小参数大小的一种方法是将其量化为更少的比特并使用低位精度(low-bit-precision )的矩阵乘法。考虑到这一目标,人们已经开发了 transformer8-bit 量化方法。虽然这些方法减少了内存使用,但它们降低了性能,通常需要在训练后进一步 tuning quantization,并且只在少于 350M 参数的模型上进行了研究。低于 350M 参数时性能无损的量化理解得不够好,十亿参数级的量化仍是一个开放性挑战。

    在本文中,我们提出了第一个不降低性能的十亿参数级 Int8 量化过程。我们的过程使得加载一个具有 16-bit32-bit 参数的 175B 参数的 transformer ,将前馈层和注意力投影层转换为 8-bit,并立即用于推理而不降低任何性能。我们通过解决两个关键挑战实现了这一结果:

    • 大于 1B 参数时需要更高的量化精度(quantization precision )。

    • 需要明确表示稀疏的但系统性的大幅值的异常值特征(sparse but systematic large magnitude outlier features),在所有的 transformer 层(从 6.7B 参数规模开始)中,这些特征一旦出现就会破坏量化精度。一旦这些异常值特征出现,C4 evaluation perplexity 以及 zero-shot accuracy 就会反映出这种精度损失(loss of precision ),如 Figure 1 所示。

    我们证明,通过我们方法的第一部分向量化量化(vector-wise quantization),可以在高达 2.7B 参数的规模下保持性能。对于向量化量化,矩阵乘法可以看作是行向量序列和列向量序列的独立内积序列。因此,我们可以为每个内积使用单独的量化归一化常数(quantization normalization constant)来提高量化精度。我们可以通过在执行下一个操作之前用列归一化常数和行归一化常数的外积对矩阵乘法的输出进行反归一化(denormalizing)来恢复矩阵乘法的输出。

    为了在不降低性能的情况下扩展到超过 6.7B 的参数,理解推理过程中隐状态(隐状态就是 activationfeature dimensions中的极端异常值的出现至关重要。为此,我们提供了一个新的描述性分析,该分析显示:

    • 在将 transformer 扩展到 6B 参数时,所有 transformer 层中大约 25% 首先出现了幅度高达其他维度 20 倍的大特征(large features ),然后这些大特征逐渐传播到其他层。

    • 在大约 6.7B 参数时,发生了一个phase shift ,所有 transformer 层、以及 75% 的所有sequence dimensions都受到极端幅度的特征(extreme magnitude features)的影响。这些异常值高度地系统化(systematic):在 6.7B 规模下,每个序列有 150,000 个异常值,但它们集中在整个 transformer 中的仅 6feature dimensions中。

      将这些异常feature dimensions设置为零会使 top-1 attention softmax 概率质量降低 20% 以上,并使 validation perplexity 退化 600-1000% ,尽管它们只占所有输入特征的约 0.1% 。相比之下,删除相同数量的随机特征会最大降低 0.3% 的概率质量,并退化约 0.1% 的困惑度(perplexity)。

    给定一个文本序列,sequence 维度表示 token id 的维度,feature 表示 embeddingactivation 的维度。上述描述的含义是:

    • 6B 模型,有 25% 的层(l=1,,L)出现了异常值。

    • 6.7B 模型,所有的层出现了异常值;沿着 token id 的方向,有 75% 的位置出现了异常值( s=1,,S);沿着 embedding/activation 的方向,有 6 个位置出现了异常值(i=1,,d)。

    写成矩阵的形式:

    (16)H1=[h1,1(1)h1,2(1)h1,d(1)h2,1(1)h2,2(1)h2,d(1)hS,1(1)hS,2(1)hS,d(1)],,HL=[h1,1(L)h1,2(L)h1,d(L)h2,1(L)h2,2(L)h2,d(L)hS,1(L)hS,2(L)hS,d(L)]RS×d

    为了支持这样极端异常值的有效量化,我们开发了混合精度分解(mixed-precision decomposition),即我们方法的第二部分。 我们对异常feature dimensions执行 16-bit 矩阵乘法、对其余 99.9% 的维度执行 8-bit 矩阵乘法。我们将向量化量化、以及混合精度分解的组合命名为 LLM.int8() 。 我们证明,通过使用 LLM.int8() ,我们可以在具有多达 175B 参数的 LLM 上进行推理,而不降低任何性能。我们的方法不仅为这些异常值对模型性能的影响提供了新的见解,而且还首次使非常大的模型(例如 OPT-175B/BLOOM )能够在具有消费级 GPU 的单服务器上使用。虽然我们的工作重点是在不降低性能的情况下使大型语言模型可访问,但我们在附录 D 中还展示了我们为大型模型(如 BLOOM-176B )维持端到端 inference runtime 性能,并为大于或等于 6.7B 参数的 GPT-3 模型提供了适度的矩阵乘法速度提升。我们开源了我们的软件,并发布了 Hugging Face Transformers 集成,使我们的方法可用于 Hugging Face Models 托管的所有具有线性层的模型。

    可以看到,LLM.int8() 仅在较大的模型(模型规模大于 6.7B )时才会加速推断;在更小的模型时,推断速度反而更慢(相比较于原始的 FP16 )。

  2. 相关工作:下面列出了 quantization data types 、以及 quantization of transformers 有密切相关的工作。附录 B 提供了有关 quantization of convolutional networks 的更多相关工作。

    • 8-bit Data Types:我们的工作研究围绕 Int8 数据类型的量化技术,因为它目前是 GPU 支持的唯一 8-bit 数据类型。其他常见的数据类型是定点 8-bit 数据类型或浮点 8-bit 数据类型(floating point 8-bit: FP8 )。

      这些数据类型通常有一个符号位( sign bit) 、以及指数位( exponent bit )和小数位( fraction bit) 的不同组合。例如,这种数据类型的一个常见变体有 5 bits 指数、 2 bits 小数,并使用 zeropoint scaling 或者 no scaling constants 。由于这些数据类型对 fraction 只有 2 bits,所以对大的幅值(large magnitude )有很大误差,但可以为小的幅值提供高精度。

      《F8net: Fixed-point 8-bit only multiplication for network quantization》 提供了出色的分析,关于对具有特定标准差的输入,在何时某些 fixed point exponent/fraction bit widths 是最佳的。我们认为 FP8 数据类型与 Int8 数据类型相比提供了优异的性能,但当前 GPUTPU 都不支持此数据类型。

    • 语言模型中的异常值特征(Outlier Features ):语言模型中大幅值异常值特征(large magnitude outlier features)的研究已经存在。

      • 先前的工作证明了 transformer 中异常值出现与 layer normalization 以及 token frequency distribution 的理论关系(《Representation degeneration problem in training natural language generation models》)。

      • 类似地,《Bert busters: Outlier dimensions that disrupt transformers》BERT 模型族中异常值的出现归因于 LayerNorm

      • 《Outliers dimensions that disrupt transformers are driven by frequency》 在经验上表明异常值的出现与训练分布中 tokens 的频率有关。

      我们通过展示自回归模型的规模与这些异常值特征的 emergent properties 之间的关系,以及适当建模异常值对有效量化(effective quantization )的重要性,从而来进一步扩展这项工作。

    • 十亿规模 transformer 的量化:与我们的工作相比,人们平行开发了两种方法:

      • nuQmm《nuqmm: Quantized matmul for efficient inference of large-scale generative language models》)、以及 ZeroQuant《Zeroquant: Efficient and affordable post-training quantization for large-scale transformers》)。两者使用相同的量化方案:分组向量化量化(group-wise quantization),其量化归一化常数粒度比向量量化更细。这种方案提供了更高的量化精度,但也需要自定义的 CUDA kernels

        • nuQmmZeroQuant 旨在加速推理和减少内存占用,而我们则关注在 8-bit 内存占用下保留预测性能。

        • nuQmmZeroQuant 评估的最大模型分别是 2.7B20B 参数的 transformerZeroQuant 实现了 20B 模型的 8-bit 量化,同时保持性能没有衰退。我们展示了我们的方法允许高达 176B 参数的模型进行 zero-degradation quantizationnuQmmZeroQuant 表明,更细粒度的量化可以是大型模型量化的有效手段。这些方法与 LLM.int8() 是互补的。

      • 另一个平行工作是 GLM-130B ,它使用我们工作的见解实现 zero-degradation 8-bit quantization《Glm-130b: An open bilingual pre-trained model》)。GLM-130B8-bit weight storage 进行完整的16-bit 精度的矩阵乘法。

        相比之下,LLM.int8() 采用 8-bit 的矩阵乘法。

3.1 背景知识

  1. 在这项工作中,我们通过扩展 transformer 模型将量化技术推向了极限。我们对两个问题感兴趣:

    • 在何种模型规模下量化技术会失败,以及为何量化技术会失败?

    • 量化技术的失败与量化精度有何关系?

    为了回答这些问题,我们研究了高精度非对称量化(zeropoint quantization )和高精度对称量化(absolute maximum quantization )。虽然 zeropoint quantization 通过使用数据类型的 full bit-range 提供了高精度,但由于实际限制而很少使用它。absolute maximum quantization 是最常用的技术。

3.1.1 8-bit 数据类型和量化

  1. absmax 量化通过将输入乘以 sXf16 从而缩放到 8-bit 范围 [-127, 127] 中。因此,对于 FP16 数据类型的输入矩阵 Xf16RS×hInt8 absmax quantization 由以下公式给出:

    (17)Xi8=127maxi,j(|Xf16,i,j|)×Xf16=127||Xf16||×Xf16=sXf16×Xf16

    其中:

    • || 表示绝对值, 表示四舍五入到最近的整数。

    • Xf16,i,j 表示 Xf16 的第 i 行、j 列的元素。

    • sXf16=127||Xf16|| 为量化常数。

  2. zeropoint 量化通过如下的方式将 input distribution 移动到 full range [-127, 127] 中:首先用 normalized dynamic range ndX 来缩放,然后用 zeropoint zpX 来移动。通过这种仿射变换(affine transformation ),任何输入张量都将使用数据类型的所有比特,从而减少非对称分布(asymmetric distributions )的量化错误。例如,对于 ReLU 输出,在 absmax 量化中,所有 [-127, 0) 的值都未被使用;而在 zeropoint 量化中,完整范围 [-127,127] 都被使用。

    zeropoint 量化由以下等式给出:

    (18)ndXf16=2×127maxi,j(Xf16,i,j)mini,j(Xf16,i,j)zpXi16=ndXf16×maxi,j(Xf16,i,j)+mini,j(Xf16,i,j)2Xi8=ndXf16×Xf16+zpXi16

    推导过程:假设 a=max(x),b=min(x),axb 。我们希望把 x 投影到 [-127, 127] 之间。则可以采用仿射变换:

    (19)y=xb(ab)×(2×127)127=x×2×127ab127×a+bab

    然后根据 q=y 来进行量化。

    根据论文《Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference》zeropoint 量化的形式为:

    (20)x=1ndXf16(qzp)1ndXf16(yzp)

    因此:

    (21)ndXf16=2×127ab,zp=127×a+bab

    逆量化为:Xf16=1ndXf16×(Xi8zp)

    要在操作中使用 zeropoint 量化,我们同时传入张量 Xi8zeropoint zpXi8 到一个特殊指令,该指令在执行 16-bit 整数操作之前,将zpXi8 添加到 Xi8 的每个元素中。例如,要将两个 zeropoint quantized 数值 Ai8Bi8 (以及它们的零点 zpAi8zpBi8)相乘,我们计算:

    (22)Ci32=multiplyi16(AzpAi16,BzpBi16)=(Ai8zpAi8)×(Bi8zpBi8)

    如果没有 multiply_i16 指令,如在 GPUTPU 上,则需要展开:

    (23)Ci32=Ai8Bi8Ai8zpBi8Bi8zpAi8+zpAi8zpBi8

    注意:结果是 32-bit 整数。

    其中:Ai8Bi8Int8 精度计算,其余以 Int16/32 精度计算。因此,如果没有 multiply_i16 指令,zeropoint 量化可能比较慢。

    在上述两种情况下,输出以32-bit 整数 Ci32 累加。为了逆量化 Ci32 ,我们将其除以缩放常数 ndAf16ndBf16

    即:

    (24)AzpAf16×BzpBf16=1ndAf16×ndBf16×[(Ai8zpAi8)×(Bi8zpBi8)]=1ndAf16×ndBf16×Ci32
  3. 具有 16-bit 浮点输入和输出的 Int8 矩阵乘法:给定隐状态 Xf16RS×h 和权重 Wf16Rh×o,其中 Ssequence dimensionshfeature dimensionso 为输出维度,我们执行具有 16-bit 浮点输入和输出的 8-bit 矩阵乘法如下:

    (25)Xf16Wf16=Cf161cXf16cWf16×Ci32=sf16×Ci32=sf16×Xi8Wi8sf16×Q(Xf16)Q(Wf16)

    其中:

    • cXf16,cWf16tensor-wise 的量化常数:

      • 对于 absmax 量化,它们分别为 sXsW

      • 对于 zeropoint 量化,它们分别为 ndX,ndW

    • sf16=1cXf16cWf16 为新的量化常数,Q()absmax 量化或 zeropoint 量化。

3.2 大规模的 Int8 矩阵乘法

  1. 使用每个张量一个 scaling constant (即, scaling constant )的量化方法的主要挑战是,单个异常值可以降低所有其他值的量化精度。因此,每个张量拥有多个 scaling constant 是可取的,比如 block-wise constants《8-bit optimizers via block-wise quantization》),这样异常值的影响就局限于每个 block 。我们通过使用向量化量化(vector-wise quantization )来改进 row-wise quantization《Fbgemm: Enabling high-performance low-precision deep learning inference》),其中row-wise quantization 是最常见的 blocking quantization 方式之一,详细内容如下所述。

  2. 为了处理超过 6.7B 规模的所有 transformer layers 中出现的大幅值异常值特征(large magnitude outlier features ),仅仅向量化量化是不够的。为此,我们开发了混合精度分解(mixed-precision decomposition),其中少量的大幅值的 feature dimensionslarge magnitude feature dimensions),占比约 0.1%16-bit 精度来表示,而其他 99.9% 的值以 8-bit 相乘。由于大多数元素仍以低精度来表示,与 16-bit 相比,我们仍保留约 50% 的内存减少。例如,对于 BLOOM-176B,我们将模型的内存占用降低了 1.96 倍。

  3. Figure 2 显示了向量化量化和混合精度分解。LLM.int8() 方法是 absmax vector-wise quantization 和混合精度分解的组合。

    注意:X 按列分解,W 按行分解。为什么?因为异常值特征主要集中在 activation (即,X)的少部分的列。而 W 通常不包含异常值。

    本文并没有理论指导,而是根据大模型的实验性分析从而得到的方法。

3.2.1 Vector-wise Quantization

  1. 增加矩阵乘法的 scaling constants 的数量的一种方法是:将矩阵乘法视为独立内积的序列。给定隐状态 Xf16RS×h 和权重 Wf16Rh×o,我们可以为 Xf16 的每一行分配不同的 scaling constants cXf16,并为 Wf16 的每一列分配不同的 cWf16。为了逆量化,我们通过 1/(cXf16cWf16)denormalize 每个内积结果。对于整个矩阵乘法,这相当于通过外积 cXf16cWf16denormalize ,其中 cXf16RScWf16Ro。因此,具有行 scaling constants 和列 scaling constants 的矩阵乘法的完整方程如下:

    (26)Cf161cXf16cWf16Ci32=SCi32=S(Ai8Bi8)=S(Q(Af16)Q(Bf16))

    其中:

    • 为逐元素乘法,Q()absmax 量化。

    • S=1cXf16cWf16scaling constants 矩阵。

    我们将其称为矩阵乘法的向量化量化。

    对于向量 aRS,bRo,它们的外积定义为:

    (27)ab=[a1b1a1b2a1boa2b1a2b2a2boaSb1aSb2aSbo]RS×o

3.2.2 LLM.int8() 的核心: Mixed-precision Decomposition

  1. 通过我们的分析,我们证明十亿级参数的 8-bit transformer 的一个重大问题是,它们具有大幅值特征(列),这对 transformer 性能非常重要,需要高精度量化。但是,我们的最佳量化技术(即,向量化量化)对每个隐状态行进行量化,这对异常值特征(outlier features )无效。幸运的是,我们看到这些异常值特征在实践中非常稀疏且系统化,只占所有feature dimensions的约 0.1% ,因此允许我们开发一种新的分解技术,重点关注这些特定维度的高精度乘法。

    这段话的意思是,异常值是集中在输入 X 的某些列,而不是集中在 X 的某些行。因此,对 X 进行按行的 scaling constants 会受到异常值的影响。

  2. 我们发现,给定输入矩阵 Xf16RS×h ,这些异常值几乎对所有 row 系统性地出现,但局限于特定的列。因此,我们为矩阵乘法提出混合精度分解,其中我们将包含异常值的列分离到集合 O={iiZ,0ih},它包含至少有一个幅值大于阈值 α 的列。在我们的工作中,我们发现 α=6.0 足以将transformerperformance degradation 减少到接近零。使用爱因斯坦记号,其中所有索引都是上标,给定权重矩阵 Wf16Rh×o,矩阵乘法的混合精度分解定义如下:

    (28)Cf16=iOXf16iWf16i+Sf16jOXi18jWi8j

    其中:Sf16denormalization 项。

    这种分离为 8-bit16-bit 允许异常值的高精度乘法,同时使用内存高效的矩阵乘法,其中包含 8-bit 权重值(在所有权重值中占比 99.9% 以上)。由于异常值的列对于高达 13B 参数的 transformer 不超过7 (即,|O|7),这种分解操作仅消耗约0.1% 的额外内存。

3.2.3 实验设置

  1. 我们随着模型规模的增加来衡量量化方法的稳健性,规模达到 175B 参数。关键问题不是某种量化方法对特定模型的表现如何,而是随着我们增加规模,这种方法的表现趋势如何。

    我们使用两种实验设置:

    • 一种基于语言建模困惑度(language modeling perplexity ),我们发现这是一种高度稳健的指标,对 quantization degradation 非常敏感。我们使用此设置来比较不同的 quantization baselines

      对于语言建模设置,我们使用在 fairseq 中预训练好的稠密的自回归 transformer ,参数范围在 125M13B 之间。这些transformerBooksEnglish WikipediaCC-NewsOpenWebTextCC-StoriesEnglish CC100 上进行了预训练。有关如何训练这些 pretrained models 的更多信息,请参阅 《Efficient large scale language modeling with mixtures of experts》

      为了评估 Int8 quantization 后语言建模的 degradation ,我们在 C4 语料库的验证数据上评估 8-bit transformer 的困惑度。C4 语料库是 Common Crawl 语料库的一个子集。我们使用 NVIDIA A40 GPU 进行评估。

    • 另外,我们在 OPT 模型上评估 zero-shot accuracy degradation ,跨不同的下游任务,其中我们将我们的方法与 16-bit baseline 进行比较。

      为了测量 zero-shot 性能的 degradation,我们使用 OPT 模型,并在 EleutherAI 语言模型评估工具箱上对这些模型进行评估。

3.2.4 主要结果

  1. C4 语料上对 125M13BInt8 模型的语言建模困惑度的主要结果见 Table 1 。我们看到:

    • 随着模型规模的增加,absmaxrow-wisezeropoint 等等量化都失败了,2.7B 参数后的模型性能低于较小的模型。zeropoint 量化在超过 6.7B 参数后失败。

      13B 规模,所有 baseline 方法的效果不如 6.7B 规模的模型。

    • 我们的方法 LLM.int8() 是唯一保持困惑度的方法。因此,LLM.int8() 是唯一具有良好缩放趋势的方法。

    row-wise :即 block-wise 量化,将张量拆分为多个 block,每个 block 拥有一个量化常数。

    倒数第三行(Int8 absmax row-wise + decomposition )和 Absmax LLM.int8()(vector-wise + decomp) 的区别仅仅是:前者采用 row-wise、后者采用 vector-wise

    最后两行的区别在于:前者采用 Absmax、后者采用 Zeropoint。可以看到,Zeropoint 相对于 absmax 的优势(第二行和第三行)消失了。原因见作者后面的讨论。

  2. 当我们在 Figure 1 中查看 OPT 模型在 EleutherAI 语言模型评估工具箱上的 zero-shot 性能的缩放趋势时,我们看到:

    • LLM.int8() 随着规模从 125M175B 参数的增加保持了 full 16-bit 性能。

    • 另一方面,基线 8-bit absmax vector-wise quantization 随着规模的增加表现糟糕,衰退为随机性能。

  3. 虽然我们的主要关注点是节省内存,但我们也测量了 LLM.int8() 的运行时间。

    • FP16 基准相比,quantization 开销可以拖慢小于 6.7B 参数模型的推理速度。但是,6.7B 参数或更小的模型在大多数 GPU 上可以正常适配,实际中不太需要量化。

    • 对于等效于 175B 模型的大矩阵乘法,LLM.int8() 的运行时间约快两倍。

    附录 D 提供了这些实验的更多详细信息。

3.3 大型 transformer 中的离群的大幅值特征

  1. 随着 transformer 规模的增加,大幅值的异常值特征涌现(emerge )并强烈影响所有层及其量化。给定隐状态 XRS×h,其中 Ssequence/token dimensionhhidden/feature dimension 。我们将特征定义为特定的 hidden/feature dimension hi (即,特征是按列来定义的),1hih。我们的分析检查给定 transformer 中所有层的特定feature dimensions hi

    我们发现:异常值特征对注意力和 transformer 的整体预测性能有很强的影响。 13B 模型中,每个 2048 token sequence 中存在多达 150k 个异常值,但这些异常值特征非常系统化,仅覆盖不超过 7unique feature dimensions hi 。这项分析的见解对开发混合精度分解至关重要。我们的分析解释了 zeropoint quantization 的优势、以及为何在使用混合精度分解后这些优势消失,以及小型模型 vs. 大型模型的量化性能。

3.3.1 寻找异常值特征

  1. 定量分析涌现现象(emergent phenomena )的困难有两个方面。我们旨在选择少量特征进行分析,使结果可理解且不太复杂,同时捕获重要的概率模式和结构模式。我们使用一种经验方法来找到这些约束。我们根据以下标准定义异常值:特征的幅值至少为 6.0 、异常值影响至少 25% 的层、异常值影响至少 6%sequence dimensions (即,6% 的行)。

    更正式地,给定具有 L 层的 transformer 和隐状态 XlRS×hl=1,,L,其中 Ssequence dimensionshfeature dimensions ,我们将特征定义为隐状态中的特定维度 hi1hih。我们跟踪那些至少有一个值的绝对值大于 6 的维度 hi ,同时我们仅统计这样的异常值:在所有隐状态中,异常值在至少在同一个特征的 25% 的层中出现,以及至少在 6% 的行中出现。由于特征异常值仅发生在注意力投影(key/query/value/outpu )和前馈网络扩张层(first sub-layer )中,因此我们忽略注意力函数和 FFN 收缩层(second sub-layer )进行此分析。

    我们选择这些阈值的原因如下:

    • 我们发现,使用混合精度分解,如果我们将任何绝对值大于或等于 6 的特征作为异常值特征对待,perplexity degradation 就会停止。

    • 对于异常值影响的层数,我们发现大型模型中的异常值特征是系统性的:要么发生在大多数层、要么根本不出现。

      另一方面,在小型模型中,异常值特征是概率性的:对于每个序列,它们有时出现在某些层中。

      因此,我们设置检测异常值特征的阈值,使得仅在我们最小的 125M 参数模型中检测到单个异常值。这个阈值对应于至少 25%transformer 层数受同一feature dimensions的一个异常值的影响。第二常见的异常值仅出现在单个层中(2% 的层),这表明这是一个合理的阈值。

      第二常见的异常值是什么意思?读者猜测是第二大的异常值。

    • 我们使用相同的过程找到异常值特征影响我们 125M 模型中多少行:异常值至少影响 6% 的行(即,sequence dimensions)。

  2. 我们测试了高达 13B 参数的模型。为了确保观察到的现象不是软件错误造成的,我们评估了在三个不同软件框架中训练的transformer 。我们评估了使用 OpenAI 软件的四个 GPT-2 模型、使用 Fairseq 软件的五个Meta AI 模型、以及使用 Tensorflow-Mesh 的一个 EleutherAI 模型GPT-J 。更多细节请参见附录 C 。我们还在两个不同的推理软件框架 FairseqHugging Face Transformers 中执行我们的分析。

    从下表可以看到:

    • C4 validation perplexity 越低,出现的异常值越多。

    • 异常值通常是单侧的,它们的四分位数范围显示,异常值的幅值比其他feature dimensions的最大幅值大 3 ~ 20 倍,而其他feature dimensions的范围通常为 [-3.5, 3.5]

    • 随着规模的增加,异常值在 transformer 的所有层中变得越来越常见,并且它们几乎出现在所有的 sequence dimensions中。

    • 6.7B 参数时发生了一个相变(phase shift ),对于约 75% 的所有sequence dimensionsSDim ),同一异常值出现在同一feature dimensions的所有层中。尽管只占所有特征的约 0.1% ,但这些异常值对大的 softmax 概率至关重要。

      如果删除异常值,平均 top-1 softmax 概率会缩小约 20% 。因为异常值在 sequence dimensions S 上具有非对称分布,这些异常维度破坏了对称的 absmax 量化,并有利于非对称的 zeropoint 量化。这解释了我们验证困惑度分析中的结果。

    这些观察结果似乎是普遍的,因为它们出现在不同软件框架中训练的模型中(fairseqOpenAITensorflow-mesh ),并且它们出现在不同的推理框架中(fairseqHugging Face Transformers)。这些异常值似乎也对 transformer 架构的细微变化稳健(rotary embeddingsembedding normresidual scaling 、不同初始化)。

3.3.2 测量异常值特征的影响

  1. 为了证明异常值特征对注意力和预测性能至关重要,我们在将隐状态 Xl 馈入注意力层投影层之前将异常值特征设为零,然后将 top-1 softmax 概率与常规的包含异常值的 softmax 概率进行比较。我们对所有层独立地执行此操作,这意味着我们 forward 常规的 softmax 概率值从而避免 cascading errors 并隔离由异常值特征引起的效应。如果我们删除outlier feature dimension(即,将其设为零)并通过 transformer 传播这些被改变的隐状态,我们还报告 perplexity degradation 。作为对照,我们对随机的 non-outlier feature dimensions 应用相同的程序,并注意 attention and perplexity degradation

    我们的主要定量结果可以总结为四个要点:

    • (1) :当以参数数量衡量时,大幅值特征在 transformer 所有层之间的涌现,在 Figure 3a 所示,在 6B6.7B 参数之间突然发生,受影响的层百分比从 65% 增至 100% 。受影响的 sequence dimensions数量迅速从 35% 增加到 75% 。这种突然的 shift 与量化开始失败的时机同时发生。

    • (2):另一方面,当以困惑度衡量时,大幅值特征在 transformer 所有层之间的涌现,可以看做是根据 decreasing perplexity 的指数函数平滑出现,如 Figure 3b 所示。这表明涌现没有什么突然,通过在更小的模型中研究指数趋势,我们可能能在发生相变之前检测到离群特征(emergent features )。这也表明涌现不仅与模型大小有关,还与许多其他因素有关,例如所使用的训练数据量和数据质量(《Training compute-optimal large language models》《Scaling laws for autoregressive generative modeling》)。

    • (3):一旦异常值特征出现在 transformer 的所有层中,median outlier feature magnitude 就迅速增加,如 Figure 4a 所示。异常值特征的大幅值和不对称分布扰乱了 Int8 量化精度。这是 6.7B 规模开始量化方法失败的核心原因:量化分布(quantization distribution )的范围太大,以至于大多数 quantization bins 是空的,small quantization values 被量化为零,本质上销毁了信息。我们假设,除了 Int8 推理之外,常规的 16-bit 浮点训练在超过 6.7B 规模后也会不稳定(如果向量相乘,而向量被填充了 magnitude60 的值,很容易偶然超过最大的 16-bit65535 )。

    • (4):如 Figure 4b 所示,随着 C4 perplexity 的降低,异常值特征的数量严格单调增加,而与模型大小的关系是非单调的。这表明模型困惑度而不是模型大小确定了相变。我们假设模型大小只是达到涌现所需的许多协变量中的一个重要协变量。

    相变发生后,这些异常值特征高度系统化。例如,对于一个序列长度为 20486.7B 参数 transformer ,我们发现对于整个transformer ,每个 sequence 约有 150k 个异常值特征,但这些特征仅集中在 6 个不同的 hidden dimensions 中。

    这些异常值对 transformer 性能至关重要。如果删除异常值,平均 top-1 softmax 概率从约 40% 降低到约 20% ,验证困惑度增加600-1000% ,即使最多只有 7outlier feature dimensions 。而当我们删除 7 个随机的feature dimensions时,top-1 softmax 概率仅降低 0.02-0.3% ,困惑度增加 0.1% 。这突显了这些feature dimensions的关键性质。这些异常值特征的量化精度至关重要,因为即使轻微的错误也会对模型性能产生巨大影响。

3.3.3 量化性能的解释

  1. 我们的分析表明,特定feature dimensions的异常值在大型 transformer 中无处不在,这些feature dimensionstransformer 性能至关重要。由于 row-wise and vector-wise quantization 对每个 hidden state sequence dimension S (行)进行缩放,而异常值发生在 feature dimension h (列)中,所以两种方法都无法有效处理这些异常值。这就是为什么 absmax 量化方法在 emergence 后迅速失败的原因。

    但是,几乎所有异常值都有严格的非对称分布:它们要么仅为正,要么仅为负(参见附录 C )。这使得 zeropoint 量化对这些异常值特别有效,因为 zeropoint 量化是一种非对称量化方法,可以将这些异常值缩放到完整范围 [-127, 127] 中。这解释了我们的 quantization scaling benchmarkTable 1 )中 zeropoint 量化的强大性能。但是,在 13B 参数规模,即使是 zeropoint 量化也会由于累积的量化误差和 outlier magnitudes 的快速增长而失败,如图 Figure 4a 所示。

    如果我们使用完整的 LLM.int8() 方法及混合精度分解, zeropoint 量化的优势消失,这表明 remaining decomposed features 是对称的。但是,与 row-wise quantization 相比,vector-wise 仍具有优势,这表明增强模型权重的量化精度对保持完整的预测性能至关重要。

3.4 讨论和局限性

  1. 我们首次证明,十亿参数级的 transformer 可以量化为 Int8 并立即用于推理,而不降低性能。我们通过使用我们在大规模分析出现的大幅值特征获得的见解来开发混合精度分解,从而将异常值特征隔离在单独的 16-bit 矩阵乘法中。结合我们的 vector-wise quantization 方法,我们经验证明可以恢复高达 175B 参数模型的完整推理性能。

  2. 局限性:

    • 我们工作的主要局限性是:我们的分析仅针对 Int8 数据类型,未研究 8-bit 浮点(FP8 )数据类型。由于当前 GPUTPU 不支持此数据类型,我们认为这最好留待未来工作。但是,我们也认为 Int8 数据类型的许多见解将直接转换为 FP8 数据类型。

    • 另一个局限性是:我们只研究了高达 175B 参数的模型。虽然我们将 175B 模型量化为 Int8 而不降低性能,但在更大规模上,额外的 emergent properties 可能会破坏我们的量化方法。

    • 第三个局限性是:我们没有对注意力函数使用 Int8 乘法。由于我们的重点是减少内存占用,而注意力函数不使用任何参数,所以这并不是绝对必要的。然而,对这个问题的初步探索表明,需要除了这里开发的之外的其他量化方法,我们留待未来工作。

    • 最后一个局限性是:我们关注推理但不研究训练或微调。我们在附录 E 中对大规模 Int8 微调和训练进行了初步分析。大规模Int8 训练需要在量化精度、训练速度、以及工程复杂性之间进行复杂的 trade-off ,这是一个非常困难的问题。我们同样留待未来工作。

  3. 更广泛的影响:我们工作的主要影响是,使以前因 GPU 内存有限而无法适配的大型模型变得可访问。这使得以前由于 GPU 内存有限而无法进行的研究和应用成为可能,特别是对资源最少的研究人员。 Table 2 列出了现在可以在不降低性能的情况下访问的 model/GPU 组合。但是,我们的工作也使得拥有许多 GPU 的资源丰富的组织可以在相同数量的 GPUserve 更多模型,这可能会增加资源丰富和资源贫穷组织之间的差距。

    具体而言,我们认为公开发布大型 pretrained 模型(例如最近的 Open Pretrained Transformers: OPT )以及我们对 zero-shot and few-shot prompting 的新的 Int8 推理,将为以前由于资源约束而无法进行的学术机构启用新的研究。这种大型模型的广泛可访问性可能对社会产生难以预测的有益的和有害的影响。

四、ZeroQuant [2022]

论文:《ZeroQuant: Efficient and Affordable Post-Training Quantization for Large-Scale Transformers》

  1. 大型自然语言模型已经在不同的应用中被广泛采用,例如使用 BERT 进行自然语言理解,以及使用 GPT-style 模型进行生成任务。虽然这些模型已经取得了 SOTA 的准确性,但随着模型规模的剧增,部署它们所需的内存占用和计算成本已经成为一个主要的瓶颈,即使是在强大的 GPU 云服务器上也是如此。

    量化是缓解这一挑战的一个有前景的方法,它可以降低权重和 activationsbit precision ,以达到更小的内存占用、以及更快的计算(例如 T4/A100 上的 INT8 Tensor cores )。然而,量化通常需要重新训练(也称为 quantization aware training: QAT )来恢复由 weight and activationsrepresentation loss 导致的准确率下降。为启用 QAT ,通常需要完整的训练流程(包括训练数据和计算资源),从而微调模型。现在访问这些组件的机会往往是没有的,而 QAT 也是一个非常耗时的过程,特别是对于那些大型模型。

    最近,zero-shot quantization《Zeroq: A novel zero shot quantization framework》《Data-free quantization through weight equalization and bias correction》)和 post-training quantization: PTQ《Up or down? adaptive rounding for post-training quantization》《Post-training quantization for vision transformer》)被提出,从而解决训练数据访问和计算需求的挑战,因为 PTQ 通常不需要(或只需要很少的)重新训练。但是大多数这些工作主要关注相对较小规模的计算机视觉问题。更近期,《Understanding and overcoming the challenges of efficient transformer quantization》BERT 上展示了有前景的 PTQ 结果。然而:

    • (1) :它的主要关注点是 BERT_base 上的高精度量化(INT8/FP16 )。

    • (2) :它没有考虑其他规模达十亿级别的参数的生成式模型(GPT-3-style 模型)。

    更重要的是,大多数这些工作没有报告真实的延迟改进,这就质疑了这些方法在改进inference latency 方面的有用性。例如,现有的工作通常不讨论与不同量化方案相关的 quantization/dequantization 成本,而这实际上对使用低精度带来的性能收益有很大影响。

    此外,对于极端量化(例如 INT4 ),通常使用知识蒸馏来提高性能,与 QAT 相比这又增加了昂贵的计算成本。而且,为了取得更好的准确率性能,通常对 quantized model 应用 hidden-states knowledge distillation ,例如 《Binarybert: Pushing the limit of bert quantization》《Ternarybert: Distillation-aware ultra-low bit bert》。这会给 GPU 内存和计算资源需求带来巨大压力,因为 teacher 模型和 student 模型都需要加载到 GPU 内存中进行训练。

    在本文中,我们提出 ZeroQuant ,一个端到端的 post-training quantization and inference pipeline ,以解决这些挑战,目标是 INT8INT4/INT8 混合精度量化。具体来说,我们的贡献如下:

    • 我们对权重和 activations 应用细粒度的硬件友好的量化方案,即权重的 group-wise quantization (即,列维度)、以及 activationstoken-wise quantization (即,行维度)。这两种量化方案都可以显著减少量化误差并保留 hardware acceleration 特性。

    • 我们提出了一种新的 layer-by-layer knowledge distillation: LKD 用于 INT4/INT8 混合精度量化,其中神经网络通过最小迭代的知识蒸馏被 layer-by-layer 地量化,甚至不需要访问原始训练数据。因此,在任意时刻,设备内存主要仅加载单个额外 layer 的占用,这使得规模达十亿级参数的模型蒸馏在有限的训练预算和 GPU 设备下成为可能。

    • 我们开发了一个高度优化的推理后端(inference backend ),消除了 quantization/dequantization 算子的高昂计算成本,在现代 GPU 硬件的 INT8 Tensor cores 上实现了延迟加速。

    • 我们的经验结果显示:

      • ZeroQuant 可以将 BERTGPT-3-style 模型量化为 INT8 权重和 activations 从而保留准确性,而不会产生任何重新训练成本。与 FP16 推理相比,在 A100 GPU 上,我们的 INT8 模型在 BERT_base/GPT-3_350M 上获得了高达 5.19x/4.16x 的加速。

      • ZeroQuant puls LKD 可以进行 BERTGPT-3-style 模型的 INT4/INT8 混合精度量化。与 FP16 模型相比,这导致了 3 倍的内存减少,准确率损失可以忽略。而且,得益于 LKD 的轻量级,我们可以在 33 秒(BERT_base )和 10 分钟(BERT_large )内完成量化过程。我们还展示 LKD 可以使用其他数据集达到类似于原始训练数据的性能。

      • 我们展示了 ZeroQuant 在两个最大的开源语言模型 GPT-J_6BGPT-NeoX_20B 上的可扩展性,使用 INT8 量化。ZeroQuant 可以在 GPT-J_6B 上实现比 FP16 模型快 3.67 倍;并且 ZeroQuantGPT-NeoX_20BGPU 需求从 2 减少到 1 ,延迟从 65ms 降低到 25ms (整体系统效率提高 5.2 倍)。

    本文的主要贡献是两个:layer-by-layer knowledge distillation 、以及高度优化的推理后端。

  2. 相关工作:人们从不同方面探索了模型压缩。其中,量化是最有前景的方向之一,因为它可以直接减少内存占用和计算强度。这里我们聚焦 NLP 模型的量化,并简要讨论相关工作。

    • 大多数量化工作可以归类为 quantization-aware training: QAT

      • 《Q-BERT: Hessian based ultra low precision quantization of bert》《Q8BERT: Quantized 8bit bert》 是第一批使用整数对权重和 activations 进行 BERT 模型量化的工作。具体而言,《Q-BERT: Hessian based ultra low precision quantization of bert》 利用 Hessian 信息将权重 bit-precision 推到 INT2/INT4 ,它还提出了 group-wise quantization ,从而比 single matrix quantization 更细粒度的方式对权重矩阵进行量化。

      • 《Training with quantization noise for extreme fixed-point compression》 引入 quantization noise 以缓解 QAT 的方差。

      • 《Ternarybert: Distillation-aware ultra-low bit bert》《Binarybert: Pushing the limit of bert quantization》 利用非常昂贵的知识蒸馏 (《Distilling the knowledge in a neural network》)和数据增强 (《Tinybert: Distilling bert for natural language understanding》 )从而 ternarize/binarize 权重。

      • 《Kdlsq-bert: A quantized bert combining knowledge distillation with learned step size quantization》 结合知识蒸馏和 learned step size quantization《Learned step size quantization》)将权重量化到 2-8 bits

      • 最近,《Compression of generative pre-trained language models via quantization》 也使用知识蒸馏将 GPT-2 模型在特定任务上压缩到 INT2

      所有这些工作都是使用原始训练数据集对模型进行量化的。更重要的是,它们需要重新训练、或微调整个模型来恢复准确率。这种 extra-large models (比如 megatron-turing nlg 530b, Palm)的计算成本,对大多数研究实验室或从业者来说几乎是不可承受的。

    • 克服计算成本挑战的一种解决方案是 post-training quantization: PTQ 。然而,PTQ 通常会导致显著的准确率下降,因为网络对量化误差敏感。

      • 沿着这条线,Transformer-based 模型的第一批工作之一是 《Gobo: Quantizing attention-based nlp models for low latency and energy efficient inference》 。作者提出了基于质心的量化方法,其中 outlier numbers 使用 FP32 格式,其余 numbers 使用 non-uniform quantization 。因此,很难在 general compute accelerators (如 CPUGPU )上获得真实的inference latency 收益,因为这些硬件中的 parallel processing units 不支持混合数据类型的有效计算。

      • 更近期地,《Understanding and overcoming the challenges of efficient transformer quantization》 为模型的一部分引入了高精度的 activation quantizationFP16 )以克服 high dynamic activation ranges

      但是,据我们所知:

      • (1) : 在先前的工作中还没有研究如何在GPT-3-style 模型上应用 PTQ 而达到高准确率。

      • (2):如何在十亿级规模的模型上应用 PTQ 仍较少被探索。

      • (3):高效的推理系统后端(inference system backend )仍然缺失,尤其是对于细粒度量化方案,这使得很难在通用硬件上获得低延迟。

      ZeroQuant 通过考虑 system backend 融入算法设计来解决所有这些局限性。我们在 BERT 和大型 GPT-3-style 模型(高达 20B 参数,即 GPT-NeoX_20B )上验证了ZeroQuant 的能力,用于各种任务。

4.1 背景和挑战

  1. 我们在附录 A 中简要概述了 Transformer 架构和量化背景。请参阅 《Attention is all you need》《A survey of quantization methods for efficient neural network inference》 以了解更多关于 Transformer 架构和量化的细节。

  2. QAT 相比,PTQ 展现了更大的压缩效率,因为 PTQ 通常被用于 quantize the model 而无需重新训练。PTQ 的一种常见策略是将训练数据馈入网络,并使用 running mean 来校准 scaling factor S 。更多细节请参见附录 B.1

    一些工作已经在 BERT_base 模型上完成,使用 INT8 权重和混合 INT8/FP16activation 量化。然而,还没有针对:

    • (1)BERT 模型上的更 bit-precisionPTQ 进行研究。

    • (2) : 大型 GPT-3-style 模型进行研究。

    这里,我们简要讨论在 BERT (见附录 C )和 GPT-3-style 模型上应用 PTQ 的挑战。

    Table 1 显示了带 PTQGPT-3_350M 的结果。可以看出:

    • INT8 activation quantization (即 W16A8 的行)引起了主要的 accuracy loss

    • 进一步将权重推到 INT8 (即 W8A8 的行)不改变 zero-shot 评估任务的准确率,但导致因果语言建模任务(Wikitext-2 )的困惑度得分变差;这表明与其他 zero-shot 问题相比,生成式任务的敏感性。

    • 对于 W4/8A16 ,在一些 accuracy-based 的任务上,GPT-3350M 仍然达到了合理的性能,如 OpenBookQA ;但它在大多数其余任务上损失了准确率。特别是对于 Wikitext-2 ,具有 W4/8A16GPT-3_350M 无法再生成任何有意义的文本。

    BERT 的分析请参见附录 C

    WaAb 表示:对权重采用 a-bit、对 activation 采用 b-bit

    W4/8A16 表示:对权重混合采用 4-bit8-bit 、对 activation 采用 16-bit 。其中,将自注意力计算的权重量化为 INT8feed-forward connection: FFC 的权重量化为 INT4

    W8A8/16 表示:对权重采用 8-bit、对 activation 混合采用 8-bit16-bit 。其中,将自注意力计算的 input activation 使用 FP16 activation ,对其余计算使用 INT8

  3. Dynamic Activation Range:为了研究为什么 INT8 activationBERTGPT-3-style 模型都导致显著的准确率下降,我们在 Figure 1(left) 中绘制了 GPT-3_350M 不同 Transformer layers 的每个 activationtoken-wise (即,行维度)的 range 。可以看出,不同 token 具有极大的 activation ranges 差异。例如,最后一层的 maximum range 约为 35、而 minimum range 接近 8 。这种 activation range 的较大方差使得使用固定的 quantization range (通常是最大值)对所有token 进行量化以保持预测准确率变得困难,因为对于 small range tokenslimited representation 能力会损害准确率性能。

  4. Different Ranges of Neurons in Weight Matrices:类似地,我们在 Figure 1(right) 中绘制了 GPT-3_350Mattention output matrix (即,Wo )的逐行(即 output dimension) )的 weight range 。不同行之间的 largest magnitudes 存在 10 倍的差异,这导致 INT8 weight PTQgeneration 性能变差。当应用 INT4 量化时,这也提出了很大的挑战,因为 INT4 只有 16 个数字,更小 10 倍的范围导致这些 smaller-range rowsrepresentations 只有 23 个数字。

  5. 这些分析结果也表明了为什么需要更昂贵的 hidden-states knowledge distillation 来进行 ultra-low precision quantization 以弥合准确率差距。但是,由于大型模型的训练成本太高,因此需要一个轻量级的和高效的方法进行 PTQ

4.2 方法

4.2.1 细粒度的硬件友好的量化方案

  1. 如前所述,即使对 BERT/GPT-3-style 模型应用 INT8 PTQ 也会导致显著的准确率下降。关键挑战是 INT8representation 并不能完全捕获权重矩阵中不同行的、以及不同 activation tokens 的数值范围。一种解决方法是对权重矩阵(或 activations )采用 group-wise (token-wise) quantization

  2. Group-wise Quantization for Weightsgroup-wise weight matrix quantization 首先在 《Q-BERT: Hessian based ultra low precision quantization of bert》 中被提出,其中权重矩阵 WRn×m 被划分为 g 个组,每个组分别被量化。然而,在 《Q-BERT: Hessian based ultra low precision quantization of bert》 中,作者仅将此应用于 quantization aware training 。更重要的是,他们没有考虑硬件效率约束(hardware efficiency constraint ),也没有系统后端支持。因此,他们缺乏真实的 latency reduction 效益。

    在我们的设计中,我们考虑了 Ampere ArchitectureGPU (例如 A100 )的硬件约束,其中计算单元基于 Warp Matrix Multiply and Accumulate (WMMA) tiling size《Using tensor cores in cuda fortran》)从而实现最佳加速。接下来,我们将展示,与 single-matrix quantization 相比,我们的 group-wise quantization 由于更细粒度的量化而具有更好的准确率,同时仍然实现了很大的 latency reduction

    group-wise weight matrix quantization 是怎么实现的?读者猜测是对权重矩阵按照 g 列一个 block 来进行量化。

    g 选择什么样的值?论文并未说清楚。

  3. Token-wise Quantization for Activations:如前面内容和附录 A.2 所述,现有 PTQ 工作的一种常见做法是:对 activation 使用静态量化,其中 min/max range 在离线校准阶段(offline calibration phase )计算。这种方法对于 activation range 方差较小的小型模型可能就足够了。然而,正如前面分析的那样,对于 GPT-3_350MBERT_base 等大型 Transformer 模型,activation range 存在巨大的方差。因此,静态量化方案(通常应用于所有 tokens/samples )会导致显著的准确率下降。克服这个问题的一个自然想法是:采用更细粒度的 token-wise quantization ,并为每个 token 动态地计算 min/max range 以减少来自 activations 的量化误差。我们在实验部分的评估也显示了 token-wise quantizationGPT-3-styleBERT 模型的准确率有显著改善。

    token-wise quantization 是怎么实现的?读者猜测:是对 activation 矩阵按行进行量化。

    然而,直接在现有的深度学习框架(如 PyTorch quantization suite )中应用 token-wise quantization 会导致显著的 quantization and dequantization 成本,因为token-wise quantization 引入了额外的操作,这些操作导致 GPU 计算单元和主内存(main memory)之间的昂贵的数据移动开销。为解决此问题,我们为 transformer 模型的 token-wise quantization 构建了一个高度优化的推理后端(inference backend)。例如,ZeroQuant 的推理后端采用所谓的 kernel fusion 技术,将 quantization operator 与其前面的算子(如 layer normalization )融合,以减轻 token-wise quantization 带来的数据移动成本。类似地,不同 GeMM's output 的逆量化成本,通过如下方式缓解:在将 final FP16 result 写回主内存以供下一个 FP16 算子(如 GeLU )使用之前,使用 weight and activation quantization scalesINT32 accumulation 进行缩放。这些优化将在接下来详细讨论。

    token-wise quantization 可以显著减少 quantized activationsrepresentation error 。而且,由于它不需要校准 activation range,接下来我们将展示对于中等量化方案( INT8 weight with INT8 activation ),ZeroQuant 不会产生任何与量化相关的成本(例如 activation range calibration )。

    注意,论文实验部分提到,对于大型模型(如 GPT-NeoX_20B ),需要将自注意力的 input activation 保持为 FP16 。如果将自注意力的 input activation 量化为 INT8 甚至 INT4,则会带来 accuracy loss

4.2.2 Layer-by-layer Knowledge Distillation with Affordable Cost

  1. 知识蒸馏(knowledge distillation: KD )是减轻模型压缩后准确率下降的最强大方法之一。然而,KD 存在几个局限性,特别是在大型语言模型上的 hidden-states KD

    • (1)KD 需要在训练期间同时持有 teacher 模型和 student 模型,这大大增加了内存和计算成本。

    • (2)KD 通常需要 full training 学生模型。因此,需要在内存中存储权重参数的若干副本(梯度、一阶动量、二阶动量等)以更新模型。

    • (3)KD 通常需要原始训练数据,而由于隐私/保密问题,有时无法访问这些数据。

    为解决这些局限性,我们提出了 layer-by-layer distillation: LKD 算法。假设要量化的目标模型有 Ntransformer blocksL1,,LN ,可访问的数据集有输入 (X,Y),可以是原始训练数据,也可以是来自其他数据源的数据集、甚至是随机生成的数据。我们的 LKD 逐层地对网络进行量化,并使用其原始版本(即 unquantized 版本)作为 teacher 模型。

    具体而言,假设层 Lk 将要被量化,其 quantized 版本是 L^k 。然后,我们使用 Lk1 的输出(即在 first k-1 layers 上对 X 进行推理)分别作为 LkL^k 的输入,测量 LkL^k 输出之间的差异,并对 L^k 进行模型更新,即:

    (29)LLKD,k=MSE(Lk(Lk1(L1(X))),L^k(Lk1(L1(X))))

    其中: MSE 是均方误差,也可以替换为其他损失函数(例如 KL 散度)。

    可以看出:

    • (1) :我们的 LKD 不需要单独的 teacher 模型,因为我们对 teacher/student 模型都使用相同的 L1Lk1 。因此,我们的额外模型成本只有 Lk

      每次仅仅调整 quantized 版本的一层,因此是一种贪心算法。

    • (2)optimizer states 的内存开销显著减少,因为唯一优化的层是 Lk

    • (3):由于我们从不优化 end-to-end model ,训练不再依赖标签。后面我们将在实验章节中展示 LKD 不依赖于原始训练数据。

      论文的实验部分展示:即使采用随机生成的 token idsLKD 也能够提升模型的性能。

      从实验部分可以看到:LKD 对于生成式任务的提升,相比分类任务,要更大。

4.2.3 Quantization-Optimized Transformer Kernels

  1. 优化 inference latency 和模型大小对于实际部署大型 Transformer 模型至关重要。在推理期间,batch size 通常相对较小,所以模型的 inference latency 主要取决于从主内存加载所需推理数据的时间。通过将 weights and activations 量化为较低精度,我们减少了加载这些数据所需的数据量,这允许更有效地利用内存带宽、以及更高的加载吞吐量。但是,简单地将 weights/activations 转换为 INT8 并不能保证改善延迟,因为存在一些与 quantization/dequantization 操作相关的额外的数据移动开销,如 Figure 2 所示的红色框。这样的开销变得昂贵,在某些情况下超过了使用低精度的性能收益。

    为了获得 token-wise quantization 带来的准确率提升和延迟改善,我们现在介绍我们的优化:通过最大化内存带宽利用率(memory bandwidth utilization )来加速 ZeroQuantinference latency

  2. CUTLASS INT8 GeMM:为支持 INT8 计算, 我们使用针对不同 batch sizes进行了调优的 CUTLASS INT8 GeMM 实现。与标准 GPU 后端库(如 cuDNN )不同,使用 CUTLASS 允许我们更灵活地在 GeMM 之前和之后融合量化操作,以减少 kernel launching 和数据移动的开销。

  3. Fusing Token-wise Activation Quantizationtoken-wise quantization/dequantization 引入了许多额外的操作,导致额外的数据移动成本。为消除这些成本,我们使用 kernel fusion,将 activation 的量化操作与其前面的 element-wise and/or reduction 操作(如 bias-add, GeLU, and LayerNorm )融合为单个算子,如 Figure 2 中的绿色框所示。对于逆量化操作(例如逆量化来自 GeMM 算子的 integer output ),我们类似地将其与我们的自定义 GeMM schedule 融合,从而避免额外的 read/write 访问主内存,如 Figure 2 中的蓝色框所示。

  4. 通过上述优化,我们能够在实验章节中展示 BERTGPT-3-style 模型的显著的延迟减少。有关我们的系统优化的更多细节,请参见附录 D

4.3 实验

  1. 为评估提出的 ZeroQuant ,我们在 BERTGPT-3 模型上测试它。

    • 对于 BERT ,我们在 GLUE benchmark 中测试了 BERT_baseBERT_large

    • 对于 GPT-3-style 模型,我们在 20zero-shot 评估任务上测试了 GPT-3_350M (即具有 350M 参数的 GPT-3-style 模型)和 GPT-3_1.3B (即具有 1.3B 参数的 GPT-3-style 模型),包括 19accuracy-based 任务和 1language modeling generation 任务。

    为了展示提出的 ZeroQuant 的可扩展性,我们还直接将其应用于两个最大的开源 GPT-3-style 模型,即 GPT-J_6BGPT-NeoXP20B。对于所有与 LKD 相关的实验,我们使用固定的超参数集合,尽管调优它们可能有利于我们的结果。请参阅附录 B.2 以获得更多关于训练的详细信息,并参阅附录 B.3 以获得报告的 BERT 指标。为提供全面研究,我们还在附录 E 中包括 BERT 的调参结果、以及针对本节中不同的 proposed components 的消融研究。

  2. 符号解释:

    • 我们使用 WxAy 表示对权重使用 x-bit 量化、对 activation 使用 y-bit 量化。

    • 除非特别说明:

      • 对于 W4/8 ,我们将 multi-head self attention: MHSA 的权重量化为 INT8feed-forward connection: FFC 的权重量化为 INT4

      • 对于 A8/16 ,我们对自注意力计算(即与 Wq,Wk,Wv 相关的 GeMM )使用 FP16 activation ,对其余计算使用 INT8

    • 我们使用 ZeroQuant 来表示仅具有细粒度量化方案的方法;使用 ZeroQuant-LKD 来表示同时具有细粒度量化方案和 LKD 的方法。

4.3.1 BERT 的主要结果

  1. BERT_base:我们在 Table 2 中报告 BERT_base 的结果。

    • 对于 W8A8PTQ 的平均准确率降低了 6 分左右。 然而,ZeroQuant 可以达到 83.75 分,仅比基线低 0.2 。 具体而言,由于ZeroQuant 没有 activation range calibration 阶段,其成本为 0 ,甚至比标准 PTQ 更便宜。

      • 《Understanding and overcoming the challenges of efficient transformer quantization》 相比(即,[6](PTQ)),我们的方法获得了更好的平均分数(高出1.29 )。 与此同时,与 ZeroQuant 中使用的 INT8 activation 相比,[6] 使用 mixed INT8 and FP16 activation

      • 我们还将我们的方法与内部训练的 QAT 和其他 QAT 工作(《Q-BERT: Hessian based ultra low precision quantization of bert》,即 [56] (QAT)+《Q8BERT: Quantized 8bit bert》,即 [76] (QAT))进行了比较。可以看出,与那些 QAT 方法获得的准确率结果相媲美,针对 INT8 量化,ZeroQuant 可以将重新训练成本从 2900s 降低到 0s (即,无需重新训练)。

    • 对于更激进的、具有 minimal (or no) training quantization 的权重量化,即 W4/8A16PTQ 完全丢失了所有准确率(纯随机预测)。 然而,ZeroQuant 仍然可以达到 81.65 的平均分数。在 ZeroQuant 的基础上,如果我们添加 LKD ,则准确率可以进一步提升到82.35,每个任务的成本仅为 31s ,仅使用单个 GPU ,与 INT8 QAT 量化相比,节省了 93.5 倍的成本。

  2. BERT_large:我们也在 BERT_large 上测试我们的方法,结果如 Table 3 所示。

    • BERT_base 类似,ZeroQuant 的准确率明显优于 PTQ 方法。与 QAT 方法相比,ZeroQuant 在更大的数据集(如 MNLI/QQP )上具有可比结果,并在小任务(例如 CoLA/MRPC/RTE )上具有更好的性能。我们实际上为 QAT 调优了多个学习率,但即使对于这些小任务也无法获得更好的性能(请参阅附录 F 以获取更多详细信息)。

    • 对于更激进的量化方案,如 W4/8A16W4/8A8ZeroQuantZeroQuant-LKD 仍然达到了很好的准确率,除了 RTE 之外,模型大小约为 FP16 模型的 3 倍。这与 INT8 QAT 结果一致,后者在 RTE 上损失了更多的准确率。由于 LKD 的轻量级成本,即使在 BERT_large 上也只需要大约 550s 就可以完成每个任务,比 QAT 便宜 13 倍。

4.3.2 GPT-3-style 模型的主要结果

  1. GPT-3_350M:我们首先在 GPT-3_350M 上测试 ZeroQuantZeroQuant-LKD ,并在 Table 4 中报告结果。

    • GPT-3-style模型上的 zero-shot 评估的第一个有趣发现是,与生成式任务相比,accuracy-based 任务的 accuracy performance 更能容忍量化。例如,W8A8 PTQ19accuracy-based 的任务上平均准确率下降了 1.1% ,相比之下在 Wikitext-2 上下降 4.7 分。

      W8A8 上,将 ZeroQuantPTQ 进行比较,我们可以将 accuracy gap1.1% 降低到 0.2% ,困惑度(perplexity: PPL )差距从 4.7 降低到 0.2 ,而无需 activation range calibration 成本。

    • 对于 W4/8A16 量化方案,PTQ 几乎无法对大多数任务进行合理预测, 其在Wikitext-2 上的 generation 性能完全崩溃。相比之下,ZeroQuant 在某些任务上仍然取得了重大的性能,但其在 Wikitext-2 上的 generation 性能显著降低。LKD 为这种W4/8A16 setting 带来了显著的性能提升。

      请注意,与 ZeroQuant 相比,ZeroQuant-LKD 将准确率从 33.5 提高到 37.0 ,困惑度从 88.6 降低到 30.6 ,而这全部的成本只有 3.1 小时在单个 A100 GPU 上。请注意,这约为完整预训练成本(128A100 GPU32 小时)的 0.027%GPU hours

    • W4/8A8 上,与 W4/8A16 类似,ZeroQuant-LKD 通过使用轻量级 LKDZeroQuant获得了更好的性能。

    PTQ 为什么需要时间?因为它对 activation 使用静态量化,其中 min/max range 在离线校准阶段(offline calibration phase )计算。

  2. GPT-3_1.3BGPT-3_1.3B 的结果如 Table 5 所示。与 GPT-3_350M 类似:

    • 对于 W8A8 ,与 PTQ 相比,ZeroQuant 的性能更好,无 activation calibration 成本,特别是对于生成式任务 Wikitext-2 (低 3.2 分)。

    • 此外,对于 W4/8A8 量化,LKD 可以为ZeroQuant 带来重大的性能收益。LKD 的成本约为完整预训练成本(128A100 GPU120 小时)的 0.02%

4.3.3 BERT 和 GPT-3-style 模型的延迟降低

  1. 我们在 Table 6 中比较了单个 40G-A100 GPU 上, BERTFP16 版本和我们的 INT8 版本之间的推理速度。通过使用高效的 quantization kernel implementation 和算子融合,INT8 模型可以在 BERT_base 上实现 2.27-5.19 倍的加速,在 BERT_large 上实现 2.47-5.01 倍的加速。

    我们还包括 GPT-3-style 模型在 FP16 和我们的 INT8 版本之间的延迟比较。具体而言,我们使用模型根据给定文本生成 first 50 tokens,并测量平均延迟。与 FP16 版本相比,我们的 INT8 模型在 GPT-3_350M/GPT-3_1.3B 上实现了 4.16x/4.06x 的加速。

4.3.4 GPT-J_6B 和 GPT-NeoX_20B 的展示

  1. 为演示 ZeroQuant 的可扩展性,我们将其应用于两个最大的开源模型,即 GPT-J_6BGPT-NeoX_20B ,它们分别具有 6B20B 参数。

  2. 我们在 Table 7 中报告了 GPT-J_6B 在三个 generation 数据集(即 PTBWikitext-2Wikitext-103 )上的结果。

    • 可以看到,ZeroQuant 在所有三个不同任务上都实现了与 FP16 相差无几的 PPL

    • 为了比较延迟,我们再次使用生成前 50 tokens 的平均延迟数。与 FP16 版本相比,我们的 W8A8 可以获得高达 3.67 倍的加速。

  3. GPT-NeoX_20B 的所有 GeMM 来量化到 W8A8 会导致准确率显著下降。我们检索每个权重矩阵和每个 activation 的量化,并最终发现:注意力计算的 activation quantization (即,自注意力的输入)导致了 accuracy loss 。我们推测这是由于超大模型(20B 参数)中自注意力模块的敏感性造成的,但由于缺乏开源的超大模型和完整的评估流程,我们无法在其他模型上验证这一点。 因此,我们将自注意力的 input activation 保持为 FP16 ,其余部分量化为 INT8 。结果如 Table 8 所示。我们的 W8A8/16 实现了与 FP16 类似的准确率,但可以减少 GPU 资源需求(从 2A100 GPU 减少到 1 个)和延迟(从 65ms 降低到 25ms ),这两者共同导致了 5.2 倍更好的吞吐量/效率。

4.3.5 不同组件的消融研究

  1. 为了研究我们引入的每个组件的性能提升,即 group-wise weight quantizationtoken-wise activation quantization 、以及 lightweight layer-by-layer knowledge distillation ,我们在此对 BERT_large 上的 W4/8A8 进行消融研究。

    我们在 Table 9 中呈现了结果。可以看出:

    • group-wise weight quantization 将准确率从 PTQ (随机猜测预测)提升到一个重大的结果(66.52 )。

    • 进一步添加 token-wise quantization 可以提高 14.54 分的准确率。

    • 在这些基础上(即 ZeroQuant ),LKD 进一步带来了 0.56 分的提升。

4.3.6 无法访问原始训练数据

  1. 如前几节所述,由于隐私和/或保密问题,原始训练数据通常很难访问。因此,我们这里研究当没有直接访问原始训练数据时,我们的LKD 的性能。由于 LKD 的蒸馏目标不依赖标签,LKD 使用的训练数据可以非常灵活。

    我们使用三种不同的训练数据资源,从而比较 GPT-3_350MW4/8A8 量化方案上的性能:即,随机数据(使用随机整数编号生成 token ids)、维基百科(使用 Huggingface 获取数据)、原始 PILE 数据集。结果如 Table 10 所示。

    • ZeroQuant 相比,使用随机数据的 LKD 可以将准确率提高 1.1% ,困惑度从 92.1 降低到 40.6 。随机数据仍然可以显著提高性能的原因是:LKD 不优化 end-to-end pipeline ,而是仅逐层学习来自 teacher 模型的内部依赖关系。因此,随机数据也可以提供有意义的信息。

    • 使用 HuggingfaceWikipedia 数据可以进一步将准确率提高到 36.2 ,困惑度降低到 30.4 ,这与使用原始数据的结果相当。这表明,当我们无法访问完整的原始数据集时,可以使用干净的文本数据集进行 LKD

五、SmoothQuant [2022]

论文:《SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models》

  1. 大型语言模型(LLM )在各种任务上展示了出色的性能。然而,由于模型规模巨大,部署 LLM 需要大量的预算和能源。例如,GPT-3 模型包含 175B 参数,至少需要 350GB 内存来存储和以 FP16 运行,仅进行推理就需要 8 * 48GB A6000 GPU5 * 80GB A100 GPU 。由于巨大的计算和通信开销,inference latency 也可能无法被实际应用所接受。量化是减少 LLM 成本的有希望的方法(《Llm.int8(): 8-bit matrix multiplication for transformers at scale》《Zeroquant: Efficient and affordable post-training quantization for large-scale transformers》)。通过用 low-bit 整数来量化权重和 activations ,我们可以减少 GPU 内存需求(大小和带宽),并加速计算密集型操作(即,线性层中的 GEMM 和注意力中的 BMM )。例如,与 FP16 相比,权重和 activationsINT8 量化可以将 GPU 内存使用量减半,矩阵乘法的吞吐量提高近一倍。

    然而,与 CNN 模型或较小的 transformer 模型如 BERT 不同,LLMactivations 很难量化。当我们将 LLM 扩展到超过 6.7B 参数时, activations 中会涌现系统性的大幅值的异常值(《Llm.int8(): 8-bit matrix multiplication for transformers at scale》),导致较大的量化误差和精度下降。

    • ZeroQuant 应用了 group-wise weight quantization 和动态的 per-token activation quantization(参考 Figure 3 )。它可以高效地实现,并为 GPT-3-350MGPT-J-6B 提供良好的准确率。但是,它无法为具有 175B 参数的大型 OPT 模型维持准确率。

    • LLM.int8() 通过进一步引入混合精度分解(即它将异常值保持为 FP16 ,其他 activations 使用 INT8 )来解决该准确率问题。但是,在 hardware accelerators上高效地实现该分解很困难。

    因此,为 LLM 派生出一种高效的、硬件友好的、最好不需要训练的量化方案,该方案会对所有计算密集型操作使用 INT8 ,仍是一个开放性挑战。

    我们提出了 SmoothQuant,这是一种准确的、高效的后训练量化(post-training quantization: PTQ )解决方案从而用于 LLMSmoothQuant 依赖于一个关键观察:由于存在异常值,即使 activations 比权重更难量化,不同 tokens 在其 channels 上表现出类似的变化。基于此观察,SmoothQuant 离线地将quantization difficultyactivations 迁移到权重(Figure 2 )。 SmoothQuant 提出了一种数学等价的 per-channel scaling transformation,可以显著平滑通道间的幅值,使模型对量化更加友好。由于SmoothQuant 兼容各种量化方案,我们为 SmoothQuant 实现了三种效率级别的 quantization setting (见 Table 2O1-O3 )。实验表明,SmoothQuant 具有硬件效率:它可以维持 OPT-175BBLOOM-176BGLM-130BMT-NLG 530B 的性能,在 PyTorch 上获得高达 1.51 倍的加速和 1.96 倍的内存节省。SmoothQuant 易于实现。我们将 SmoothQuant 集成到 FasterTransformer 中(这是 SOTAtransformer serving 框架),与 FP16 相比,实现了高达 1.56 倍的加速,以及内存占用减半。值得注意的是,相比较于 FP16SmoothQuant 允许仅使用一半 GPU 数量就可以 servingOPT-175B 等大型模型,而且更快,并可以在单个 8-GPU 节点上部署 530B 模型。我们的工作通过提供一键解决方案来减少 serving 成本,推广了 LLM 的使用。我们希望 SmoothQuant 可以在未来激发 LLM 的更广泛应用。

    注意:SmoothQuant-O1/O2/O3 对权重均采用 per-tensor 量化,区别仅在于 activations 上的量化方式。

  2. 相关工作:

    • 大型语言模型:通过 scaling uppre-trained 语言模型在各种基准测试中实现了显着的性能。GPT-3 是首个超过 100B 参数的LLM ,并在 few-shot/zero-shot learning 中取得了令人印象深刻的结果。后续工作继续推进 scaling 的前沿,超过了500B 参数。但是,随着语言模型变大,为这些模型提供推理变得昂贵和具有挑战性。在本文中,我们展示了所提出的方法可以量化三个最大的开源 LLMOPT-175BBLOOM-176BGLM-130B ),甚至 MT-NLG 530B ,以减少内存成本和加速推理。

    • 模型量化:量化是减小模型规模和加速推理的有效方法。它对各种卷积神经网络和 transformer 都被证明是有效的。 weight equalization《Data-free quantization through weight equalization and bias correction》)和 channel splitting《Improving neural network quantization without retraining using outlier channel splitting》)通过抑制权重中的异常值来减小量化误差。但是,这些技术无法解决 activation outliers ,这是 LLM 量化的主要瓶颈(《Llm.int8(): 8-bit matrix multiplication for transformers at scale》)。

    • LLM 的量化:

      • 《Gptq: Accurate post-training quantization for generative pretrained transformers》 仅对权重而不是 activations 进行量化(请参阅附录 A 的简短讨论)。

      • ZeroQuant《Zeroquant: Efficient and affordable post-training quantization for large-scale transformers》)和 nuQmm《nuqmm: Quantized matmul for efficient inference of large-scale generative language models》)为 LLM 使用 per-token (在 activations 上)和 group-wise (在 weights 上)的量化方案,需要定制的 CUDA kernels 。它们分别评估的最大模型为 20B2.7B ,未能维持 OPT-175BLLM 的性能。

      • LLM.int8()《Llm.int8(): 8-bit matrix multiplication for transformers at scale》)使用混合 INT8/FP16 decomposition 来处理 activation outliers 。但是,这样的实现导致很大的延迟开销,甚至比 FP16 推理更慢。

        6.7B 及其以上规模的模型中,LLM.int8() 的推理速度比 FP16 更快;而更小规模的模型中,LLM.int8() 反而更慢。

      • Outlier Suppression《Outlier suppression: Pushing the limit of low-bit transformer language models》)使用 non-scaling Layer-Normtoken-wise clipping 来处理 activation outliers 。但是,它只在小型语言模型(如 BERTBART )上成功,未能维持 LLM 的准确率(Table 4 )。

      我们的算法以高效的 per-tensor 的、静态的量化方案保留了LLM 的性能(高达 176B ,我们能找到的最大的开源 LLM ),而无需重新训练,允许我们使用开箱即用的 INT8 GEMM 来实现高的硬件效率。

      Table 4 可以看到,LLM.int8() 的效果相当好,和表现最佳的 SmoothQuant 相比相差无几甚至更好。而且在 175B 模型上,LLM.int8() 的推理速度可以高达 2 倍(相比于 FP16)。

5.1 背景知识

  1. 量化将一个 high-precision value 映射到离散级别(discrete levels)。我们研究整数(具体为 INT8 )的 uniform quantization《Quantizationand training of neural networks for efficient integer arithmetic-only inference 》)以获得更好的硬件支持和效率。量化过程可以表示为:

    (30)X¯INT8=XFP16Δ,Δ=max(|XFP16|)2N11

    其中:

    • XFP16 是浮点张量,X¯INT8 是量化后的张量。

    • Δ 为量化步长(quantization step size),rounding 函数,Nbits 数量(在我们这个 case 中是 8 )。

    这里为简单起见,假设张量 X 是关于零对称的。对于非对称的情况(如经过 ReLU 非线性函数之后),通过添加一个 zero-point ,讨论过程是类似的(《Quantization and training of neural networks for efficient integer arithmetic-only inference》)。

    这样的量化器(quantizer )使用 maximum absolute value 来计算 Δ,以保留 activation 中的异常值,这些异常值对精度很重要(《Llm.int8(): 8-bit matrix multiplication for transformers at scale》)。

    • 我们可以用一些 calibration samplesactivations 来离线地计算 Δ,我们称之为静态量化(static quantization )。

    • 我们也可以使用 activations 的运行时统计信息(runtime statistics )得到 Δ,我们称之为动态量化(dynamic quantization )。

    Figure 3 所示,量化具有不同的粒度级别:

    • per-tensor quantization 对整个矩阵使用单个步长。

    • 通过为每个 token 相关联的 activations(per-token quantization )、或权重的每个 output channel 相关联的 activationsper-channel quantization )使用不同的量化步长,我们可以实现更细粒度的量化。

      per-channel quantization 的一个粗粒度版本是对不同的 channel groups 使用不同的量化步长,称为 group-wise quantization《Q-bert: Hessian based ultra low precision quantization of bert》《Zeroquant: Efficient and affordable post-training quantization for large-scale transformers》)。

    通俗地讲:

    • per-tensor 量化:对矩阵(权重矩阵或者 activation 矩阵)采用单个步长。

    • per-channel 量化:对权重矩阵按列量化,即每一列对应一个步长。

    • per-token 量化:对 activation 矩阵按行量化,即每一行对应一个步长。

  2. 对于transformer 中的线性层(参见 Figure 3 ,为简单起见,我们省略了 batch 维度):

    (31)Y=XW

    其中:

    • XRT×Ciinput activationsTtoken 数量,Ci 为输入通道数量。

    • WRCi×Co 为权重矩阵,Co 为输出通道数。

    • YRT×Cooutput activations

    通过将权重量化为 INT8 ,相比 FP16 ,我们可以将模型存储量减半。但是,为了加速推理,我们需要将权重和 activations 都量化为 INT8 (即 W8A8 ),从而利用 integer kernels (如 INT8 GEMM ),这些 integer kernels 被广泛的硬件所支持(如NVIDIA GPUIntel CPUQualcomm DSP 等)。

5.2 回顾 Quantization Difficulty

  1. 由于 activations 中的异常值,LLM 难以量化。我们首先回顾 activation quantization 的困难,并在异常值中寻找模式。我们在 Figure 4(Left) 中可视化了具有较大 quantization error 的线性层的 input activations 和权重。我们可以找到几个启发我们方法的模式:

    • (1)activations 比权重更难量化。

      权重分布非常均匀和平坦,很容易量化。先前的工作表明,使用 INT8 甚至 INT4 来量化 LLM 的权重,不会降低准确性,这与我们的观察一致。

    • (2):异常值使 activation quantization 困难。

      activation 中的异常值的 scale 比大多数 activations 大约高 100 倍。在 per-tensor quantization 的情况下,large outliers 主导 maximum magnitude 的测量,导致 non-outlier channelseffective quantization bits/levels 较低(Figure 2 ):假设通道 imaximum magnitudemi ,整个矩阵的最大值为 m ,则通道 ieffective quantization levels28×mim。对于 non-outlier channelseffective quantization levels 将非常小(2-3 ),导致较大的量化误差。

      即,在 non-outlier channels 上,量化后的结果都聚集在少数的 bins 上,导致逆量化之后都集中在少数几个值上。

    • (3):异常值出现在固定的通道中。

      对于 activations ,异常值仅出现在少数通道中。如果一个通道有一个异常值,它会持续出现在所有 tokens 中( Figure 4 ,红色)。

      • 给定一个 token ,它的各个通道之间的 activations 方差很大(某些通道中的 activations 非常大,但大多数很小)。

      • 但给定一个通道,它的跨 tokens 之间的 activations 方差很小(异常值通道中的 activations 一致地很大)。

  2. 由于异常值的 persistence 、以及每个通道内的小方差,如果我们可以对 activation 进行 per-channel quantization《Understanding and overcoming the challenges of efficient transformer quantization》)(即对每个通道使用不同的量化步长),与 per-tensor quantization 相比,量化误差会小得多,而 per-token quantization 几乎没有帮助。在Table 1 中,我们验证了假设:模拟的 per-channel activation quantization 成功地与FP16 baseline 实现了准确率一致。这与《Understanding and overcoming the challenges of efficient transformer quantization》 的发现一致。

    对于 activationsper-token quantization 就是按行进行量化,per-channel quantization 就是按列进行量化。

    为什么说这里是 “模拟” 的?因为目前的硬件不支持 activationsper-channel quantization ,因此作者采用模拟的手段来实现相同的效果。

  3. 然而,per-channel activation quantization 与硬件加速的 GEMM kernels 不匹配,这些 GEMM kernels 依赖于高吞吐量地执行的 a sequence of operations(如 Tensor Core MMAs ) ,并且不容忍在该序列中插入吞吐量较低的指令(例如,转换、或 CUDA Core FMAs )。在这些 kernels 中,scaling 只能沿矩阵乘法的 outer dimensions 执行(即 activationstoken dimension T 、权重的 output channel dimension Co ,见 Figure 3 )。这种 scaling 通过在矩阵乘法完成后应用如下操作来实现:

    (32)Y=diag(ΔXFP16)(X¯INT8W¯INT8)diag(ΔWFP16)

    其中:diag() 表示对角矩阵;X¯W¯ 分别表示量化后的 activations 和权重。

    因此,先前的工作都为线性层使用 per-token activation quantizationLlm.int8(), Zeroquant),尽管它们无法解决 activation quantization 的困难(仅比 per-tensor quantization量略好)。

5.3 SmoothQuant

  1. 我们提出平滑 input activation 而不是执行 per-channel activation quantization (这不可行),方法是将 input activation 除以 per-channel smoothing factor sRCi。为保持线性层的数学等价,我们相应地按相反方向缩放权重:

    (33)Y=(Xdiag(s)1)(diag(s)W)=X^W^

    其中:X^=Xdiag(s)1W^=diag(s)W

    即,对 activation 矩阵的第 i 列除以 si ,同时对权重矩阵的第 i 行乘以 si

    考虑到输入 X 通常来自前面的线性操作(例如 linear layerslayer norms 等),我们可以轻松地将平滑因子(smoothing factor )离线地融合到前一层的参数中,这不会导致 an extra scalingkernel call 的开销。对于其他一些情况,当输入 X 来自 residual add 时,我们可以像 《Outlier suppression: Pushing the limit of low-bit transformer language models》 那样,在 residual branch 中添加 an extra scaling

    关于如何融合平滑因子,可以参考论文的实现代码。

  2. quantization difficultyactivations 迁移到权重:我们的目标是选择 per-channel smoothing factor s ,使得 X^=Xdiag(s)1 易于量化。为减小量化误差,我们应该为所有通道增加 effective quantization bits。当所有通道具有相同的maximum magnitude 时,total effective quantization bits将最大。因此,一个直观的选择是:

    (34)sj=max(|X:,j|),j=1,2,,Ci

    其中 j 对应第 j 个输入通道,sjs 的第 j 个元素。

    这种选择确保在除法之后,所有 activation channels 将具有相同的最大值,很容易量化。注意,activations 的范围是动态的;它对不同的输入样本各不相同。这里,我们使用预训练数据集中的 calibration samples 来估计 activations channelsscale《Quantization and training of neural networks for efficient integer arithmetic-only inference》)。

    然而,这个公式将所有 quantization difficulty 都推到权重上。我们发现,在这种情况下,权重的量化误差会很大(outlier channels 现在迁移到权重上),导致很大的准确率下降(参见 Figure 10)。

    另一方面,我们也可以通过选择 sj=1max(|Wj,:|) 将所有 quantization difficulty 从权重推到 activations 。类似地,由于activation 量化误差,模型性能不佳。因此,我们需要在权重和 activations 之间分担 quantization difficulty ,以使它们都易于量化。

    这里我们引入一个超参数,迁移强度(migration strengthα ,来控制我们要从 activations 迁移到权重的难度量,使用以下等式:

    (35)sj=max(|X:,j|)αmax(|Wj,:|)1α

    我们发现,对于大多数模型(例如所有的 OPTBLOOM 模型),α=0.5 是一个很好的平衡点,可以均匀地分担 quantization difficulty ,尤其是在我们对权重和 activations 使用相同的 quantizer 时(例如 per-tensor 的静态量化)。该公式确保权重和 activations 在相应的通道上共享相似的最大值,因此共享相同的 quantization difficultyFigure 5 说明了当我们取 α=0.5 时的 smoothing transformation 。 对于 activation outliers 更明显的一些其他模型(例如 GLM-130B 有约 30% 的异常值,这对 activation quantization 更具挑战性),我们可以选择较大的 α 从而将更多 quantization difficulty 迁移到权重(如 α=0.75 )。

  3. SmoothQuant 应用于 Transformer blocks :线性层占了 LLM 模型的参数和计算的大部分。默认情况下,我们对自注意力和前馈层的 input activations 执行 scale smoothing ,并使用 W8A8 量化所有线性层。我们还量化注意力计算中的 BMM 算子。我们在 Figure 6 中设计了 transformer 模块的量化流程。我们使用 INT8 quantization 计算 compute-heavy 的算子(如线性层和注意力层中的 BMM )的输入和权重,而将其他轻量级 element-wise 算子(如 ReLUSoftmaxLayer-Norm )的 activation 保持为FP16 。这种设计帮助我们在精度和推理效率之间取得平衡。

    BMMbatchmatrix-matrix 乘法。

5.4 实验

  1. baselines:我们在 INT8 post-training quantization setting(即,不重训模型参数)中与四个基准进行比较:W8A8 naive quantizationZeroQuantLLM.int8()Outlier Suppression

    由于 SmoothQuant 与量化方案正交,我们提供从 O1O3 逐渐激进的和有效的 quantization levels 。基准和 SmoothQuant 的详细量化方案如 Table 2 所示。

  2. 模型和数据集:

    • 我们选择三个 LLM 系列来评估 SmoothQuantOPTBLOOMGLM-130B

    • 我们使用七个 zero-shot evaluation tasksLAMBADAHellaSwagPIQAWinoGrandeOpenBookQARTECOPA,以及一个语言建模数据集 WikiText 来评估 OPTBLOOM 模型。

      我们使用 MMLUMNLIQNLILAMBADA 来评估 GLM-130B 模型,因为上述一些基准出现在 GLM-130B 的训练集中。

    • 我们使用 lm-eval-harness 来评估 OPTBLOOM 模型,使用 GLM-130B 的官方仓库评估其本身。

    • 最后,我们将方法扩展到 MT-NLG 530B,首次在单节点内实现了对大于 500B 模型的 serving

    注意,我们关注量化前后模型的相对性能变化而不是绝对值变化。

  3. Activation smoothing:迁移强度 α=0.5 是所有 OPTBLOOM 模型的通用最佳点;而对于量化更具挑战性的 activationsGLM-130Bα=0.75 。我们在 Pile 验证集的一个子集上快速 grid search 以获得合适的 α。为了获得 activations 的统计信息,我们一次性地使用预训练数据集 Pile 中的 512 个随机句子,从而校准 smoothing factorsstatic quantization step sizes,并将相同的 smoothed and quantized model 应用于所有下游任务。通过这种方式,我们可以 benchmark 量化后的 LLM 的普适性和zero-shot 性能。

  4. 实现:我们使用两个后端实现 SmoothQuant

    • (1)PyTorch Huggingface 进行概念验证。

    • (2)FasterTransformer 作为生产环境中使用的高性能框架的示例。

    PyTorch HuggingfaceFasterTransformer 框架中,我们都使用 CUTLASS INT8 GEMM kernels 实现了 INT8 线性模块和 batched matrix multiplication: BMM函数。我们简单地用我们的 INT8 kernels 替换原始的浮点(FP16 )线性模块和 bmm 函数,从而作为 INT8 模型。

5.4.1 准确的量化

  1. OPT-175B 的结果:SmoothQuant 可以处理非常大的 LLM 的量化,其中,这种大型 LLMactivations 更难以量化。我们在 OPT-175B 上研究量化。如 Table 3 所示:

    • SmoothQuant 可以在所有评估数据集上在所有量化方案上匹配 FP16 的准确率。

    • LLM.int8() 可以匹配浮点的准确率,因为他们使用浮点值来表示异常值,这会导致很大的延迟开销(Table 10)。

    • W8A8ZeroQuantOutlier Suppressionbaselines 产生几乎随机的结果,表明朴素地量化 LLMactivation 将破坏性能。

    在这三种 SmoothQuant 变体中,SmoothQuant-O3 的实现最简单(静态的 per-tensor 量化),但是效果也还不错。

  2. 不同 LLM 的结果:SmoothQuant 可以应用于各种 LLM 。在 Table 4 中,我们展示 SmoothQuant 可以量化所有现有的超过 100B 参数的开源 LLM

    • OPT-175B 模型相比,BLOOM-176B 模型更容易量化:没有 baselines 完全破坏模型;即使是朴素的 W8A8 per-tensor dynamic quantization 也只降低了 4% 的准确率。

      SmoothQuantO1-levelO2-level 成功地维持了浮点的准确率,而 O3-levelper-tensor static)降低了平均准确率 0.8% ,我们将其归因于统计信息与真实评估样本 activation statistics之间的差异。

    • 相反,GLM-130B 模型更难以量化(《Glm-130b: An open bilingual pre-trained model》相呼应)。尽管如此,SmoothQuant-O1 可以匹配 FP16 的准确率,而 SmoothQuant-O3 的准确率只降低了 1% ,明显优于 baselines 。注意,在为 GLM-130B 校准 static quantization step sizes 时,我们按照 《Outlier suppression: Pushing the limit of low-bit transformer language models》 的方法裁剪了 top 2% tokens

    注意,不同的模型/训练设计具有不同的 quantization difficulty ,我们希望这能激发未来的研究。

    注意:对于给定的量化方法,即使它在某个大模型上表现较好,也无法断定它在另一些大模型上表现也好。例如,ZeroQuantBLOOM-176B 上表现较好,但是在 OPT-175B 上表现很差。

  3. 不同大小的 LLM 的结果:SmoothQuant 不仅适用于超过 100B 参数的非常大的 LLM ,而且也适用于较小的 LLM 。在 Figure 7 中,我们展示 SmoothQuant 可以适用于所有规模的 OPT 模型,使用 INT8 quantization 匹配 FP16 的准确率。

  4. Instruction-Tuned LLM 的结果:如 Table 5 所示,SmoothQuant 也适用于Instruction-Tuned LLM 。我们在 OPT-IML-30B 模型上使用 WikiText-2LAMBADA 数据集测试 SmoothQuant 。我们的结果表明:SmoothQuant 成功地以 W8A8 quantization 保留了模型准确率,而 baselines 未能做到这一点。SmoothQuant 是为 transformer 模型平衡 quantization difficulty 而设计的通用方法。由于Instruction-Tuned LLM 的架构与普通 LLM 在本质上没有不同,它们的预训练过程也非常相似,因此 SmoothQuant 也适用于Instruction-Tuned LLM

  5. LLaMA 模型的结果:LLaMA 模型是具有卓越性能的新的开源语言模型。通过初步实验,我们发现:与 OPTBLOOM 等模型相比,LLaMA 模型通常具有更轻度的 activation outlier 问题。尽管如此,SmoothQuantLLaMA 模型仍然非常有效。我们在 Table 6 中给出了 LLaMA W8A8 quantization 的一些初步结果。W8A8 SmoothQuant 的性能与 FP16 baseline 相差无几。

5.4.2 加速和内存节省

  1. 在这一节中,我们展示了集成到 PyTorchFasterTransformer 中的 SmoothQuant-O3 所测量到的加速和内存节省。

  2. Context-stage: PyTorch Implementation:针对 a batch of 4 sentences ,我们测量在 one pass 中生成所有隐状态的端到端延迟,即上下文阶段延迟(context stage latency)。我们记录此过程中的(聚合后的)峰值 GPU 内存使用。我们仅将SmoothQuantLLM.int8() 进行比较,因为后者是唯一可以在所有规模上保持LLM 准确率的现有量化方法。

    由于 Huggingface 不支持模型并行,针对 PyTorch 实现,我们只在单 GPU 上测量 SmoothQuant 的性能,因此我们选择 OPT-6.7BOPT-13BOPT-30B 进行评估。

    FasterTransformer 库中,SmoothQuant 可以与张量并行算法无缝协作,所以我们同时针对单 GPU 和多GPU 基准测试,在 OPT-13BOPT-30BOPT-66BOPT-175B 上测试 SmoothQuant

    我们的所有实验都是在 NVIDIA A100 80GB GPU 服务器上进行的。 Figure 8 显示了基于 PyTorch 实现的inference latency 和峰值内存使用。可以看到:

    • SmoothQuant 始终比 FP16 baseline 更快,在序列长度为 256 时,在 OPT-30B 上获得了 1.51 倍的加速。我们还看到,模型越大,加速越明显的趋势。

    • 另一方面,LLM.int8() 几乎总是比 FP16 baseline 慢,这是由于 mixed-precision activation representation 的大开销。

    • 在内存方面,SmoothQuantLLM.int8() 都将 FP16 模型的内存使用减少了近一半,而 SmoothQuant 节省的内存略多,因为它使用 fully INT8 GEMMs

  3. Context-stage: FasterTransformer Implementation :如 Figure 9 (top) 所示,与 OPTFasterTransformer's FP16 实现相比,SmoothQuant-O3 可以将单 GPU 上,将 OPT-13BOPT-30B 的执行延迟降低最多 1.56 倍。这具有挑战性,因为与PyTorch 实现相比,FasterTransformerOPT-30B 已经快了 3 倍以上。

    值得注意的是,对于必须跨多个 GPU 分配的更大模型,SmoothQuant 使用仅一半数量的 GPU (对于OPT-66B,只需要 1GPU 而不是 2 个;对于 OPT-175B ,只需要 4GPU 而不是 8 个)实现了类似甚至更好的延迟。这可以大大降低 serving LLM 的成本。

    Figure 9 (bottom) 显示,在 FasterTransformer 中使用 SmoothQuant-O3 时所需的内存减少了近 2 倍。

  4. Decoding-stage:在 Table 7 中,我们展示 SmoothQuant 可以显著加速 LLM 的自回归解码阶段。

    • FP16 相比,SmoothQuant 一致地降低 per-token decoding延迟(最高 1.42 倍加速)。

    • 此外,SmoothQuantLLM 推理的内存占用减半,使 LLM 部署的成本大大降低。

5.4.3 Scaling Up: 单节点内的 530B 模型

  1. 我们可以进一步将 SmoothQuant 扩展至超过 500B 级别的模型,实现 MT-NLG 530B 的高效的和准确的 W8A8 quantization 。如 Table 8Table 9 所示,SmoothQuant 实现了 530B 模型在可忽略的准确率损失下的W8A8 quantization 。减小的模型大小允许我们使用一半数量的 GPU (从 16 GPU8 GPU )来 serve 模型,在类似延迟下,实现了单节点(8 * A100 80 GPU )内 serving 大于 500B 模型。

5.4.4 消融实验

  1. 量化方案:Table 10 基于我们的 PyTorch 实现显示了不同量化方案的inference latency 。我们可以看到:

    • 量化粒度越粗(从 O1O3 ),延迟越低。

    • 静态量化与动态量化相比可以显著加速推理,因为我们不再需要在运行时计算量化步长。

    • SmoothQuant 在所有设置下都比 FP16 baseline 快,而 LLM.int8() 通常更慢。

    如果准确率允许,我们建议使用更粗粒度的方案。

  2. 迁移强度:我们需要找到合适的迁移强度 α 来平衡权重和 activations 之间的 quantization difficulty 。我们在 Figure 10 中检验不同 αOPT-175BLAMBADA 的影响。

    • α 太小(小于 0.4 )时,activations 难以量化。

    • α 太大(大于 0.6 )时,权重难以量化。

    • 只有当我们从最佳区域(0.4 ~ 0.6 )选择 α 时,我们才能获得权重和 activations 的小的量化误差,并在量化后保持模型性能。

六、GPTQ [2022]

论文:《GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers》

  1. 来自 Transformer 家族的 pretrained 生成式模型(如 GPTOPT ),在复杂的语言建模任务中展示了突破性的性能,导致了人们巨大的学术的和实际的兴趣。它们的一个主要障碍是计算成本和存储成本,这些成本在已知模型中是最高的。例如,性能最佳的模型变种,即 GPT3-175B ,参数量级达 175B ,需要数十到数百个 GPU years 才能训练(《OPT: Open pre-trained transformer language models》)。即使是在更简单的任务,即在 pre-trained 模型上进行推理,也非常具有挑战性(这也是我们在本文中关注的焦点):例如,GPT3-175B 的参数以 compact float16 format 存储时,占用 326GB (以 1024 为基数计算)的内存。这甚至超过了最高端的 single GPU 的容量,因此推理必须使用更复杂的和更昂贵的 setup 来执行,例如 multi-GPU deployments

    尽管消除这些开销的标准方法是模型压缩,例如 《Sparsity indeep learning: Pruning and growth for efficient inference and training in neural networks》《A survey of quantization methods for efficient neural network inference》,但令人惊讶的是,几乎没有人知道如何压缩这些模型以进行推理。一个原因是,针对 low-bit width quantizationmodel pruning 的更复杂的方法通常需要对模型进行重新训练,而这对于十亿级参数的模型来说极其昂贵。另一方面,在不进行重新训练的情况以 one shot 方式压缩模型的 post-training 方法非常有吸引力。不幸的是,这种方法的更 accurate 的变体非常复杂,很难扩展到十亿级的参数(《ZeroQuant: Efficient and affordable post-training quantization for large-scale transformers》)。到目前为止,只有 round-to-nearest quantizationbasic variants《LLM.int8(): 8-bit matrix multiplication for transformers at scale》)已经应用于 GPT-175B 规模;虽然这对 low compression 目标(例如,8-bit 权重)而言效果很好,但它们在更高的压缩率下无法保持准确率。因此,one-shot post-training quantization 到更高压缩率是否可行,仍然是个未解决问题。

    贡献:在本文中,我们提出了一种新的 post-training quantization 方法 GPTQ ,其效率足以在几小时内对数百亿参数的模型执行,精度足以将这些模型压缩到每个参数 3 bits4 bits,几乎没有损失准确率。例如,GPTQ 可以在大约 4 GPU hours 内量化最大的开源可用模型 OPT-175BBLOOM-176B ,并且仅仅稍稍增加了困惑度(困惑度是非常严格的准确率指标)。

    此外,我们还表明,在极端量化区域,即模型被量化为每个参数 2 bits 、甚至 1.5 bits (即,该数据类型只有三个值),我们的模型也可以提供稳健的结果。在实用性方面,我们开发了一个执行工具,允许我们为生成式任务有效地执行被量化后的 compressed models 。具体来说,我们能够第一次在单个 NVIDIA A100 GPU 上运行 compressed OPT-175B model ,或者只使用两个更经济实惠的 NVIDIA A6000 GPU 来运行。我们还实现了定制的 GPU kernels,能够利用 compression 进行更快的内存加载,在使用 A100 GPU 时加速了 3.25 倍、在使用 A6000 GPU 时加速了 4.5 倍。

    据我们所知,我们是首次展示含数百亿参数的 extremely accurate 的语言模型可以被量化到每个参数 3-4 bits :之前的 post-training 方法只能在 8 bits 下保持准确率(《ZeroQuant: Efficient and affordable post-training quantization for large-scale transformers》《LLM.int8(): 8-bit matrix multiplication for transformers at scale》);而之前的 training-based 的技术只处理过小一个到两个数量级的模型(《Extreme compression for pre-trained transformers made simple and efficient》)。这种高度压缩似乎很自然,因为这些网络是过参数化的(overparametrized);然而,正如我们在对结果的详细分析中所讨论的,compression 在语言建模的准确率(即,困惑度指标)、bit-width 、以及原始模型大小之间引入了重要的 tradeoffs

    我们希望我们的工作将激发这个领域的进一步研究,并且可以是进一步的步骤从而使这些模型更广泛可用。就局限性而言,我们的方法目前无法为实际乘法提供加速,因为主流架构上缺乏对混合精度操作数(例如,FP16 * INT4 )的硬件支持。此外,我们当前的结果不包括 activation quantization ,因为它们在我们的目标场景中不是关键瓶颈;然而,这可以使用正交技术来支持(《ZeroQuant: Efficient and affordable post-training quantization for large-scale transformers》)。

  2. 相关工作:量化方法大致分为两类:quantization during trainingpost-training 方法。前者在通常昂贵的重新训练和/或微调期间对模型进行量化,针对 rounding 操作使用某种 approximate differentiation 机制(《A survey of quantization methods for efficient neural network inference》《A white paper on neural network quantization》)。相比之下,post-training 方法(也叫做 one-shot 方法)使用较少的资源对 trained 模型进行量化,通常需要几千个数据样本和几个小时的计算。post-training 方法对于大型模型特别有前景,因为对大型模型进行完整的模型训练甚至微调都非常昂贵。我们在这里关注这种场景。

    • Post-training Quantization:大多数 post-training 方法都集中在视觉模型上。通常,accurate 的方法通过量化单个 layerssmall blocks of consecutive layers来操作。

      • AdaRound 方法(《Up or down? Adaptive rounding for post-training quantization》)通过 annealing 一个惩罚项来计算 data-dependent rounding ,该项鼓励权重向对应于 quantization levelsgrid points 移动。

      • BitSplit《Towards accurate post-training network quantization via bit-split and stitching》)使用 residual errorsquared error objective 逐比特地构建 quantized value ,而 AdaQuant《Accurate post training quantization with small calibration sets》 )基于直接估计进行 direct optimization

      • BRECQ《BRECQ: Pushing the limit of post-training quantization by block reconstruction》)在目标函数中引入 Fisher 信息,并联合优化单个 residual blocklayers

      • 最后,Optimal Brain Quantization: OBQ《Optimal Brain Compression: A framework for accurate post-training quantization and pruning》)将经典的 Optimal Brain Surgeon: OBS 二阶权值修剪框架(《Efficient second-order approximation for neural network compression》)推广到量化。OBQ 逐个地量化权重,按 quantization error 的顺序,总是调整剩余权重。

      虽然这些方法可以在几个 GPU hours 内为最多 100M 参数的模型产生良好结果,但将其扩展到数量级更大的网络面临挑战。

    • Large-model Quantization:随着 BLOOMOPT-175B 等语言模型的开源发布,研究人员已经开始开发可负担的方法来压缩这种巨大的网络以进行推理。尽管所有现有的工作(ZeroQuanLLM.int8()nuQmm )都仔细选择了量化粒度,如 vector-wise ,但它们最终只是将权重舍入到最近(round weights to the nearest: RTN)的 quantization level ,从而为每个非常大的模型维持可接受的运行时间。

      • ZeroQuant 进一步提出了类似于 AdaQuant 的逐层知识蒸馏(layer-wise knowledge distillation ),但它可以应用这种方法的最大模型只有 1.3B 参数。在这种规模下,ZeroQuant 已经需要 3 小时的计算;而 GPTQ4 小时内量化了大约100 倍的模型。

      • LLM.int8() 观察到在少数 feature dimensions 中的 activation outliers 会破坏更大模型的量化,并提出通过以更高的精度来保持这些维度从而来解决这个问题。

      • 最后,nuQmm 为一种特定的 binary-coding based 量化方案开发了高效的 GPU kernels

      与这些工作相比,我们表明:在大的 model scale 上可以有效地实现一个明显更复杂的和更精确的 quantizer 。具体来说,在类似的准确率下,GPTQ 将先前技术的压缩量提高了一倍以上。

6.1 背景知识

  1. Layer-Wise Quantization:在 high level ,我们的方法遵循 SOTApost-training quantization 方法的结构,逐层执行量化,为每一层解决相应的重构问题。具体而言,设 Wl 为线性层 l 对应的权重,令 Xl 表示 layer input (对应于少量的 m 个数据点在网络中前向传播)。然后,目标是找到一组 quantized weights W^,使得相对于 full precision layer output 的平方误差最小化。形式上,这可以描述为:

    (36)argminW^WXW^X22

    此外,与 《Up or down? Adaptive rounding for post-training quantization 》《BRECQ: Pushing the limit of post-training quantization by block reconstruction》《Optimal Brain Compression: A framework for accurate post-training quantization and pruning》类似,我们假设 W^quantization grid 在过程开始前就固定好了,单个权重可以如《Accurate post training quantization with small calibration sets》《Optimal Brain Compression: A framework for accurate post-training quantization and pruning》 中那样自由移动。

    quantization grid 就是 bit-width。例如,int-4 量化的 grid 粒度就要比 int-8 量化的粒度更粗。

  2. Optimal Brain Quantization:我们的方法建立在最近提出的 Optimal Brain Quanization: OBQ 方法(《Optimal Brain Compression: A framework for accurate post-training quantization and pruning》)的基础上,用于解决上面定义的 layer-wise quantization 问题。我们对 OBQ 方法进行了一系列重大修改,这使其可以扩展到大规模语言模型,提供了三个数量级以上的计算加速。为了帮助理解,我们首先简要概括一下原始的 OBQ 方法。

    OBQ 方法的起点是观察到公式 argminW^WXW^X22 可以写成 W 每行的平方误差之和。然后,OBQ 独立地处理每一行 w (其中 wW 的某一行),一次性量化一个权重,同时总是更新所有尚未被量化的权重,从而补偿量化单个权重带来的误差。

    由于对应的目标函数是二次函数,其海森矩阵为 HF=2XFXF,其中 F 表示 w 中剩余的 full-precision weights 的集合,那么 greedy-optimal 的下一个要量化的权重(记做 wq ),以及 F 中所有权重的对应 optimal update (记做 δF),由以下公式给出:

    (37)wq=argminwq(quant(wq)wq)2[(HF)1]q,qδF=wqquant(wq)[(HF)1]q,q×((HF)1):,q

    这是核心思想。后面的内容都是针对该公式的计算速度和稳定性上的优化。

    其中:

    • quant(w)w 舍入到 quantization grid 上的 nearest valuewqwqF

    • [(HF)1]q,q 为海森矩阵 HF 的逆矩阵的第 q 行、第 q 列的元素,即对角线上的第 q 个元素;((HF)1):,q 为海森矩阵 HF 的逆矩阵的第 q 列。

    OBQ 使用这两个等式迭代地量化权重,直到 w 的所有权重都被量化完毕。这是高效地完成的,通过如下公式从而避免 H1 的昂贵的 full recomputations

    (38)(Hq)1=(H11[H1]q,q(H1):,q(H1)q,:)q

    其中:

    • Hq 表示从 H 中移除第 q 行、第 q 列得到的新矩阵;(Hq)1 表示 (Hq) 的逆矩阵。

    • (H1)q,: 表示 H1 的第 q 行、(H1):,q 表示 H1 的第 q 列。

    该方法具有向量化实现,可以并行处理 W 的多行。最终,该算法可以在中等规模的模型上实现合理的运行时间:例如,它可以在单GPU 上在 1 小时内完全量化 ResNet-50 模型(25M 参数),这与实现 SOTA 准确率的其他 post-training 方法的运行时间大致相当(《Optimal Brain Compression: A framework for accurate post-training quantization and pruning》)。然而,OBQdrow×dcol 矩阵 W 的运行时间有立方的输入依赖性 O(drow×dcol2),这意味着如果将其应用于数十亿参数的模型,则代价非常昂贵。

    推导过程,对于给定的权重行 w

    (39)Ew=wXw^X22

    则通过泰勒展开公式:

    (40)ΔE=wEΔw+12(Δw)H(Δw)+O(Δw3)

    其中:Δw=w^wwE=Ew

    为最小化 Ew ,则第一项为零(因为 E 位于极值点,此时一阶导数为零),同时忽略第三项(因为是三阶无穷小),则有:

    (41)min(Δw)H(Δw)

    因此对于第 q 个元素 wq ,我们需要满足:

    (42)wq=argminwqΔwq2[H1]q,q=argminwq(quant(wq)wq)2[H1]q,q

6.2 GPTQ 算法

  1. Step 1: Arbitrary Order Insight:如前一节所述,OBQ 以贪心的顺序来量化权重,即它总是选择当前引起的 additional quantization error最小的权重。有趣的是,我们发现,虽然这种非常自然的策略的确似乎表现非常好,但与任意顺序(arbitrary order )来量化权重相比,其改进通常很小,尤其是在大型的、参数密集的层上。很可能是因为数量较少的、具有较大误差的 quantized weights ,与那些在量化过程接近结束时的 quantized weights 所平衡;而在量化过程接近结束时,只剩下很少其他 unquantized weights 可以进行补偿调整。正如我们现在要讨论的,这一见解,即任意固定顺序可能表现良好,特别是在大型模型上,具有有趣的影响。

    原始 OBQ 方法独立地以特定顺序(该顺序由对应的additional quantization error 来定义)量化 W 的行。相比之下,我们将试图对所有的行以相同的顺序来量化权重,并将展示这通常会产生与原始解决方案类似的 final squared error 。因此,unquantized weights 的集合 F ,以及 (HF)1 对所有行来说总是相同的(参见 Figure 2 中的示意图)。更具体地说,后者是由于 HF 仅取决于 layer input XF ,对所有行都是相同的,而与任何权重无关。因此,我们只需要执行公式 (Hq)1=(H11[H1]q,q(H1):,q(H1)q,:)q 给出的 (HF)1dcol 次更新,每列一次;而不是 drow×dcol 次更新,每个权重一次。这将总体运行时间从 O(drow×dcol3) 降低到 O(max{drow×dcol2,dcol3}) ,即降低了 min{drow,dcol} 倍。对于较大的模型,这个差异占几个数量级。然而,在这个算法可以实际应用到非常大的模型之前,需要解决另外两个主要问题。

  2. Step 2: Lazy Batch-Updates :首先,直接实现前面描述的方案在实践中将不会很快,因为该算法具有相对较低的 compute-to-memory-access ratio 。例如,对于每一个 q ,公式 (Hq)1=(H11[H1]q,q(H1):,q(H1)q,:)q 需要更新一个潜在的巨大矩阵的所有元素,仅仅使用很少的 FLOPs。这种操作无法充分利用现代 GPU 的大规模计算能力,并会受到明显更低的内存带宽的限制。

    幸运的是,通过以下观察可以解决这个问题:对第 i 列的 final rounding decisions 仅受到对该列执行的更新的影响,因此对 later columns 的更新与第 i 列的更新在这个过程中是不相关的。这使得可以 "lazily batch" updates 从而实现更好的 GPU利用率。具体而言,我们同时对 B=128 列应用该算法,将更新限制在那些列上、以及 H1 对应 B×Bblock 中(参见 Figure 2 )。仅当一个 block 被完全处理后,我们才使用下面给出的 multi-weight 版本的公式,对整个 H1W 矩阵执行全局更新,其中 Q 表示一组索引、(HQ)1 表示删除对应行和列的矩阵的逆矩阵:

    (43)δF=(wQquant(wQ))([(HF)1]Q,Q)1((HF)1):,Q(HQ)1=(H1(H1):,Q([H1]Q,Q)1(H1)Q,:)Q

    尽管这种策略理论上不减少计算量,但它有效地解决了内存吞吐量瓶颈,在非常大的模型上实际提供了一个数量级的加速,使其成为我们算法的关键组成部分。

    即,每次更新一个 batch 的权重,而不是单个权重。

  3. Cholesky Reformulation:我们必须解决的最后一个技术问题是数值不准确,它可能在现有模型规模下成为主要问题,特别是结合上一步中讨论的 block updates 。具体来说,可能出现 (HF)1 变为不定矩阵的情况,我们注意到这可能导致算法错误地调整 remaining weights 的方向,从而导致对应层的 arbitrarily-bad quantization 。在实践中,我们观察到发生这种情况的概率随模型大小增加:具体来说,对于大于数十亿参数的模型,它几乎肯定对至少一些层发生。主要问题似乎是重复应用公式 (HQ)1=(H1(H1):,Q([H1]Q,Q)1(H1)Q,:)Q ,它会累积各种数值误差,特别是通过 additional matrix inversion

    对于较小的模型,应用阻尼,即将 H 对角线元素增加一个很小的常数 λ (我们总是选择对角线平均值的 1% )看起来足以避免数值问题。然而,更大的模型需要更稳健的和更通用的方法。

    为此,我们首先注意到,从 (HFq)1 中所需的唯一信息是行 q (其中 Fq 表示当量化 weight q 时的 unquantized weights 集合),或者更准确地说,从对角线开始的该行中的元素。其结果是,我们可以使用更数值稳定的方法预先计算所有这些行,而不会显著增加内存消耗。实际上,对于我们的对称矩阵 H1,通过 (Hq)1=(H11[H1]q,q(H1):,q(H1)q,:)q 移除行,这对应于执行 Cholesky 分解,只是后者存在细微的差别:将行 q 除以 ([(HFq)1]q,q)1/2 。因此,我们可以利用 SOTACholesky kernelsH1 中提前计算我们将需要的所有信息。与温和阻尼相结合,所得到的方法足够稳健,可以在巨大的模型上执行而没有问题。作为奖励,使用优化良好的 Cholesky kernel 还可以进一步加速。接下来,我们详细说明 Cholesky 版本算法所需的所有小改动。

    虽然大型模型的参数规模可以达到千亿级,但是这里的 H 是由当前 layerinput X 来决定,通常规模不大。可以快速地进行 Cholesky 分解。

  4. 完整算法:最后,我们在 Algorithm 1 中给出 GPTQ 的完整伪代码,包括上面讨论的优化。

    注意:GPTQ 需要依赖输入数据 X 来执行量化。在实验部分,作者采用 C4 数据集中随机采样的 128random 2048 token segments组成的 X 。如果 X 来自不同的数据,例如随机生成的文本序列,是否对 GPTQ 有影响?采用比 128 更多的样本更好,还是更少的样本更好?论文都没有进行消融研究。(在 SparseGPT 的论文中,作者对 calibration 数据进行了消融分析,发现::随着 calibration 样本数量的增加,准确性得到改善。但是当数量超过某个点时,困惑度曲线逐渐变平缓。)

    注意:GPTQ 仅关注权重 W 的量化,而不关心 activation X 的量化。

    注意:在当前 layer 量化完之后,再将 X 馈入当前的 quantized layer 从而作为 next layer 的输入。

    注意:算法的迭代没有采用随机梯度下降,而是直接用的解析解,因此迭代效率非常高。

    注意:blocksize B 对于模型准确性没有影响,它影响的是训练速度。

6.3 实验

  1. 我们首先在小型模型上验证 GPTQ 相对于其他 accurate-but-expensive quantizers的准确率,这些方法在这些小型模型上可以提供合理的运行时间。接下来,我们检查 GPTQ 在超大型模型上的 runtime scaling 。然后,我们通过困难的语言生成任务上的困惑度表现,展示 BLOOMOPT 模型族的整体 3-bit4-bit 的量化结果。此外,我们展示,当粒度减小到 small blocks of consecutive weights 时,我们的方法在 2-bit 量化也很稳定。

    为补充这一困惑度分析,我们还在一系列标准的 zero-shot 任务上评估得到的 quantized models 。最后,我们关注两个最大(和有趣)的开源可用模型,即 Bloom-176BOPT-175B ,在这里我们对几个任务进行详细评估。对于这些模型,我们还提出实际改进,即,为生成式任务减少推理所需的 GPU 数量、以及端到端加速。

  2. 设置:我们在 PyTorch 中实现了 GPTQ ,并使用 HuggingFaceBLOOMOPT 模型家族。我们使用单个 NVIDIA A100 GPU80GB 内存)来量化所有模型(包括 175B 参数变体)。我们整个 GPTQ 校准数据(calibration data )由 C4 数据集中随机采样的 128random 2048 token segments组成。我们强调这意味着 GPTQ 没有看到任何特定任务的数据,因此我们的结果实际上保持 "zero-shot"。我们在 min-max grid 上执行 standard uniform per-row asymmetric quantization,与 《LLM.int8(): 8-bit matrix multiplication for transformers at scale》类似。附录 A.2.1 中提供了更多评估细节。

    为确保整个压缩过程可以在比运行 full precision model 所需的 GPU 内存显著更小的内存中执行,必须谨慎操作。具体来说,我们一次将一个由 6 layers 组成的 Transformer block 加载到 GPU 内存中,然后累积 layer-Hessians 并执行量化。最后,通过再次将 current block inputs 馈入 fully quantized block ,从而产生 next blocknew inputs 从而进行量化。因此,量化过程不是在 full precision modellayer inputs 上运行,而是在已经部分 quantized modelactual layer inputs 上运行。我们发现,这在几乎没有额外成本的情况下带来显着改进。

  3. baselines

    • 我们的主要基准线,记做 RTN ,将所有权重舍入到与 GPTQ 使用的完全相同的 asymmetric per-row grid 上的 nearest quantized value;这对应于 SOTALLM.int8()weight quantization 。这目前是非常大规模语言模型的量化中所有工作的选择方法:它的运行时间随着具有数十亿参数的网络很好地扩展,因为它只执行直接舍入(direct rounding )。

    • 正如我们稍后将更深入讨论的,像 AdaRound《Up or down? Adaptive rounding for post-training quantization》)或 BRECQ《BRECQ: Pushing the limit of post-training quantization by block reconstruction》 )这样更精确的方法目前对于数十亿参数的模型来说计算开销太大,这也是本文的主要关注点。

    • 尽管如此,我们还展示 GPTQ 在小型模型上与这些方法相媲美,同时也可扩展到 OPT-175B 这样的巨型模型。

  4. Quantizing Small Models:作为第一个消融研究,我们在 ResNet18ResNet50 上比较 GPTQSOTApost-training quantization: PTQ 方法的性能,这些是标准的 PTQ benchmarks ,设置与 《Optimal Brain Compression: A framework for accurate post-training quantization and pruning》 相同。

    结果如 Table 1 所示。可以看到:

    • 4-bit 时,GPTQ 的表现与最 accurate 的方法相当。

    • 3-bitGPTQ 与最 accurate 的方法相比略差一些。

    • 与此同时, GPTQ 明显优于 AdaQuant ,后者是先前 PTQ 方法中最快的。

    此外,我们还与两个小型语言模型 BERT-baseOPT-125M 上的 full greedy OBQ 方法进行了比较。结果如附录 Table 8 所示。可以看到:在 4-bit 时,两种方法的性能相似;在 3-bit 时,出人意料的是,GPTQ 的表现略好一些。我们怀疑这是因为 OBQ 使用的一些额外启发式方法,如 early outlier rounding ,可能需要仔细调整从而在 non-vision 模型上获得最佳性能。

    总体而言,GPTQ 似乎与小型模型的 SOTAPTQ 方法相媲美,而只需要 <1 minute 而不是 1 hour。这使其可以扩展到更大的模型。

  5. Runtime :接下来,我们通过 GPTQ 测量 full model quantization time (在单个 NVIDIA A100 GPU 上);结果如 Table 2 所示。可以看出:

    • GPTQ 可以在几分钟内量化 1B-3B 参数的模型,在几小时内量化 175B 参数的模型。

    • 作为参考,基于 straight-through 的方法 ZeroQuant-LKD《ZeroQuant: Efficient and affordable post-training quantization for large-scale transformers》)报告了一个 1.3B 参数模型的 3 小时 runtime (在相同硬件上),这会线性外推到 175B 参数模型的数百小时(几周)。

    • adaptive rounding-based 的方法通常采用大量 SGD steps ,因此计算代价甚至更高(《Up or down? Adaptive rounding for post-training quantization》《BRECQ: Pushing the limit of post-training quantization by block reconstruction》)。

  6. Language Generation:我们通过压缩整个 OPTBLOOM 模型系列到 3-bit4-bit 开始 large-scale 研究。然后我们在几项语言任务上评估这些模型,包括 WikiText2 (参考 Figure 1Table 4)、Penn Treebank: PTB 、和 C4 (都在附录 A.3 中)。我们关注这些基于困惑度的任务,因为已知它们特别敏感于 model quantization《ZeroQuant: Efficient and affordable post-training quantization for large-scale transformers》)。

    • OPT 模型上,GPTQ 明显优于 RTN ,差距很大。例如,在 175B 参数模型的 4-bit 下,GPTQ只损失了 0.03 的困惑度,而RTN 下降了 2.2 的困惑度(甚至比规模小 10 倍的 full-precision 13B model 表现还差)。

      3 比特下,RTN 完全崩溃,而 GPTQ 仍能维持合理的困惑度,特别是对较大的模型。

    • BLOOM 显示了类似的模式:方法之间的差距通常稍小一些,这表明这个模型系列可能更容易被量化。

    • 一个有趣的趋势(参见 Figure 1)是:除 OPT-66B 之外,较大的模型似乎通常更容易被量化。这对实际应用来说是个好消息,因为这些也是最需要压缩的情况。

  7. 175 Billion Parameter Models:现在我们检查 BLOOM-176BOPT-175B ,这是最大的公开可用的稠密模型。Table 5 总结了它们在 Wikitext-2PTBC4 上的结果。我们观察到:

    • 4-bit 下,GPTQ 模型的困惑度仅比 full-precision versions0.25,并且在 OPT-175B 上以较大优势超越了 RTN 的结果。

    • 3-bit 下,RTN 崩溃,而 GPTQ 仍能在大多数任务上维持良好的性能,在超过 5 倍压缩的情况下仅仅损失 0.3-0.6 点。

    • 我们注意到,通过更细粒度的分组(《nuQmm: Quantized matmul for efficient inference of large-scale generative language models》),GPTQ 的准确率可以进一步提高:group-size =1024(约 0.02 extra bits )改善了平均困惑度约0.2group-size =128(约 0.15 extra bits )继续改善了平均困惑度约 0.1 ,与未压缩的困惑度只差 0.1-0.3

      我们注意到,groupingGPTQ 互相协作得非常好,因为可以在每一层的量化过程期间确定 group parameters ,总是使用 most current updated weights

  8. 实际加速:最后,我们研究实际应用。作为一个有趣的 case,我们关注 OPT-175B 模型:量化到 3-bit 后,这个模型占用约 63GB 内存,包括 embedding layeroutput layer(它们保持 full FP16 precision )。另外,为所有层存储 keysvalues 的完整历史,这是 generation 任务的常见优化,对于最大 2048 tokens 又占用约额外 9GB 。因此,我们实际上可以将整个 quantized model 装入单个 80GB A100 GPU 中,可以通过在推理期间需要时动态地 dequantizing layers 来执行(使用 4-bit 模型将不会完全适合单个 GPU 内存)。作为参考,标准 FP16 执行需要 580GB GPU;而 SOTA8-bit LLM.int8() quantizer 需要 3 个这样的 GPU

    接下来,我们考虑 language generation,这是这些模型最吸引人的应用之一,目标是减少延迟。与 LLM.int8() 不同,其中 LLM.int8() 减少了内存成本但与 FP16 baselineruntime 相同,我们展示了我们的 quantized models 可以实现显着的加速。对于 language generation,模型一次处理和输出一个 token,对于 OPT-175B ,每个 token 需要几百毫秒。提高生成结果的速度具有挑战性,因为计算主要由 matrix-vector 乘法所主导。与 matrix-matrix 乘法不同, matrix-vector 乘法主要受内存带宽限制。我们通过开发 quantized-matrix full-precision-vector product kernel 来解决这个问题,该 kernel 通过在需要时动态地 dequantizing weights 来执行 matrix-vector 乘法。最重要的是,这不需要任何 activation quantization 。虽然 dequantization 消耗了额外计算,但 kernel 需要访问更少内存,如 Table 6 所示,这导致显着加速。我们注意到,几乎所有加速都归因于我们的 kernels ,因为在我们的标准 HuggingFace-accelerate-like setting 中,通信成本可忽略不计(详见附录A.2.2 )。

    例如:

    • 使用我们的 kernels ,通过 GPTQ 获得的 3-bit OPT-175B 模型在单 A100 GPU 上运行时,与 FP16 版本(在 5GPU 上运行)相比,average time per token 快约 3.25 倍。

    • 对于 NVIDIA A6000 (具有更低的内存带宽),这种策略甚至更有效:在 2A6000 GPU 上执行 3-bit OPT-175B 模型将延迟从 FP16 版本的 589 毫秒(在 8GPU 上)降低到 130 毫秒,延迟降低了 4.5 倍。

  9. Zero-Shot Tasks:虽然我们的重点是 language generation ,但我们还在一些流行的 zero-shot 任务上评估了 quantized models 的性能,即 LAMBADAARC (Easy and Challenge) 、和 PIQAFigure 3 可视化了模型在 LAMBADA 上的性能(参见 Table 5 中的 "Lamb." 结果)。我们观察到之前类似的行为,但是一些异常情况是:

    • 1) :在 4-bit ,量化对所有模型来说似乎 “更容易”, 即使RTN 也表现相对良好。

    • 2) :在 3-bitRTN 崩溃 而 GPTQ 仍然提供良好的准确率。

    我们在附录 A.4 中提供了更多结果。

  10. Additional Tricks:虽然到目前为止我们的实验仅集中在普通的 row-wise quantization 上,但我们想强调 GPTQ 与基本上任何quantization grid choice 兼容。例如,它很容易与 standard grouping《QSGD: Randomized quantization for communication-efficient stochastic gradient descent》《nuQmm: Quantized matmul for efficient inference of large-scale generative language models》)相结合,即对 groups of g consecutive weights 应用独立的量化。如 Table 5 最后几行所示,这在 3-bit 对最大模型可以带来显着的额外准确率提升。此外,如 Figurer 4 所示,它显着减少了中等大小模型在 4-bit precision 下的准确率损失。

  11. 极端量化:最后,grouping 也使得在平均 2-bit per parameter 的极端量化上获得合理性能成为可能。Table 7 显示了在不同 group-size 下将最大模型量化为 2-bit 时在 WikiText2 上的结果。

    • 在大约 2.2 bitgroup-size 128; using FP16 scale and 2-bit zero point per group )时,困惑度的增加还不到 1.5

    • 而在约 2.6 bitgroup-size 32 )时,困惑度增加到 0.6-0.7 ,这只比普通的 3-bit 略差,并且对实际 kernel implementations 可能很有趣。

    • 此外,如果我们将 group-size 减小到 8 ,我们可以应用三值(ternary )量化(-1, 0, +1),在 OPT-175B 上获得 9.20 的困惑度,增加不到 1 个点。虽然与上述 2-bit 数字相比,这在平均上导致较差的压缩,但这种模式可以在 FPGA 等定制硬件上有效实现。

    总之,这些结果是首次向着极端压缩非常大型语言模型的有希望的第一步,甚至低于平均 3-bit per parameter

6.4 讨论

  1. 局限性:我们强调一些重要的局限性:

    • 在技术上,我们的方法来自减少内存移动带来的加速,而没有导致计算减少。

      注意,这是因为 GPU kernels 目前还不支持 3-bit 整数和 FP 16 的乘法,因此在推理过程中,3-bit 整数被逆量化为 FP16,然后进行 FP16FP16 的乘法运算,这就是作者开发的 quantized-matrix full-precision-vector product kernel

    • 此外,我们的研究侧重于生成式任务,而且不考虑 activation quantization

    这些是自然的未来工作方向,我们相信这可以通过精心设计的 GPU kernels 和现有技术来实现(《ZeroQuant: Efficient and affordable post-training quantization for large-scale transformers》《Extreme compression forpre-trained transformers made simple and efficient 》)。