论文:
《Mixed Precision Training》
论文是关于混合精度训练的,考虑到混合精度训练的思想已经广为人知,因此这里仅做粗读。
Introduction
:略(参考原始论文)。
相关工作:略(参考原始论文)。
我们介绍了 training with FP16
的关键技术,同时仍然匹配 FP32 training session
的 model accuracy
:single-precision master weights and updates
、loss-scaling
、accumulating FP16 products into FP32
。
单精度浮点数为
float32
、双精度浮点数为float64
。
在混合精度训练中,权重、activations
以及梯度以 FP16
格式存储。为了匹配 FP32
网络的准确率,我们维护权重的一份 FP32 master copy
,并在 optimizer step
中用 weight gradient
来更新它。在每次迭代中,使用 master weights
的 FP16 copy
进行正向传播和反向传播,将 FP32 training
所需的存储和带宽减半。Figure 1
说明了这种混合精度训练过程。
虽然 FP32 master weights
的需求并非普遍存在,但有两个可能的原因解释为什么许多网络需要它:
一个解释是 updates
( weight gradients
乘以学习率)变得太小而无法用 FP16
表示。FP16
中任何 magnitude
小于 Figure 2b
所示,约 5%
的 weight gradient values
的 exponents
小于 -24
。在 optimizer
中,这些小的梯度与学习率相乘后会变成零,并对模型准确率产生不利影响。使用 single-precision copy
进行更新可以克服这个问题并恢复准确率。
即,
weight updates
绝对很小,导致updates
变成零。
另一个解释是 weight value
与 weight update
的比率非常大。在这种情况下,即使 weight update
可以用 FP16
来表示,当加法操作将 weight update
右移从而将 binary point
与 weights
对齐时, weight update
仍然可能变成零。当 normalized weight value
的 magnitude
比 weight update
的 magnitude
大至少 2048
倍时,这种情况可能发生。由于FP16
有 10-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
。
尽管与 single precision training
相比,维护额外的权重副本将权重的内存需求增加了 50%
,但对整体内存使用的影响要小得多。 对于训练,内存消耗主要由 activations
引起,这是由于较大的 batch size
、以及保存每层的 activations
从而在反向传播中重用。 由于 activations
也以半精度格式存储,所以整体内存消耗约减半。
作者这里并未给出数据来说明。
FP16 exponent
将 normalized value exponents
范围有偏地居中到 [-14,15]
,而实际梯度值往往以小 magnitudes
( negative exponents
)为主。例如,考虑 Figure 3
,显示了在 FP32
训练 Multibox SSD
检测器网络过程中收集的所有层的 activation gradient values
的直方图。注意,FP16
可表示范围的大部分未被使用,而许多值低于最小可表示范围并变为零。 scaling up
梯度将使它们占用更多的可表示范围,并保留一些值(如果不 scaling up
,这些值将会因为零而丢失)。
不缩放梯度时,该特定网络会发散;但将其缩放 8
倍(对 exponents
增加 3
)足以匹配 FP32 training
达到的准确率。这表明,在 magnitude
上小于 activation gradient values
对此模型的训练无关,但 magnitude
的 activation gradient values
很重要。
由于学习率通常很小,因此
范围内的 activation gradient values
乘以学习率仍然可能小于。但是, Weight Update
采用FP32
,因此不会变为零。
将 gradient values
移至 FP16
可表示范围的一种有效方法是:在开始反向传播之前,缩放在前向传播中计算的 loss value
。通过链式法则,反向传播将确保所有梯度值被缩放相同的量。这在反向传播期间不需要额外的操作,并使相关的梯度值不会变成零。
在权重更新之前,必须 unscale
权重梯度,从而保持 weight update magnitudes
与 FP32 training
相同。最简单的方法是:在反向传播结束之后、但在梯度裁剪或任何其他与梯度相关的计算之前进行 unscale
,从而确保不需要调整任何超参数(如梯度裁剪阈值、weight decay
等)。
虽然可以通过缩小学习率来间接地缩放梯度,但是梯度裁剪阈值、
weight decay
等等方法的超参数也需要相应地缩放。
loss scaling factor
有几种选择。最简单的一种是选择一个常量的 scaling factor
。我们用 8
到 32K
的 scaling factor
训练了各种网络(许多网络不需要 scaling factor
)。可以经验性地选择一个常量 scaling factor
,或者如果有梯度统计信息,可以直接选择一个 scaling factor
使其与 maximum absolute gradient value
的乘积低于 65,504
(FP16
中可表示的最大值)。
只要不在反向传播期间导致数值溢出,选择一个大的 scaling factor
就没有坏处。数值溢出会导致 weight gradients
中出现无穷大和 NaN
,在权重更新后会不可逆地破坏权重。请注意,数值溢出可以通过检查计算到的 weight gradients
(例如在 unscale weight gradient values
的时候)来有效检测。一种解决方法是:在检测到数值溢出时跳过 weight update
,直接进入下一次迭代。
在很大程度上,神经网络的算术分为三类:向量点积、reductions
、以及 point-wise
操作。这些算术类别在 reduced precision
算术方面受益于不同的处理。
为了保持模型准确率,我们发现一些网络要求 FP16 vector dot-product
从而累积 partial products
到 FP32
值,然后在写入内存前将其转换为 FP16
。如果不这样累积到 FP32
,一些 FP16
模型的准确率无法匹配 baseline
模型。而先前的 GPU
只支持 FP16 multiply-add
操作,而 NVIDIA Volta GPU
引入了 Tensor Core
,可以将 FP16
的 输入矩阵相乘并累积乘积结果到 FP16 output
或 FP32 output
。
大型的 reductions
(如向量元素之和)应在 FP32
中进行。这种 reductions
主要出现在 batch-normalization layers
(累积统计信息)和 softmax layers
。在我们的实现中,这两种 layer
类型仍从内存读取和写入 FP16
张量,而在 FP32
中执行算术运算。这并没有减慢训练过程,因为这些 layers
受内存带宽限制,而对于算术速度不敏感。
point-wise
操作(如非线性激活函数、element-wise
矩阵乘法)受内存带宽限制。由于算术精度不影响这些操作的速度,可以使用 FP16
或 FP32
。
略(参考原始论文)。
论文:
《Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference》
论文是关于量化 CNN
模型的,这里仅做粗读,仅关注核心算法。
Introduction
:略(参考原始论文)。
相关工作:略(参考原始论文)。
在这一节中,我们描述了通用的量化方案,也就是两种类型数值之间的对应关系: bit representation of values
(这个整数记为 "quantized value"
)、以及它们作为数学的实数的解释(对应的实数记为 "real value"
)。我们的量化方案在推理时只使用整数算术实现,在训练时使用浮点算术实现,两种 implementations
高度对应。我们首先数学上严格定义量化方案,然后分别采用该方案用于 integer-arithmetic inference
和 floating-point training
。
floating-point training
类似于量化感知训练Quantization Aware Training
,即在训练阶段就应用 “模拟” 量化操作,从而降低integer-arithmetic inference
的量化误差。
我们量化方案的一个基本要求是,它允许只使用整数算术操作对 quantized values
进行所有算术运算的有效实现(我们避免需要 lookup tables
的实现,因为它们往往比在 SIMD
硬件上进行纯算术运算表现更差)。这相当于要求量化方案是整数
其中:
常数 "scale"
)是一个任意的正实数。它通常以软件中的浮点数形式表示,类似于实数
常数 "zero-point"
)与 quantized value
quantized value
quantized value
精确地表示。这一要求的动机是,高效实现的神经网络算子通常需要对数组进行 zero-padding
。
这个公式是我们的量化方案,常数 quantization parameters
)。我们的量化方案对每个 activations array
内的所有值、以及 weights array
内的所有值使用单组量化参数,即:不同的 array
使用独立的量化参数。
对于 8-bit
量化,8-bit
整数(对于 B-bit
量化,B-bit
整数)。一些数组(通常是 bias vectors
)被量化为 32-bit
整数,参见后续内容。
到目前为止的讨论被总结在以下的 quantized buffer
数据结构中,神经网络中的每个 activations array
和 weights array
都有这样一个 buffer
实例。我们使用 C++
语法是因为它可以明确地表达类型:
xxxxxxxxxx
template<typename QType> // e.g. QType=uint8
struct QuantizedBuffer {
vector<QType> q; // the quantized values
float S; // the scale
QType Z; // the zero-point
};
我们现在考虑如何仅使用整数算术进行推理,也就是如何使用方程 quantized-values
运算,以及后者如何设计为仅包含整数算术,即使 scaling
参数
考虑两个 quantized
矩阵为
从矩阵乘法的定义,我们有:
这可以重写为:
其中乘数
quantization scales
其中:其中
归一化的乘数 int16
或 int32
)。例如,如果使用 int32
的整数乘法,表示 int32
值。由于 30-bit
的相对精度。因此,乘以 fixed-point multiplication
)。
同时,乘以 bit-shift
),尽管需要具有正确的四舍五入(round-to-nearest
)行为,我们在附录 B
中讨论这个问题。
为了在不执行 16-bit
整数的情况下,有效地实现公式
其中:
每个
上式的剩余成本几乎全部集中在核心的整数矩阵乘法累加上:
这需要
的确,zero-points
都能以很小的开销处理,除了 core integer matrix multiplication accumulation
,因为我们在任何其他 zero-points-free
方案中都必须计算它。
这仅仅改善了减法操作,而没有改善乘法操作。
原始方法中,对于
,一共需要 的减法操作;但是新的方法中,计算 需要 次加法操作。然后 可以在不同的 中共享。 但是,对于乘法操作,二者之间并未改善。
我们继续前面的讨论,但现在显式地定义所有涉及的量(quantities
)的数据类型,并修改 quantized
的矩阵乘法,从而直接将 bias-addition
和 activation function evaluation
合并到其中。这样将整个 layer
融合成单个操作而不仅是一个优化。由于我们必须在推理代码中重现训练中使用的相同算术,推理代码中的 fused operators
的粒度(接受 8-bit quantized input
并产生 8-bit quantized output
)必须与训练图中 "fake quantization" operators
的 placement
相匹配。
对于 ARM
和 x86 CPU
架构,我们使用 gemmlowp
库(《gemmlowp: a small self-contained low-precision gemm library》
),其 GemmWithOutputPipeline
入口点支持我们现在描述的 fused operations
。
General Matrix Multiplication: GEMM
:通用矩阵乘法。
我们将 activations
。权重和 activations
均为 uint8
类型(我们也可以等效地选择 int8
,适当修改 zero-points
)。uint8
值的乘积的累加需要 32-bit accumulator
,我们为 accumulator
选择带符号类型,原因很快就会变清楚。
为了得到 quantized bias-addition
(将 int32 bias
添加到 int32 accumulator
上),bias-vector
被量化为:
使用 int32
作为其量化数据类型。
使用 0
作为其 quantization zero-point
其 quantization scale
accumulators
的相同,即 weights scale
和 input activations scale
的乘积:
尽管 bias-vectors
被量化为 32-bit
值,但它们只占神经网络参数的很小一部分。此外,对 bias vectors
使用更高精度满足了一个真正的需求:由于每个 bias-vector entry
被添加到许多 output activations
中,bias-vector
中的任何量化误差往往表现为一个 overall bias
(即,均值不为零的误差项),这必须避免以保持端到端的神经网络准确性。
即,对于任何样本
, bias-vector
都添加到它的output activation
上,因此bias-vector
对所有样本都产生了影响。
对 int32 accumulator
的最终值,还剩下三件事要做:
scale down
到 final scale
,这个 final scale
被 8-bit output activations
所使用。
cast down
到 unit8
。
应用 activation function
生成 final 8-bit output activation
。
下采样对应于乘数 rounding bit-shift
组成。之后,我们执行 cast
到 uint8
,饱和到 [0,255]
范围。
我们仅仅关注 clamps
类型的激活函数,例如 ReLU
、ReLU6
。数学函数在附录 A.1
中讨论,目前我们不会将它们融合到这种层中。因此,我们 fused activation functions
唯一需要做的就是进一步将 uint8
值截断到 [0,255]
的某个子区间,然后存储 final uint8 output activation
。实际上,quantized training process
(参考下一节)倾向于学习使用整个 output uint8
区间 [0,255]
,以致 activation function
不再起任何作用,其效果被归因于截断到区间 [0, 255]
(由于 cast
到 unit8
所隐含的)。
在大模型时代,通常很少采用
simulated quantization
的训练,而是直接训练一个大模型,然后再进行post-training
量化。
训练 quantized networks
的常见方法是:用浮点进行训练,然后量化所得到的权重(有时伴随额外 post-quantization training
从而进行微调)。我们发现,这种方法对具有相当表达能力的大型模型效果足够好,但对小型模型会导致明显的准确率下降。simple post-training quantization
的常见失败模式包括:
1)
:不同 output channels
的权重范围差异很大(大于 100
倍)。注意:前面章节中规定,同一层的所有通道必须量化到相同分辨率;这会导致权重范围较小的通道中,权重的相对误差更大。
2)
:outlier weight values
,这些异常值使得量化后所有的非异常值的权重降低了精确性。
我们提出了一种在训练的前向传播中模拟量化效应(quantization effects
)的方法。反向传播仍然照常进行,所有权重和 bias
以浮点存储,以便可以轻易地略微调整。但是,前向传播模拟 quantized inference
(因为 quantized inference
发生在推理引擎中),通过如下方式:以浮点算法实现我们前面介绍的量化方案中的 rounding behavior
。
权重在与 input
执行卷积之前被量化。如果 layer
使用 batch normalization
,则在量化之前,batch normalization
参数被 “折叠”到权重中。
activations
在这样的时点上被量化:在推理期间 activations
被量化的点。例如:在 activation function
应用于卷积层或全连接层输出之后、或在像 ResNet
中那样多个层的输出相加或拼接的 bypass connection
之后。
对于每一层,quantization
由 quantization levels
数量、以及 clamping range
的参数化,并通过 point-wise
地应用下面定义的量化函数
其中:quantization levels
数量;
在我们的实验中,8-bit
量化时
即,在原始的神经网络中插入这些特定的
fake quantization layer
。
weight quantization
与 activation quantization
的 quantization ranges
的处理不同:
对于权重,基本思想是:简单地设置 int8
值,取值范围仅仅在 [-127, 127]
并且不会取值为 -128
,因为这 enable
了一个重要的 optimization opportunity
(更多细节见附录 B
)。
对于 activations
,ranges
取决于网络输入。为了估计 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
在量化后可以精确表示为整数 quantization parameters
映射到方程 scale
zero-point
下面我们假设神经网络的计算被捕获为 TensorFlow graph
,然后描述 simulated quantization
。典型的工作流程在 Algorithm 1
中描述。通过 fusing and removing operations
的inference graph
的优化,超出了本文范围。用于 graph modifications
的源码(插入 fake quantization
操作、创建和优化 inference graph
)、以及 low bit inference engine
已在 《Tensorflow quantized training support》
中通过 TensorFlow contributions
开源。
公式
12
为:
Figure 1.1 a and b
说明了一个简单卷积层量化前后的 TensorFlow graph
。Figure C.3
中,更复杂的带 bypass connection
的卷积的说明,可以在 Figure C.4
中找到。
请注意,bias
没有被量化,因为在推理过程中它们表示为 32-bit
整数,范围和精度远高于 8-bit weights and activations
。此外,用于,bias
的量化参数从权重和激活的量化参数推导出来。
使用《Tensorflow quantized training support》
的典型 TensorFlow
代码示例如下:
xxxxxxxxxx
from tf.contrib.quantize import quantize_graph as qg
g = tf.Graph()
with g.as_default():
output = ...
total_loss = ...
optimizer = ...
train_tensor = ...
if is_training:
quantized_graph = qg.create_training_graph(g)
else:
quantized_graph = qg.create_eval_graph(g)
# Train or evaluate quantized_graph.
对于使用 batch normalization
的模型,存在额外复杂性:training graph
中 batch normalization
是单独的操作块,而 inference graph
中 batch normalization
参数 “折叠” 到卷积层或全连接层的权重和 bias
中,从而提高效率。为了准确模拟量化效应,我们需要模拟这种折叠,并在权重被 batch normalization parameters
缩放后再来量化权重。我们采用以下方法:
其中:
batch normalization
的 scale
参数。
convolution results
的 batch
内方差的移动平均估计。
折叠后,batch-normalized convolutional layer
简化为 Figure 1.1a
中所示的简单卷积层,具有被折叠的权重 bias
。因此,相同的配方也适用于 Figure 1.1b
。附录中可以查阅 batch-normalized convolutional layer
( Figure C.5
)、相应的 inference graph
(Figure C.6
)、batch-norm folding
后的训练图( Figure C.7
)以及 folding and quantization
后的训练图( Figure C.8
)。
略(参考原始论文)。
论文:
《LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale》
大型 pretrained
语言模型在 NLP
中被广泛采用,但需要大量内存进行推理。对于超过 6.7B
参数的大型 transformer
语言模型,前馈层(feed-forward layer
)和注意力投影层(attention projection layer
)及其矩阵乘法操作占据了 95%
的参数和 65-85%
的所有计算(《High performance natural language processing》
)。减小参数大小的一种方法是将其量化为更少的比特并使用低位精度(low-bit-precision
)的矩阵乘法。考虑到这一目标,人们已经开发了 transformer
的 8-bit
量化方法。虽然这些方法减少了内存使用,但它们降低了性能,通常需要在训练后进一步 tuning quantization
,并且只在少于 350M
参数的模型上进行了研究。低于 350M
参数时性能无损的量化理解得不够好,十亿参数级的量化仍是一个开放性挑战。
在本文中,我们提出了第一个不降低性能的十亿参数级 Int8
量化过程。我们的过程使得加载一个具有 16-bit
或 32-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
的参数,理解推理过程中隐状态(隐状态就是 activation
)feature 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
中的仅 6
个feature dimensions
中。
将这些异常feature dimensions
设置为零会使 top-1 attention softmax
概率质量降低 20%
以上,并使 validation perplexity
退化 600-1000%
,尽管它们只占所有输入特征的约 0.1%
。相比之下,删除相同数量的随机特征会最大降低 0.3%
的概率质量,并退化约 0.1%
的困惑度(perplexity
)。
给定一个文本序列,
sequence
维度表示token id
的维度,feature
表示embedding
或activation
的维度。上述描述的含义是:
在
6B
模型,有25%
的层()出现了异常值。 在
6.7B
模型,所有的层出现了异常值;沿着token id
的方向,有75%
的位置出现了异常值();沿着 embedding/activation
的方向,有6
个位置出现了异常值()。 写成矩阵的形式:
为了支持这样极端异常值的有效量化,我们开发了混合精度分解(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
)。
相关工作:下面列出了 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
数据类型相比提供了优异的性能,但当前 GPU
和 TPU
都不支持此数据类型。
语言模型中的异常值特征(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
。
nuQmm
和 ZeroQuant
旨在加速推理和减少内存占用,而我们则关注在 8-bit
内存占用下保留预测性能。
nuQmm
和 ZeroQuant
评估的最大模型分别是 2.7B
和 20B
参数的 transformer
。ZeroQuant
实现了 20B
模型的 8-bit
量化,同时保持性能没有衰退。我们展示了我们的方法允许高达 176B
参数的模型进行 zero-degradation quantization
。nuQmm
和 ZeroQuant
表明,更细粒度的量化可以是大型模型量化的有效手段。这些方法与 LLM.int8()
是互补的。
另一个平行工作是 GLM-130B
,它使用我们工作的见解实现 zero-degradation 8-bit quantization
(《Glm-130b: An open bilingual pre-trained model》
)。GLM-130B
以 8-bit weight storage
进行完整的16-bit
精度的矩阵乘法。
相比之下,
LLM.int8()
采用8-bit
的矩阵乘法。
在这项工作中,我们通过扩展 transformer
模型将量化技术推向了极限。我们对两个问题感兴趣:
在何种模型规模下量化技术会失败,以及为何量化技术会失败?
量化技术的失败与量化精度有何关系?
为了回答这些问题,我们研究了高精度非对称量化(zeropoint quantization
)和高精度对称量化(absolute maximum quantization
)。虽然 zeropoint quantization
通过使用数据类型的 full bit-range
提供了高精度,但由于实际限制而很少使用它。absolute maximum quantization
是最常用的技术。
absmax
量化通过将输入乘以 8-bit
范围 [-127, 127]
中。因此,对于 FP16
数据类型的输入矩阵 Int8 absmax quantization
由以下公式给出:
其中:
zeropoint
量化通过如下的方式将 input distribution
移动到 full range [-127, 127]
中:首先用 normalized dynamic range
zeropoint
affine transformation
),任何输入张量都将使用数据类型的所有比特,从而减少非对称分布(asymmetric distributions
)的量化错误。例如,对于 ReLU
输出,在 absmax
量化中,所有 [-127, 0)
的值都未被使用;而在 zeropoint
量化中,完整范围 [-127,127]
都被使用。
zeropoint
量化由以下等式给出:
推导过程:假设
。我们希望把 投影到 [-127, 127]
之间。则可以采用仿射变换:然后根据
来进行量化。 根据论文
《Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference》
,zeropoint
量化的形式为:因此:
逆量化为:
。
要在操作中使用 zeropoint
量化,我们同时传入张量 zeropoint
16-bit
整数操作之前,将zeropoint quantized
数值
如果没有 multiply_i16
指令,如在 GPU
或 TPU
上,则需要展开:
注意:结果是
32-bit
整数。
其中:Int8
精度计算,其余以 Int16/32
精度计算。因此,如果没有 multiply_i16
指令,zeropoint
量化可能比较慢。
在上述两种情况下,输出以32-bit
整数
即:
具有 16-bit
浮点输入和输出的 Int8
矩阵乘法:给定隐状态 sequence dimensions
、feature dimensions
、16-bit
浮点输入和输出的 8-bit
矩阵乘法如下:
其中:
tensor-wise
的量化常数:
对于 absmax
量化,它们分别为
对于 zeropoint
量化,它们分别为
absmax
量化或 zeropoint
量化。
使用每个张量一个 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
方式之一,详细内容如下所述。
为了处理超过 6.7B
规模的所有 transformer layers
中出现的大幅值异常值特征(large magnitude outlier features
),仅仅向量化量化是不够的。为此,我们开发了混合精度分解(mixed-precision decomposition
),其中少量的大幅值的 feature dimensions
(large magnitude feature dimensions
),占比约 0.1%
以 16-bit
精度来表示,而其他 99.9%
的值以 8-bit
相乘。由于大多数元素仍以低精度来表示,与 16-bit
相比,我们仍保留约 50%
的内存减少。例如,对于 BLOOM-176B
,我们将模型的内存占用降低了 1.96
倍。
Figure 2
显示了向量化量化和混合精度分解。LLM.int8()
方法是 absmax vector-wise quantization
和混合精度分解的组合。
注意:
按列分解, 按行分解。为什么?因为异常值特征主要集中在 activation
(即,)的少部分的列。而 通常不包含异常值。 本文并没有理论指导,而是根据大模型的实验性分析从而得到的方法。
增加矩阵乘法的 scaling constants
的数量的一种方法是:将矩阵乘法视为独立内积的序列。给定隐状态 scaling constants
denormalize
每个内积结果。对于整个矩阵乘法,这相当于通过外积 denormalize
,其中 scaling constants
和列 scaling constants
的矩阵乘法的完整方程如下:
其中:
absmax
量化。
scaling constants
矩阵。
我们将其称为矩阵乘法的向量化量化。
对于向量
,它们的外积定义为:
通过我们的分析,我们证明十亿级参数的 8-bit transformer
的一个重大问题是,它们具有大幅值特征(列),这对 transformer
性能非常重要,需要高精度量化。但是,我们的最佳量化技术(即,向量化量化)对每个隐状态行进行量化,这对异常值特征(outlier features
)无效。幸运的是,我们看到这些异常值特征在实践中非常稀疏且系统化,只占所有feature dimensions
的约 0.1%
,因此允许我们开发一种新的分解技术,重点关注这些特定维度的高精度乘法。
这段话的意思是,异常值是集中在输入
的某些列,而不是集中在 的某些行。因此,对 进行按行的 scaling constants
会受到异常值的影响。
我们发现,给定输入矩阵 row
系统性地出现,但局限于特定的列。因此,我们为矩阵乘法提出混合精度分解,其中我们将包含异常值的列分离到集合 transformer
的 performance degradation
减少到接近零。使用爱因斯坦记号,其中所有索引都是上标,给定权重矩阵
其中:denormalization
项。
这种分离为 8-bit
和 16-bit
允许异常值的高精度乘法,同时使用内存高效的矩阵乘法,其中包含 8-bit
权重值(在所有权重值中占比 99.9%
以上)。由于异常值的列对于高达 13B
参数的 transformer
不超过7
(即,0.1%
的额外内存。
我们随着模型规模的增加来衡量量化方法的稳健性,规模达到 175B
参数。关键问题不是某种量化方法对特定模型的表现如何,而是随着我们增加规模,这种方法的表现趋势如何。
我们使用两种实验设置:
一种基于语言建模困惑度(language modeling perplexity
),我们发现这是一种高度稳健的指标,对 quantization degradation
非常敏感。我们使用此设置来比较不同的 quantization baselines
。
对于语言建模设置,我们使用在 fairseq
中预训练好的稠密的自回归 transformer
,参数范围在 125M
到 13B
之间。这些transformer
在 Books
、English Wikipedia
、CC-News
、OpenWebText
、CC-Stories
、English 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
语言模型评估工具箱上对这些模型进行评估。
在 C4
语料上对 125M
到 13B
的 Int8
模型的语言建模困惑度的主要结果见 Table 1
。我们看到:
随着模型规模的增加,absmax
、row-wise
和 zeropoint
等等量化都失败了,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
的优势(第二行和第三行)消失了。原因见作者后面的讨论。
当我们在 Figure 1
中查看 OPT
模型在 EleutherAI
语言模型评估工具箱上的 zero-shot
性能的缩放趋势时,我们看到:
LLM.int8()
随着规模从 125M
到 175B
参数的增加保持了 full 16-bit
性能。
另一方面,基线 8-bit absmax vector-wise quantization
随着规模的增加表现糟糕,衰退为随机性能。
虽然我们的主要关注点是节省内存,但我们也测量了 LLM.int8()
的运行时间。
与 FP16
基准相比,quantization
开销可以拖慢小于 6.7B
参数模型的推理速度。但是,6.7B
参数或更小的模型在大多数 GPU
上可以正常适配,实际中不太需要量化。
对于等效于 175B
模型的大矩阵乘法,LLM.int8()
的运行时间约快两倍。
附录 D
提供了这些实验的更多详细信息。
随着 transformer
规模的增加,大幅值的异常值特征涌现(emerge
)并强烈影响所有层及其量化。给定隐状态 sequence/token dimension
、hidden/feature dimension
。我们将特征定义为特定的 hidden/feature dimension
transformer
中所有层的特定feature dimensions
我们发现:异常值特征对注意力和 transformer
的整体预测性能有很强的影响。 13B
模型中,每个 2048 token sequence
中存在多达 150k
个异常值,但这些异常值特征非常系统化,仅覆盖不超过 7
个 unique feature dimensions
zeropoint quantization
的优势、以及为何在使用混合精度分解后这些优势消失,以及小型模型 vs.
大型模型的量化性能。
定量分析涌现现象(emergent phenomena
)的困难有两个方面。我们旨在选择少量特征进行分析,使结果可理解且不太复杂,同时捕获重要的概率模式和结构模式。我们使用一种经验方法来找到这些约束。我们根据以下标准定义异常值:特征的幅值至少为 6.0
、异常值影响至少 25%
的层、异常值影响至少 6%
的 sequence dimensions
(即,6%
的行)。
更正式地,给定具有 transformer
和隐状态 sequence dimensions
、feature dimensions
,我们将特征定义为隐状态中的特定维度 6
的维度 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
)。
我们测试了高达 13B
参数的模型。为了确保观察到的现象不是软件错误造成的,我们评估了在三个不同软件框架中训练的transformer
。我们评估了使用 OpenAI
软件的四个 GPT-2
模型、使用 Fairseq
软件的五个Meta AI
模型、以及使用 Tensorflow-Mesh
的一个 EleutherAI
模型GPT-J
。更多细节请参见附录 C
。我们还在两个不同的推理软件框架 Fairseq
和Hugging Face Transformers
中执行我们的分析。
从下表可以看到:
C4 validation perplexity
越低,出现的异常值越多。
异常值通常是单侧的,它们的四分位数范围显示,异常值的幅值比其他feature dimensions
的最大幅值大 3 ~ 20
倍,而其他feature dimensions
的范围通常为 [-3.5, 3.5]
。
随着规模的增加,异常值在 transformer
的所有层中变得越来越常见,并且它们几乎出现在所有的 sequence dimensions
中。
在 6.7B
参数时发生了一个相变(phase shift
),对于约 75%
的所有sequence dimensions
(SDim
),同一异常值出现在同一feature dimensions
的所有层中。尽管只占所有特征的约 0.1%
,但这些异常值对大的 softmax
概率至关重要。
如果删除异常值,平均 top-1 softmax
概率会缩小约 20%
。因为异常值在 sequence dimensions
absmax
量化,并有利于非对称的 zeropoint
量化。这解释了我们验证困惑度分析中的结果。
这些观察结果似乎是普遍的,因为它们出现在不同软件框架中训练的模型中(fairseq
、OpenAI
、Tensorflow-mesh
),并且它们出现在不同的推理框架中(fairseq
、Hugging Face Transformers
)。这些异常值似乎也对 transformer
架构的细微变化稳健(rotary embeddings
、embedding norm
、residual scaling
、不同初始化)。
为了证明异常值特征对注意力和预测性能至关重要,我们在将隐状态 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
所示,在 6B
至 6.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
规模后也会不稳定(如果向量相乘,而向量被填充了 magnitude
为 60
的值,很容易偶然超过最大的 16-bit
值 65535
)。
(4)
:如 Figure 4b
所示,随着 C4 perplexity
的降低,异常值特征的数量严格单调增加,而与模型大小的关系是非单调的。这表明模型困惑度而不是模型大小确定了相变。我们假设模型大小只是达到涌现所需的许多协变量中的一个重要协变量。
相变发生后,这些异常值特征高度系统化。例如,对于一个序列长度为 2048
的 6.7B
参数 transformer
,我们发现对于整个transformer
,每个 sequence
约有 150k
个异常值特征,但这些特征仅集中在 6
个不同的 hidden dimensions
中。
这些异常值对 transformer
性能至关重要。如果删除异常值,平均 top-1 softmax
概率从约 40%
降低到约 20%
,验证困惑度增加600-1000%
,即使最多只有 7
个 outlier feature dimensions
。而当我们删除 7
个随机的feature dimensions
时,top-1 softmax
概率仅降低 0.02-0.3%
,困惑度增加 0.1%
。这突显了这些feature dimensions
的关键性质。这些异常值特征的量化精度至关重要,因为即使轻微的错误也会对模型性能产生巨大影响。
我们的分析表明,特定feature dimensions
的异常值在大型 transformer
中无处不在,这些feature dimensions
对 transformer
性能至关重要。由于 row-wise and vector-wise quantization
对每个 hidden state sequence dimension
feature dimension
absmax
量化方法在 emergence
后迅速失败的原因。
但是,几乎所有异常值都有严格的非对称分布:它们要么仅为正,要么仅为负(参见附录 C
)。这使得 zeropoint
量化对这些异常值特别有效,因为 zeropoint
量化是一种非对称量化方法,可以将这些异常值缩放到完整范围 [-127, 127]
中。这解释了我们的 quantization scaling benchmark
(Table 1
)中 zeropoint
量化的强大性能。但是,在 13B
参数规模,即使是 zeropoint
量化也会由于累积的量化误差和 outlier magnitudes
的快速增长而失败,如图 Figure 4a
所示。
如果我们使用完整的 LLM.int8()
方法及混合精度分解, zeropoint
量化的优势消失,这表明 remaining decomposed features
是对称的。但是,与 row-wise quantization
相比,vector-wise
仍具有优势,这表明增强模型权重的量化精度对保持完整的预测性能至关重要。
我们首次证明,十亿参数级的 transformer
可以量化为 Int8
并立即用于推理,而不降低性能。我们通过使用我们在大规模分析出现的大幅值特征获得的见解来开发混合精度分解,从而将异常值特征隔离在单独的 16-bit
矩阵乘法中。结合我们的 vector-wise quantization
方法,我们经验证明可以恢复高达 175B
参数模型的完整推理性能。
局限性:
我们工作的主要局限性是:我们的分析仅针对 Int8
数据类型,未研究 8-bit
浮点(FP8
)数据类型。由于当前 GPU
和 TPU
不支持此数据类型,我们认为这最好留待未来工作。但是,我们也认为 Int8
数据类型的许多见解将直接转换为 FP8
数据类型。
另一个局限性是:我们只研究了高达 175B
参数的模型。虽然我们将 175B
模型量化为 Int8
而不降低性能,但在更大规模上,额外的 emergent properties
可能会破坏我们的量化方法。
第三个局限性是:我们没有对注意力函数使用 Int8
乘法。由于我们的重点是减少内存占用,而注意力函数不使用任何参数,所以这并不是绝对必要的。然而,对这个问题的初步探索表明,需要除了这里开发的之外的其他量化方法,我们留待未来工作。
最后一个局限性是:我们关注推理但不研究训练或微调。我们在附录 E
中对大规模 Int8
微调和训练进行了初步分析。大规模Int8
训练需要在量化精度、训练速度、以及工程复杂性之间进行复杂的 trade-off
,这是一个非常困难的问题。我们同样留待未来工作。
更广泛的影响:我们工作的主要影响是,使以前因 GPU
内存有限而无法适配的大型模型变得可访问。这使得以前由于 GPU
内存有限而无法进行的研究和应用成为可能,特别是对资源最少的研究人员。 Table 2
列出了现在可以在不降低性能的情况下访问的 model/GPU
组合。但是,我们的工作也使得拥有许多 GPU
的资源丰富的组织可以在相同数量的 GPU
上 serve
更多模型,这可能会增加资源丰富和资源贫穷组织之间的差距。
具体而言,我们认为公开发布大型 pretrained
模型(例如最近的 Open Pretrained Transformers: OPT
)以及我们对 zero-shot and few-shot prompting
的新的 Int8
推理,将为以前由于资源约束而无法进行的学术机构启用新的研究。这种大型模型的广泛可访问性可能对社会产生难以预测的有益的和有害的影响。
论文:
《ZeroQuant: Efficient and Affordable Post-Training Quantization for Large-Scale Transformers》
大型自然语言模型已经在不同的应用中被广泛采用,例如使用 BERT
进行自然语言理解,以及使用 GPT-style
模型进行生成任务。虽然这些模型已经取得了 SOTA
的准确性,但随着模型规模的剧增,部署它们所需的内存占用和计算成本已经成为一个主要的瓶颈,即使是在强大的 GPU
云服务器上也是如此。
量化是缓解这一挑战的一个有前景的方法,它可以降低权重和 activations
的 bit precision
,以达到更小的内存占用、以及更快的计算(例如 T4/A100
上的 INT8 Tensor cores
)。然而,量化通常需要重新训练(也称为 quantization aware training: QAT
)来恢复由 weight and activations
的 representation 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
,以解决这些挑战,目标是 INT8
和 INT4/INT8
混合精度量化。具体来说,我们的贡献如下:
我们对权重和 activations
应用细粒度的硬件友好的量化方案,即权重的 group-wise quantization
(即,列维度)、以及 activations
的 token-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
可以将 BERT
和 GPT-3-style
模型量化为 INT8
权重和 activations
从而保留准确性,而不会产生任何重新训练成本。与 FP16
推理相比,在 A100 GPU
上,我们的 INT8
模型在 BERT_base/GPT-3_350M
上获得了高达 5.19x/4.16x
的加速。
ZeroQuant puls LKD
可以进行 BERT
和 GPT-3-style
模型的 INT4/INT8
混合精度量化。与 FP16
模型相比,这导致了 3
倍的内存减少,准确率损失可以忽略。而且,得益于 LKD
的轻量级,我们可以在 33
秒(BERT_base
)和 10
分钟(BERT_large
)内完成量化过程。我们还展示 LKD
可以使用其他数据集达到类似于原始训练数据的性能。
我们展示了 ZeroQuant
在两个最大的开源语言模型 GPT-J_6B
和 GPT-NeoX_20B
上的可扩展性,使用 INT8
量化。ZeroQuant
可以在 GPT-J_6B
上实现比 FP16
模型快 3.67
倍;并且 ZeroQuant
将 GPT-NeoX_20B
的 GPU
需求从 2
减少到 1
,延迟从 65ms
降低到 25ms
(整体系统效率提高 5.2
倍)。
本文的主要贡献是两个:
layer-by-layer knowledge distillation
、以及高度优化的推理后端。
相关工作:人们从不同方面探索了模型压缩。其中,量化是最有前景的方向之一,因为它可以直接减少内存占用和计算强度。这里我们聚焦 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
(如 CPU
和 GPU
)上获得真实的inference latency
收益,因为这些硬件中的 parallel processing units
不支持混合数据类型的有效计算。
更近期地,《Understanding and overcoming the challenges of efficient transformer quantization》
为模型的一部分引入了高精度的 activation quantization
(FP16
)以克服 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
的能力,用于各种任务。
我们在附录 A
中简要概述了 Transformer
架构和量化背景。请参阅 《Attention is all you need》
和 《A survey of quantization methods for efficient neural network inference》
以了解更多关于 Transformer
架构和量化的细节。
与 QAT
相比,PTQ
展现了更大的压缩效率,因为 PTQ
通常被用于 quantize the model
而无需重新训练。PTQ
的一种常见策略是将训练数据馈入网络,并使用 running mean
来校准 scaling factor
B.1
。
一些工作已经在 BERT_base
模型上完成,使用 INT8
权重和混合 INT8/FP16
的 activation
量化。然而,还没有针对:
(1)
:BERT
模型上的更 bit-precision
的 PTQ
进行研究。
(2)
: 大型 GPT-3-style
模型进行研究。
这里,我们简要讨论在 BERT
(见附录 C
)和 GPT-3-style
模型上应用 PTQ
的挑战。
Table 1
显示了带 PTQ
的 GPT-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/8A16
的 GPT-3_350M
无法再生成任何有意义的文本。
BERT
的分析请参见附录 C
。
WaAb
表示:对权重采用a-bit
、对activation
采用b-bit
。
W4/8A16
表示:对权重混合采用4-bit
和8-bit
、对activation
采用16-bit
。其中,将自注意力计算的权重量化为INT8
、feed-forward connection: FFC
的权重量化为INT4
。
W8A8/16
表示:对权重采用8-bit
、对activation
混合采用8-bit
和16-bit
。其中,将自注意力计算的input activation
使用FP16 activation
,对其余计算使用INT8
。
Dynamic Activation Range
:为了研究为什么 INT8 activation
对 BERT
和 GPT-3-style
模型都导致显著的准确率下降,我们在 Figure 1(left)
中绘制了 GPT-3_350M
不同 Transformer layers
的每个 activation
的 token-wise
(即,行维度)的 range
。可以看出,不同 token
具有极大的 activation ranges
差异。例如,最后一层的 maximum range
约为 35
、而 minimum range
接近 8
。这种 activation range
的较大方差使得使用固定的 quantization range
(通常是最大值)对所有token
进行量化以保持预测准确率变得困难,因为对于 small range tokens
的 limited representation
能力会损害准确率性能。
Different Ranges of Neurons in Weight Matrices
:类似地,我们在 Figure 1(right)
中绘制了 GPT-3_350M
的 attention output matrix
(即,output dimension)
)的 weight range
。不同行之间的 largest magnitudes
存在 10
倍的差异,这导致 INT8 weight PTQ
的 generation
性能变差。当应用 INT4
量化时,这也提出了很大的挑战,因为 INT4
只有 16
个数字,更小 10
倍的范围导致这些 smaller-range rows
的 representations
只有 2
或 3
个数字。
这些分析结果也表明了为什么需要更昂贵的 hidden-states knowledge distillation
来进行 ultra-low precision quantization
以弥合准确率差距。但是,由于大型模型的训练成本太高,因此需要一个轻量级的和高效的方法进行 PTQ
。
如前所述,即使对 BERT/GPT-3-style
模型应用 INT8 PTQ
也会导致显著的准确率下降。关键挑战是 INT8
的 representation
并不能完全捕获权重矩阵中不同行的、以及不同 activation tokens
的数值范围。一种解决方法是对权重矩阵(或 activations
)采用 group-wise (token-wise) quantization
。
Group-wise Quantization for Weights
: group-wise weight matrix quantization
首先在 《Q-BERT: Hessian based ultra low precision quantization of bert》
中被提出,其中权重矩阵 《Q-BERT: Hessian based ultra low precision quantization of bert》
中,作者仅将此应用于 quantization aware training
。更重要的是,他们没有考虑硬件效率约束(hardware efficiency constraint
),也没有系统后端支持。因此,他们缺乏真实的 latency reduction
效益。
在我们的设计中,我们考虑了 Ampere Architecture
的 GPU
(例如 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
是怎么实现的?读者猜测是对权重矩阵按照列一个 block
来进行量化。
选择什么样的值?论文并未说清楚。
Token-wise Quantization for Activations
:如前面内容和附录 A.2
所述,现有 PTQ
工作的一种常见做法是:对 activation
使用静态量化,其中 min/max range
在离线校准阶段(offline calibration phase
)计算。这种方法对于 activation range
方差较小的小型模型可能就足够了。然而,正如前面分析的那样,对于 GPT-3_350M
和 BERT_base
等大型 Transformer
模型,activation range
存在巨大的方差。因此,静态量化方案(通常应用于所有 tokens/samples
)会导致显著的准确率下降。克服这个问题的一个自然想法是:采用更细粒度的 token-wise quantization
,并为每个 token
动态地计算 min/max range
以减少来自 activations
的量化误差。我们在实验部分的评估也显示了 token-wise quantization
对 GPT-3-style
和 BERT
模型的准确率有显著改善。
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 scales
对 INT32 accumulation
进行缩放。这些优化将在接下来详细讨论。
token-wise quantization
可以显著减少 quantized activations
的 representation error
。而且,由于它不需要校准 activation range
,接下来我们将展示对于中等量化方案( INT8 weight with INT8 activation
),ZeroQuant
不会产生任何与量化相关的成本(例如 activation range calibration
)。
注意,论文实验部分提到,对于大型模型(如
GPT-NeoX_20B
),需要将自注意力的input activation
保持为FP16
。如果将自注意力的input activation
量化为INT8
甚至INT4
,则会带来accuracy loss
。
知识蒸馏(knowledge distillation: KD
)是减轻模型压缩后准确率下降的最强大方法之一。然而,KD
存在几个局限性,特别是在大型语言模型上的 hidden-states KD
:
(1)
:KD
需要在训练期间同时持有 teacher
模型和 student
模型,这大大增加了内存和计算成本。
(2)
:KD
通常需要 full training
学生模型。因此,需要在内存中存储权重参数的若干副本(梯度、一阶动量、二阶动量等)以更新模型。
(3)
:KD
通常需要原始训练数据,而由于隐私/保密问题,有时无法访问这些数据。
为解决这些局限性,我们提出了 layer-by-layer distillation: LKD
算法。假设要量化的目标模型有 transformer blocks
,LKD
逐层地对网络进行量化,并使用其原始版本(即 unquantized
版本)作为 teacher
模型。
具体而言,假设层 quantized
版本是 first k-1 layers
上对
其中: MSE
是均方误差,也可以替换为其他损失函数(例如 KL
散度)。
可以看出:
(1)
:我们的 LKD
不需要单独的 teacher
模型,因为我们对 teacher/student
模型都使用相同的
每次仅仅调整
quantized
版本的一层,因此是一种贪心算法。
(2)
:optimizer states
的内存开销显著减少,因为唯一优化的层是
(3)
:由于我们从不优化 end-to-end model
,训练不再依赖标签。后面我们将在实验章节中展示 LKD
不依赖于原始训练数据。
论文的实验部分展示:即使采用随机生成的
token ids
,LKD
也能够提升模型的性能。从实验部分可以看到:
LKD
对于生成式任务的提升,相比分类任务,要更大。
优化 inference latency
和模型大小对于实际部署大型 Transformer
模型至关重要。在推理期间,batch size
通常相对较小,所以模型的 inference latency
主要取决于从主内存加载所需推理数据的时间。通过将 weights and activations
量化为较低精度,我们减少了加载这些数据所需的数据量,这允许更有效地利用内存带宽、以及更高的加载吞吐量。但是,简单地将 weights/activations
转换为 INT8
并不能保证改善延迟,因为存在一些与 quantization/dequantization
操作相关的额外的数据移动开销,如 Figure 2
所示的红色框。这样的开销变得昂贵,在某些情况下超过了使用低精度的性能收益。
为了获得 token-wise quantization
带来的准确率提升和延迟改善,我们现在介绍我们的优化:通过最大化内存带宽利用率(memory bandwidth utilization
)来加速 ZeroQuant
的inference latency
。
CUTLASS INT8 GeMM
:为支持 INT8
计算, 我们使用针对不同 batch sizes
进行了调优的 CUTLASS INT8 GeMM
实现。与标准 GPU
后端库(如 cuDNN
)不同,使用 CUTLASS
允许我们更灵活地在 GeMM
之前和之后融合量化操作,以减少 kernel launching
和数据移动的开销。
Fusing Token-wise Activation Quantization
:token-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
中的蓝色框所示。
通过上述优化,我们能够在实验章节中展示 BERT
和 GPT-3-style
模型的显著的延迟减少。有关我们的系统优化的更多细节,请参见附录 D
。
为评估提出的 ZeroQuant
,我们在 BERT
和 GPT-3
模型上测试它。
对于 BERT
,我们在 GLUE benchmark
中测试了 BERT_base
和 BERT_large
。
对于 GPT-3-style
模型,我们在 20
个 zero-shot
评估任务上测试了 GPT-3_350M
(即具有 350M
参数的 GPT-3-style
模型)和 GPT-3_1.3B
(即具有 1.3B
参数的 GPT-3-style
模型),包括 19
个 accuracy-based
任务和 1
个 language modeling generation
任务。
为了展示提出的 ZeroQuant
的可扩展性,我们还直接将其应用于两个最大的开源 GPT-3-style
模型,即 GPT-J_6B
和 GPT-NeoXP20B
。对于所有与 LKD
相关的实验,我们使用固定的超参数集合,尽管调优它们可能有利于我们的结果。请参阅附录 B.2
以获得更多关于训练的详细信息,并参阅附录 B.3
以获得报告的 BERT
指标。为提供全面研究,我们还在附录 E
中包括 BERT
的调参结果、以及针对本节中不同的 proposed components
的消融研究。
符号解释:
我们使用 WxAy
表示对权重使用 x-bit
量化、对 activation
使用 y-bit
量化。
除非特别说明:
对于 W4/8
,我们将 multi-head self attention: MHSA
的权重量化为 INT8
、feed-forward connection: FFC
的权重量化为 INT4
。
对于 A8/16
,我们对自注意力计算(即与 GeMM
)使用 FP16 activation
,对其余计算使用 INT8
。
我们使用 ZeroQuant
来表示仅具有细粒度量化方案的方法;使用 ZeroQuant-LKD
来表示同时具有细粒度量化方案和 LKD
的方法。
BERT_base
:我们在 Table 2
中报告 BERT_base
的结果。
对于 W8A8
,PTQ
的平均准确率降低了 6
分左右。 然而,ZeroQuant
可以达到 83.75
分,仅比基线低 0.2
。 具体而言,由于ZeroQuant
没有 activation range calibration
阶段,其成本为 0
,甚至比标准 PTQ
更便宜。
与 《Understanding and overcoming the challenges of efficient transformer quantization》
相比(即,[6]
,1.29
)。 与此同时,与 ZeroQuant
中使用的 INT8 activation
相比,[6]
使用 mixed INT8 and FP16 activation
。
我们还将我们的方法与内部训练的 QAT
和其他 QAT
工作(《Q-BERT: Hessian based ultra low precision quantization of bert》
,即 [56]
《Q8BERT: Quantized 8bit bert》
,即 [76]
QAT
方法获得的准确率结果相媲美,针对 INT8
量化,ZeroQuant
可以将重新训练成本从 2900s
降低到 0s
(即,无需重新训练)。
对于更激进的、具有 minimal (or no) training quantization
的权重量化,即 W4/8A16
,PTQ
完全丢失了所有准确率(纯随机预测)。 然而,ZeroQuant
仍然可以达到 81.65
的平均分数。在 ZeroQuant
的基础上,如果我们添加 LKD
,则准确率可以进一步提升到82.35
,每个任务的成本仅为 31s
,仅使用单个 GPU
,与 INT8 QAT
量化相比,节省了 93.5
倍的成本。
BERT_large
:我们也在 BERT_large
上测试我们的方法,结果如 Table 3
所示。
与BERT_base
类似,ZeroQuant
的准确率明显优于 PTQ
方法。与 QAT
方法相比,ZeroQuant
在更大的数据集(如 MNLI/QQP
)上具有可比结果,并在小任务(例如 CoLA/MRPC/RTE
)上具有更好的性能。我们实际上为 QAT
调优了多个学习率,但即使对于这些小任务也无法获得更好的性能(请参阅附录 F
以获取更多详细信息)。
对于更激进的量化方案,如 W4/8A16
和 W4/8A8
,ZeroQuant
和 ZeroQuant-LKD
仍然达到了很好的准确率,除了 RTE
之外,模型大小约为 FP16
模型的 3
倍。这与 INT8 QAT
结果一致,后者在 RTE
上损失了更多的准确率。由于 LKD
的轻量级成本,即使在 BERT_large
上也只需要大约 550s
就可以完成每个任务,比 QAT
便宜 13
倍。
GPT-3_350M
:我们首先在 GPT-3_350M
上测试 ZeroQuant
和 ZeroQuant-LKD
,并在 Table 4
中报告结果。
GPT-3-style
模型上的 zero-shot
评估的第一个有趣发现是,与生成式任务相比,accuracy-based
任务的 accuracy performance
更能容忍量化。例如,W8A8 PTQ
在 19
个 accuracy-based
的任务上平均准确率下降了 1.1%
,相比之下在 Wikitext-2
上下降 4.7
分。
在 W8A8
上,将 ZeroQuant
与 PTQ
进行比较,我们可以将 accuracy gap
从 1.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
上。请注意,这约为完整预训练成本(128
个A100 GPU
,32
小时)的 0.027%
的 GPU hours
。
在 W4/8A8
上,与 W4/8A16
类似,ZeroQuant-LKD
通过使用轻量级 LKD
比 ZeroQuant
获得了更好的性能。
PTQ
为什么需要时间?因为它对activation
使用静态量化,其中min/max range
在离线校准阶段(offline calibration phase
)计算。
GPT-3_1.3B
:GPT-3_1.3B
的结果如 Table 5
所示。与 GPT-3_350M
类似:
对于 W8A8
,与 PTQ
相比,ZeroQuant
的性能更好,无 activation calibration
成本,特别是对于生成式任务 Wikitext-2
(低 3.2
分)。
此外,对于 W4/8A8
量化,LKD
可以为ZeroQuant
带来重大的性能收益。LKD
的成本约为完整预训练成本(128
个 A100 GPU
,120
小时)的 0.02%
。
我们在 Table 6
中比较了单个 40G-A100 GPU
上, BERT
的 FP16
版本和我们的 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
的加速。
为演示 ZeroQuant
的可扩展性,我们将其应用于两个最大的开源模型,即 GPT-J_6B
和 GPT-NeoX_20B
,它们分别具有 6B
和 20B
参数。
我们在 Table 7
中报告了 GPT-J_6B
在三个 generation
数据集(即 PTB
、Wikitext-2
和 Wikitext-103
)上的结果。
可以看到,ZeroQuant
在所有三个不同任务上都实现了与 FP16
相差无几的 PPL
。
为了比较延迟,我们再次使用生成前 50 tokens
的平均延迟数。与 FP16
版本相比,我们的 W8A8
可以获得高达 3.67
倍的加速。
为 GPT-NeoX_20B
的所有 GeMM
来量化到 W8A8
会导致准确率显著下降。我们检索每个权重矩阵和每个 activation
的量化,并最终发现:注意力计算的 activation quantization
(即,自注意力的输入)导致了 accuracy loss
。我们推测这是由于超大模型(20B
参数)中自注意力模块的敏感性造成的,但由于缺乏开源的超大模型和完整的评估流程,我们无法在其他模型上验证这一点。 因此,我们将自注意力的 input activation
保持为 FP16
,其余部分量化为 INT8
。结果如 Table 8
所示。我们的 W8A8/16
实现了与 FP16
类似的准确率,但可以减少 GPU
资源需求(从 2
个 A100 GPU
减少到 1
个)和延迟(从 65ms
降低到 25ms
),这两者共同导致了 5.2
倍更好的吞吐量/效率。
为了研究我们引入的每个组件的性能提升,即 group-wise weight quantization
、token-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
分的提升。
如前几节所述,由于隐私和/或保密问题,原始训练数据通常很难访问。因此,我们这里研究当没有直接访问原始训练数据时,我们的LKD
的性能。由于 LKD
的蒸馏目标不依赖标签,LKD
使用的训练数据可以非常灵活。
我们使用三种不同的训练数据资源,从而比较 GPT-3_350M
在 W4/8A8
量化方案上的性能:即,随机数据(使用随机整数编号生成 token ids
)、维基百科(使用 Huggingface
获取数据)、原始 PILE
数据集。结果如 Table 10
所示。
与 ZeroQuant
相比,使用随机数据的 LKD
可以将准确率提高 1.1%
,困惑度从 92.1
降低到 40.6
。随机数据仍然可以显著提高性能的原因是:LKD
不优化 end-to-end pipeline
,而是仅逐层学习来自 teacher
模型的内部依赖关系。因此,随机数据也可以提供有意义的信息。
使用 Huggingface
的 Wikipedia
数据可以进一步将准确率提高到 36.2
,困惑度降低到 30.4
,这与使用原始数据的结果相当。这表明,当我们无法访问完整的原始数据集时,可以使用干净的文本数据集进行 LKD
。
论文:
《SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models》
大型语言模型(LLM
)在各种任务上展示了出色的性能。然而,由于模型规模巨大,部署 LLM
需要大量的预算和能源。例如,GPT-3
模型包含 175B
参数,至少需要 350GB
内存来存储和以 FP16
运行,仅进行推理就需要 8 * 48GB A6000 GPU
或 5 * 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
相比,权重和 activations
的 INT8
量化可以将 GPU
内存使用量减半,矩阵乘法的吞吐量提高近一倍。
然而,与 CNN
模型或较小的 transformer
模型如 BERT
不同,LLM
的 activations
很难量化。当我们将 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-350M
和 GPT-J-6B
提供良好的准确率。但是,它无法为具有 175B
参数的大型 OPT
模型维持准确率。
LLM.int8()
通过进一步引入混合精度分解(即它将异常值保持为 FP16
,其他 activations
使用 INT8
)来解决该准确率问题。但是,在 hardware accelerators
上高效地实现该分解很困难。
因此,为 LLM
派生出一种高效的、硬件友好的、最好不需要训练的量化方案,该方案会对所有计算密集型操作使用 INT8
,仍是一个开放性挑战。
我们提出了 SmoothQuant
,这是一种准确的、高效的后训练量化(post-training quantization: PTQ
)解决方案从而用于 LLM
。SmoothQuant
依赖于一个关键观察:由于存在异常值,即使 activations
比权重更难量化,不同 tokens
在其 channels
上表现出类似的变化。基于此观察,SmoothQuant
离线地将quantization difficulty
从 activations
迁移到权重(Figure 2
)。 SmoothQuant
提出了一种数学等价的 per-channel scaling transformation
,可以显著平滑通道间的幅值,使模型对量化更加友好。由于SmoothQuant
兼容各种量化方案,我们为 SmoothQuant
实现了三种效率级别的 quantization setting
(见 Table 2
的 O1-O3
)。实验表明,SmoothQuant
具有硬件效率:它可以维持 OPT-175B
、BLOOM-176B
、GLM-130B
和 MT-NLG 530B
的性能,在 PyTorch
上获得高达 1.51
倍的加速和 1.96
倍的内存节省。SmoothQuant
易于实现。我们将 SmoothQuant
集成到 FasterTransformer
中(这是 SOTA
的 transformer serving
框架),与 FP16
相比,实现了高达 1.56
倍的加速,以及内存占用减半。值得注意的是,相比较于 FP16
,SmoothQuant
允许仅使用一半 GPU
数量就可以 serving
像 OPT-175B
等大型模型,而且更快,并可以在单个 8-GPU
节点上部署 530B
模型。我们的工作通过提供一键解决方案来减少 serving
成本,推广了 LLM
的使用。我们希望 SmoothQuant
可以在未来激发 LLM
的更广泛应用。
注意:
SmoothQuant-O1/O2/O3
对权重均采用per-tensor
量化,区别仅在于activations
上的量化方式。
相关工作:
大型语言模型:通过 scaling up
,pre-trained
语言模型在各种基准测试中实现了显着的性能。GPT-3
是首个超过 100B
参数的LLM
,并在 few-shot/zero-shot learning
中取得了令人印象深刻的结果。后续工作继续推进 scaling
的前沿,超过了500B
参数。但是,随着语言模型变大,为这些模型提供推理变得昂贵和具有挑战性。在本文中,我们展示了所提出的方法可以量化三个最大的开源 LLM
(OPT-175B
、BLOOM-176B
和 GLM-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
。它们分别评估的最大模型为 20B
和 2.7B
,未能维持 OPT-175B
等 LLM
的性能。
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-Norm
和 token-wise clipping
来处理 activation outliers
。但是,它只在小型语言模型(如 BERT
和 BART
)上成功,未能维持 LLM
的准确率(Table 4
)。
我们的算法以高效的 per-tensor
的、静态的量化方案保留了LLM
的性能(高达 176B
,我们能找到的最大的开源 LLM
),而无需重新训练,允许我们使用开箱即用的 INT8 GEMM
来实现高的硬件效率。
从
Table 4
可以看到,LLM.int8()
的效果相当好,和表现最佳的SmoothQuant
相比相差无几甚至更好。而且在175B
模型上,LLM.int8()
的推理速度可以高达2
倍(相比于FP16
)。
量化将一个 high-precision value
映射到离散级别(discrete levels
)。我们研究整数(具体为 INT8
)的 uniform quantization
(《Quantizationand training of neural networks for efficient integer arithmetic-only inference 》
)以获得更好的硬件支持和效率。量化过程可以表示为:
其中:
quantization step size
),rounding
函数,bits
数量(在我们这个 case
中是 8
)。
这里为简单起见,假设张量 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 samples
的 activations
来离线地计算 static quantization
)。
我们也可以使用 activations
的运行时统计信息(runtime statistics
)得到 dynamic quantization
)。
如 Figure 3
所示,量化具有不同的粒度级别:
per-tensor quantization
对整个矩阵使用单个步长。
通过为每个 token
相关联的 activations
((per-token quantization
)、或权重的每个 output channel
相关联的 activations
( per-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
矩阵按行量化,即每一行对应一个步长。
对于transformer
中的线性层(参见 Figure 3
,为简单起见,我们省略了 batch
维度):
其中:
input activations
,token
数量,
output activations
。
通过将权重量化为 INT8
,相比 FP16
,我们可以将模型存储量减半。但是,为了加速推理,我们需要将权重和 activations
都量化为 INT8
(即 W8A8
),从而利用 integer kernels
(如 INT8 GEMM
),这些 integer kernels
被广泛的硬件所支持(如NVIDIA GPU
、Intel CPU
、Qualcomm DSP
等)。
由于 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 channels
的 effective quantization bits/levels
较低(Figure 2
):假设通道 maximum magnitude
为 effective quantization levels
为 non-outlier channels
,effective quantization levels
将非常小(2-3
),导致较大的量化误差。
即,在
non-outlier channels
上,量化后的结果都聚集在少数的bins
上,导致逆量化之后都集中在少数几个值上。
(3)
:异常值出现在固定的通道中。
对于 activations
,异常值仅出现在少数通道中。如果一个通道有一个异常值,它会持续出现在所有 tokens
中( Figure 4
,红色)。
给定一个 token
,它的各个通道之间的 activations
方差很大(某些通道中的 activations
非常大,但大多数很小)。
但给定一个通道,它的跨 tokens
之间的 activations
方差很小(异常值通道中的 activations
一致地很大)。
由于异常值的 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》
的发现一致。
对于
activations
,per-token quantization
就是按行进行量化,per-channel quantization
就是按列进行量化。为什么说这里是 “模拟” 的?因为目前的硬件不支持
activations
的per-channel quantization
,因此作者采用模拟的手段来实现相同的效果。
然而,per-channel activation quantization
与硬件加速的 GEMM kernels
不匹配,这些 GEMM kernels
依赖于高吞吐量地执行的 a sequence of operations
(如 Tensor Core MMAs
) ,并且不容忍在该序列中插入吞吐量较低的指令(例如,转换、或 CUDA Core FMAs
)。在这些 kernels
中,scaling
只能沿矩阵乘法的 outer dimensions
执行(即 activations
的 token dimension
output channel dimension
Figure 3
)。这种 scaling
通过在矩阵乘法完成后应用如下操作来实现:
其中:activations
和权重。
因此,先前的工作都为线性层使用 per-token activation quantization
(Llm.int8(), Zeroquant
),尽管它们无法解决 activation quantization
的困难(仅比 per-tensor quantization
量略好)。
我们提出平滑 input activation
而不是执行 per-channel activation quantization
(这不可行),方法是将 input activation
除以 per-channel smoothing factor
其中:
即,对
activation
矩阵的第列除以 ,同时对权重矩阵的第 行乘以 。
考虑到输入 linear layers
、layer norms
等),我们可以轻松地将平滑因子(smoothing factor
)离线地融合到前一层的参数中,这不会导致 an extra scaling
的 kernel call
的开销。对于其他一些情况,当输入 residual add
时,我们可以像 《Outlier suppression: Pushing the limit of low-bit transformer language models》
那样,在 residual branch
中添加 an extra scaling
。
关于如何融合平滑因子,可以参考论文的实现代码。
将 quantization difficulty
从 activations
迁移到权重:我们的目标是选择 per-channel smoothing factor
effective quantization bits
。当所有通道具有相同的maximum magnitude
时,total effective quantization bits
将最大。因此,一个直观的选择是:
其中
这种选择确保在除法之后,所有 activation channels
将具有相同的最大值,很容易量化。注意,activations
的范围是动态的;它对不同的输入样本各不相同。这里,我们使用预训练数据集中的 calibration samples
来估计 activations channels
的 scale
(《Quantization and training of neural networks for efficient integer arithmetic-only inference》
)。
然而,这个公式将所有 quantization difficulty
都推到权重上。我们发现,在这种情况下,权重的量化误差会很大(outlier channels
现在迁移到权重上),导致很大的准确率下降(参见 Figure 10
)。
另一方面,我们也可以通过选择 quantization difficulty
从权重推到 activations
。类似地,由于activation
量化误差,模型性能不佳。因此,我们需要在权重和 activations
之间分担 quantization difficulty
,以使它们都易于量化。
这里我们引入一个超参数,迁移强度(migration strength
)activations
迁移到权重的难度量,使用以下等式:
我们发现,对于大多数模型(例如所有的 OPT
和 BLOOM
模型),quantization difficulty
,尤其是在我们对权重和 activations
使用相同的 quantizer
时(例如 per-tensor
的静态量化)。该公式确保权重和 activations
在相应的通道上共享相似的最大值,因此共享相同的 quantization difficulty
。Figure 5
说明了当我们取 smoothing transformation
。 对于 activation outliers
更明显的一些其他模型(例如 GLM-130B
有约 30%
的异常值,这对 activation quantization
更具挑战性),我们可以选择较大的 quantization difficulty
迁移到权重(如
将 SmoothQuant
应用于 Transformer blocks
:线性层占了 LLM
模型的参数和计算的大部分。默认情况下,我们对自注意力和前馈层的 input activations
执行 scale smoothing
,并使用 W8A8
量化所有线性层。我们还量化注意力计算中的 BMM
算子。我们在 Figure 6
中设计了 transformer
模块的量化流程。我们使用 INT8 quantization
计算 compute-heavy
的算子(如线性层和注意力层中的 BMM
)的输入和权重,而将其他轻量级 element-wise
算子(如 ReLU
、Softmax
和 Layer-Norm
)的 activation
保持为FP16
。这种设计帮助我们在精度和推理效率之间取得平衡。
BMM
:batch
的matrix-matrix
乘法。
baselines
:我们在 INT8 post-training quantization setting
(即,不重训模型参数)中与四个基准进行比较:W8A8 naive quantization
、ZeroQuant
、LLM.int8()
、Outlier Suppression
。
由于 SmoothQuant
与量化方案正交,我们提供从 O1
到 O3
逐渐激进的和有效的 quantization levels
。基准和 SmoothQuant
的详细量化方案如 Table 2
所示。
模型和数据集:
我们选择三个 LLM
系列来评估 SmoothQuant
:OPT
、BLOOM
和 GLM-130B
。
我们使用七个 zero-shot evaluation tasks
:LAMBADA
、HellaSwag
、PIQA
、WinoGrande
、OpenBookQA
、RTE
、COPA
,以及一个语言建模数据集 WikiText
来评估 OPT
和 BLOOM
模型。
我们使用 MMLU
、MNLI
、QNLI
和 LAMBADA
来评估 GLM-130B
模型,因为上述一些基准出现在 GLM-130B
的训练集中。
我们使用 lm-eval-harness
来评估 OPT
和 BLOOM
模型,使用 GLM-130B
的官方仓库评估其本身。
最后,我们将方法扩展到 MT-NLG 530B
,首次在单节点内实现了对大于 500B
模型的 serving
。
注意,我们关注量化前后模型的相对性能变化而不是绝对值变化。
Activation smoothing
:迁移强度 OPT
和 BLOOM
模型的通用最佳点;而对于量化更具挑战性的 activations
的 GLM-130B
,Pile
验证集的一个子集上快速 grid search
以获得合适的 activations
的统计信息,我们一次性地使用预训练数据集 Pile
中的 512
个随机句子,从而校准 smoothing factors
和 static quantization step sizes
,并将相同的 smoothed and quantized model
应用于所有下游任务。通过这种方式,我们可以 benchmark
量化后的 LLM
的普适性和zero-shot
性能。
实现:我们使用两个后端实现 SmoothQuant
:
(1)
: PyTorch Huggingface
进行概念验证。
(2)
: FasterTransformer
作为生产环境中使用的高性能框架的示例。
在 PyTorch Huggingface
和 FasterTransformer
框架中,我们都使用 CUTLASS INT8 GEMM kernels
实现了 INT8
线性模块和 batched matrix multiplication: BMM
函数。我们简单地用我们的 INT8 kernels
替换原始的浮点(FP16
)线性模块和 bmm
函数,从而作为 INT8
模型。
OPT-175B
的结果:SmoothQuant
可以处理非常大的 LLM
的量化,其中,这种大型 LLM
的 activations
更难以量化。我们在 OPT-175B
上研究量化。如 Table 3
所示:
SmoothQuant
可以在所有评估数据集上在所有量化方案上匹配 FP16
的准确率。
LLM.int8()
可以匹配浮点的准确率,因为他们使用浮点值来表示异常值,这会导致很大的延迟开销(Table 10
)。
W8A8
、ZeroQuant
和 Outlier Suppression
等 baselines
产生几乎随机的结果,表明朴素地量化 LLM
的 activation
将破坏性能。
在这三种
SmoothQuant
变体中,SmoothQuant-O3
的实现最简单(静态的per-tensor
量化),但是效果也还不错。
不同 LLM
的结果:SmoothQuant
可以应用于各种 LLM
。在 Table 4
中,我们展示 SmoothQuant
可以量化所有现有的超过 100B
参数的开源 LLM
。
与 OPT-175B
模型相比,BLOOM-176B
模型更容易量化:没有 baselines
完全破坏模型;即使是朴素的 W8A8 per-tensor dynamic quantization
也只降低了 4%
的准确率。
SmoothQuant
的 O1-level
和 O2-level
成功地维持了浮点的准确率,而 O3-level
(per-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
,我们希望这能激发未来的研究。
注意:对于给定的量化方法,即使它在某个大模型上表现较好,也无法断定它在另一些大模型上表现也好。例如,
ZeroQuant
在BLOOM-176B
上表现较好,但是在OPT-175B
上表现很差。
不同大小的 LLM
的结果:SmoothQuant
不仅适用于超过 100B
参数的非常大的 LLM
,而且也适用于较小的 LLM
。在 Figure 7
中,我们展示 SmoothQuant
可以适用于所有规模的 OPT
模型,使用 INT8 quantization
匹配 FP16
的准确率。
Instruction-Tuned LLM
的结果:如 Table 5
所示,SmoothQuant
也适用于Instruction-Tuned LLM
。我们在 OPT-IML-30B
模型上使用 WikiText-2
和 LAMBADA
数据集测试 SmoothQuant
。我们的结果表明:SmoothQuant
成功地以 W8A8 quantization
保留了模型准确率,而 baselines
未能做到这一点。SmoothQuant
是为 transformer
模型平衡 quantization difficulty
而设计的通用方法。由于Instruction-Tuned LLM
的架构与普通 LLM
在本质上没有不同,它们的预训练过程也非常相似,因此 SmoothQuant
也适用于Instruction-Tuned LLM
。
LLaMA
模型的结果:LLaMA
模型是具有卓越性能的新的开源语言模型。通过初步实验,我们发现:与 OPT
和 BLOOM
等模型相比,LLaMA
模型通常具有更轻度的 activation outlier
问题。尽管如此,SmoothQuant
对 LLaMA
模型仍然非常有效。我们在 Table 6
中给出了 LLaMA W8A8 quantization
的一些初步结果。W8A8 SmoothQuant
的性能与 FP16 baseline
相差无几。
在这一节中,我们展示了集成到 PyTorch
和 FasterTransformer
中的 SmoothQuant-O3
所测量到的加速和内存节省。
Context-stage: PyTorch Implementation
:针对 a batch of 4 sentences
,我们测量在 one pass
中生成所有隐状态的端到端延迟,即上下文阶段延迟(context stage latency
)。我们记录此过程中的(聚合后的)峰值 GPU
内存使用。我们仅将SmoothQuant
与 LLM.int8()
进行比较,因为后者是唯一可以在所有规模上保持LLM
准确率的现有量化方法。
由于 Huggingface
不支持模型并行,针对 PyTorch
实现,我们只在单 GPU
上测量 SmoothQuant
的性能,因此我们选择 OPT-6.7B
、OPT-13B
和 OPT-30B
进行评估。
在 FasterTransformer
库中,SmoothQuant
可以与张量并行算法无缝协作,所以我们同时针对单 GPU
和多GPU
基准测试,在 OPT-13B
、OPT-30B
、OPT-66B
和OPT-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
的大开销。
在内存方面,SmoothQuant
和 LLM.int8()
都将 FP16
模型的内存使用减少了近一半,而 SmoothQuant
节省的内存略多,因为它使用 fully INT8 GEMMs
。
Context-stage: FasterTransformer Implementation
:如 Figure 9 (top)
所示,与 OPT
的 FasterTransformer's FP16
实现相比,SmoothQuant-O3
可以将单 GPU
上,将 OPT-13B
和 OPT-30B
的执行延迟降低最多 1.56
倍。这具有挑战性,因为与PyTorch
实现相比,FasterTransformer
的 OPT-30B
已经快了 3
倍以上。
值得注意的是,对于必须跨多个 GPU
分配的更大模型,SmoothQuant
使用仅一半数量的 GPU
(对于OPT-66B
,只需要 1
个 GPU
而不是 2
个;对于 OPT-175B
,只需要 4
个 GPU
而不是 8
个)实现了类似甚至更好的延迟。这可以大大降低 serving LLM
的成本。
Figure 9 (bottom)
显示,在 FasterTransformer
中使用 SmoothQuant-O3
时所需的内存减少了近 2
倍。
Decoding-stage
:在 Table 7
中,我们展示 SmoothQuant
可以显著加速 LLM
的自回归解码阶段。
与 FP16
相比,SmoothQuant
一致地降低 per-token decoding
延迟(最高 1.42
倍加速)。
此外,SmoothQuant
将 LLM
推理的内存占用减半,使 LLM
部署的成本大大降低。
我们可以进一步将 SmoothQuant
扩展至超过 500B
级别的模型,实现 MT-NLG 530B
的高效的和准确的 W8A8 quantization
。如 Table 8
和 Table 9
所示,SmoothQuant
实现了 530B
模型在可忽略的准确率损失下的W8A8 quantization
。减小的模型大小允许我们使用一半数量的 GPU
(从 16 GPU
到 8 GPU
)来 serve
模型,在类似延迟下,实现了单节点(8 * A100 80 GPU
)内 serving
大于 500B
模型。
量化方案:Table 10
基于我们的 PyTorch
实现显示了不同量化方案的inference latency
。我们可以看到:
量化粒度越粗(从 O1
到 O3
),延迟越低。
静态量化与动态量化相比可以显著加速推理,因为我们不再需要在运行时计算量化步长。
SmoothQuant
在所有设置下都比 FP16 baseline
快,而 LLM.int8()
通常更慢。
如果准确率允许,我们建议使用更粗粒度的方案。
迁移强度:我们需要找到合适的迁移强度 activations
之间的 quantization difficulty
。我们在 Figure 10
中检验不同 OPT-175B
和 LAMBADA
的影响。
当 0.4
)时,activations
难以量化。
当 0.6
)时,权重难以量化。
只有当我们从最佳区域(0.4 ~ 0.6
)选择 activations
的小的量化误差,并在量化后保持模型性能。
论文:
《GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers》
来自 Transformer
家族的 pretrained
生成式模型(如 GPT
或 OPT
),在复杂的语言建模任务中展示了突破性的性能,导致了人们巨大的学术的和实际的兴趣。它们的一个主要障碍是计算成本和存储成本,这些成本在已知模型中是最高的。例如,性能最佳的模型变种,即 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 quantization
或 model pruning
的更复杂的方法通常需要对模型进行重新训练,而这对于十亿级参数的模型来说极其昂贵。另一方面,在不进行重新训练的情况以 one shot
方式压缩模型的 post-training
方法非常有吸引力。不幸的是,这种方法的更 accurate
的变体非常复杂,很难扩展到十亿级的参数(《ZeroQuant: Efficient and affordable post-training quantization for large-scale transformers》
)。到目前为止,只有 round-to-nearest quantization
的 basic 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 bits
或 4 bits
,几乎没有损失准确率。例如,GPTQ
可以在大约 4 GPU hours
内量化最大的开源可用模型 OPT-175B
和 BLOOM-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》
)。
相关工作:量化方法大致分为两类:quantization during training
、post-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
的方法通过量化单个 layers
或 small blocks of consecutive layers
来操作。
AdaRound
方法(《Up or down? Adaptive rounding for post-training quantization》
)通过 annealing
一个惩罚项来计算 data-dependent rounding
,该项鼓励权重向对应于 quantization levels
的 grid points
移动。
BitSplit
(《Towards accurate post-training network quantization via bit-split and stitching》
)使用 residual error
的 squared 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 block
的 layers
。
最后,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
:随着 BLOOM
或 OPT-175B
等语言模型的开源发布,研究人员已经开始开发可负担的方法来压缩这种巨大的网络以进行推理。尽管所有现有的工作(ZeroQuan
、LLM.int8()
和 nuQmm
)都仔细选择了量化粒度,如 vector-wise
,但它们最终只是将权重舍入到最近(round weights to the nearest: RTN
)的 quantization level
,从而为每个非常大的模型维持可接受的运行时间。
ZeroQuant
进一步提出了类似于 AdaQuant
的逐层知识蒸馏(layer-wise knowledge distillation
),但它可以应用这种方法的最大模型只有 1.3B
参数。在这种规模下,ZeroQuant
已经需要 3
小时的计算;而 GPTQ
在 4
小时内量化了大约100
倍的模型。
LLM.int8()
观察到在少数 feature dimensions
中的 activation outliers
会破坏更大模型的量化,并提出通过以更高的精度来保持这些维度从而来解决这个问题。
最后,nuQmm
为一种特定的 binary-coding based
量化方案开发了高效的 GPU kernels
。
与这些工作相比,我们表明:在大的 model scale
上可以有效地实现一个明显更复杂的和更精确的 quantizer
。具体来说,在类似的准确率下,GPTQ
将先前技术的压缩量提高了一倍以上。
Layer-Wise Quantization
:在 high level
,我们的方法遵循 SOTA
的 post-training quantization
方法的结构,逐层执行量化,为每一层解决相应的重构问题。具体而言,设 layer input
(对应于少量的 quantized weights
full precision layer output
的平方误差最小化。形式上,这可以描述为:
此外,与 《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》
类似,我们假设 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
量化的粒度更粗。
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
方法的起点是观察到公式 OBQ
独立地处理每一行
由于对应的目标函数是二次函数,其海森矩阵为 full-precision weights
的集合,那么 greedy-optimal
的下一个要量化的权重(记做 optimal update
(记做
这是核心思想。后面的内容都是针对该公式的计算速度和稳定性上的优化。
其中:
quantization grid
上的 nearest value
。
OBQ
使用这两个等式迭代地量化权重,直到 full recomputations
:
其中:
该方法具有向量化实现,可以并行处理 GPU
上在 1
小时内完全量化 ResNet-50
模型(25M
参数),这与实现 SOTA
准确率的其他 post-training
方法的运行时间大致相当(《Optimal Brain Compression: A framework for accurate post-training quantization and pruning》
)。然而,OBQ
对
推导过程,对于给定的权重行
: 则通过泰勒展开公式:
其中:
, 。 为最小化
,则第一项为零(因为 位于极值点,此时一阶导数为零),同时忽略第三项(因为是三阶无穷小),则有: 因此对于第
个元素 ,我们需要满足:
Step 1: Arbitrary Order Insight
:如前一节所述,OBQ
以贪心的顺序来量化权重,即它总是选择当前引起的 additional quantization error
最小的权重。有趣的是,我们发现,虽然这种非常自然的策略的确似乎表现非常好,但与任意顺序(arbitrary order
)来量化权重相比,其改进通常很小,尤其是在大型的、参数密集的层上。很可能是因为数量较少的、具有较大误差的 quantized weights
,与那些在量化过程接近结束时的 quantized weights
所平衡;而在量化过程接近结束时,只剩下很少其他 unquantized weights
可以进行补偿调整。正如我们现在要讨论的,这一见解,即任意固定顺序可能表现良好,特别是在大型模型上,具有有趣的影响。
原始 OBQ
方法独立地以特定顺序(该顺序由对应的additional quantization error
来定义)量化 final squared error
。因此,unquantized weights
的集合 Figure 2
中的示意图)。更具体地说,后者是由于 layer input
Step 2: Lazy Batch-Updates
:首先,直接实现前面描述的方案在实践中将不会很快,因为该算法具有相对较低的 compute-to-memory-access ratio
。例如,对于每一个 FLOPs
。这种操作无法充分利用现代 GPU
的大规模计算能力,并会受到明显更低的内存带宽的限制。
幸运的是,通过以下观察可以解决这个问题:对第 final rounding decisions
仅受到对该列执行的更新的影响,因此对 later columns
的更新与第 "lazily batch" updates
从而实现更好的 GPU
利用率。具体而言,我们同时对 block
中(参见 Figure 2
)。仅当一个 block
被完全处理后,我们才使用下面给出的 multi-weight
版本的公式,对整个
尽管这种策略理论上不减少计算量,但它有效地解决了内存吞吐量瓶颈,在非常大的模型上实际提供了一个数量级的加速,使其成为我们算法的关键组成部分。
即,每次更新一个
batch
的权重,而不是单个权重。
Cholesky Reformulation
:我们必须解决的最后一个技术问题是数值不准确,它可能在现有模型规模下成为主要问题,特别是结合上一步中讨论的 block updates
。具体来说,可能出现 remaining weights
的方向,从而导致对应层的 arbitrarily-bad quantization
。在实践中,我们观察到发生这种情况的概率随模型大小增加:具体来说,对于大于数十亿参数的模型,它几乎肯定对至少一些层发生。主要问题似乎是重复应用公式 additional matrix inversion
。
对于较小的模型,应用阻尼,即将 1%
)看起来足以避免数值问题。然而,更大的模型需要更稳健的和更通用的方法。
为此,我们首先注意到,从 weight q
时的 unquantized weights
集合),或者更准确地说,从对角线开始的该行中的元素。其结果是,我们可以使用更数值稳定的方法预先计算所有这些行,而不会显著增加内存消耗。实际上,对于我们的对称矩阵 Cholesky
分解,只是后者存在细微的差别:将行 SOTA
的 Cholesky kernels
从 Cholesky kernel
还可以进一步加速。接下来,我们详细说明 Cholesky
版本算法所需的所有小改动。
虽然大型模型的参数规模可以达到千亿级,但是这里的
是由当前 layer
的input
来决定,通常规模不大。可以快速地进行 Cholesky
分解。
完整算法:最后,我们在 Algorithm 1
中给出 GPTQ
的完整伪代码,包括上面讨论的优化。
注意:
GPTQ
需要依赖输入数据来执行量化。在实验部分,作者采用 C4
数据集中随机采样的128
个random 2048 token segments
组成的。如果 来自不同的数据,例如随机生成的文本序列,是否对 GPTQ
有影响?采用比128
更多的样本更好,还是更少的样本更好?论文都没有进行消融研究。(在SparseGPT
的论文中,作者对calibration
数据进行了消融分析,发现::随着calibration
样本数量的增加,准确性得到改善。但是当数量超过某个点时,困惑度曲线逐渐变平缓。)注意:
GPTQ
仅关注权重的量化,而不关心 activation
的量化。 注意:在当前
layer
量化完之后,再将馈入当前的 quantized layer
从而作为next layer
的输入。注意:算法的迭代没有采用随机梯度下降,而是直接用的解析解,因此迭代效率非常高。
注意:
blocksize
对于模型准确性没有影响,它影响的是训练速度。
我们首先在小型模型上验证 GPTQ
相对于其他 accurate-but-expensive quantizers
的准确率,这些方法在这些小型模型上可以提供合理的运行时间。接下来,我们检查 GPTQ
在超大型模型上的 runtime scaling
。然后,我们通过困难的语言生成任务上的困惑度表现,展示 BLOOM
和 OPT
模型族的整体 3-bit
和 4-bit
的量化结果。此外,我们展示,当粒度减小到 small blocks of consecutive weights
时,我们的方法在 2-bit
量化也很稳定。
为补充这一困惑度分析,我们还在一系列标准的 zero-shot
任务上评估得到的 quantized models
。最后,我们关注两个最大(和有趣)的开源可用模型,即 Bloom-176B
和 OPT-175B
,在这里我们对几个任务进行详细评估。对于这些模型,我们还提出实际改进,即,为生成式任务减少推理所需的 GPU
数量、以及端到端加速。
设置:我们在 PyTorch
中实现了 GPTQ
,并使用 HuggingFace
的BLOOM
和 OPT
模型家族。我们使用单个 NVIDIA A100 GPU
(80GB
内存)来量化所有模型(包括 175B
参数变体)。我们整个 GPTQ
校准数据(calibration data
)由 C4
数据集中随机采样的 128
个 random 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 block
的 new inputs
从而进行量化。因此,量化过程不是在 full precision model
的 layer inputs
上运行,而是在已经部分 quantized model
的 actual layer inputs
上运行。我们发现,这在几乎没有额外成本的情况下带来显着改进。
baselines
:
我们的主要基准线,记做 RTN
,将所有权重舍入到与 GPTQ
使用的完全相同的 asymmetric per-row grid
上的 nearest quantized value
;这对应于 SOTA
的LLM.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
这样的巨型模型。
Quantizing Small Models
:作为第一个消融研究,我们在 ResNet18
和 ResNet50
上比较 GPTQ
与 SOTA
的 post-training quantization: PTQ
方法的性能,这些是标准的 PTQ benchmarks
,设置与 《Optimal Brain Compression: A framework for accurate post-training quantization and pruning》
相同。
结果如 Table 1
所示。可以看到:
在 4-bit
时,GPTQ
的表现与最 accurate
的方法相当。
在 3-bit
时 GPTQ
与最 accurate
的方法相比略差一些。
与此同时, GPTQ
明显优于 AdaQuant
,后者是先前 PTQ
方法中最快的。
此外,我们还与两个小型语言模型 BERT-base
和 OPT-125M
上的 full greedy OBQ
方法进行了比较。结果如附录 Table 8
所示。可以看到:在 4-bit
时,两种方法的性能相似;在 3-bit
时,出人意料的是,GPTQ
的表现略好一些。我们怀疑这是因为 OBQ
使用的一些额外启发式方法,如 early outlier rounding
,可能需要仔细调整从而在 non-vision
模型上获得最佳性能。
总体而言,GPTQ
似乎与小型模型的 SOTA
的 PTQ
方法相媲美,而只需要
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》
)。
Language Generation
:我们通过压缩整个 OPT
和 BLOOM
模型系列到 3-bit
和 4-bit
开始 large-scale
研究。然后我们在几项语言任务上评估这些模型,包括 WikiText2
(参考 Figure 1
和 Table 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
之外,较大的模型似乎通常更容易被量化。这对实际应用来说是个好消息,因为这些也是最需要压缩的情况。
175 Billion Parameter Models
:现在我们检查 BLOOM-176B
和 OPT-175B
,这是最大的公开可用的稠密模型。Table 5
总结了它们在 Wikitext-2
、PTB
、C4
上的结果。我们观察到:
在 4-bit
下,GPTQ
模型的困惑度仅比 full-precision versions
低 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.2
;group-size =128
(约 0.15 extra bits
)继续改善了平均困惑度约 0.1
,与未压缩的困惑度只差 0.1-0.3
。
我们注意到,grouping
与 GPTQ
互相协作得非常好,因为可以在每一层的量化过程期间确定 group parameters
,总是使用 most current updated weights
。
实际加速:最后,我们研究实际应用。作为一个有趣的 case
,我们关注 OPT-175B
模型:量化到 3-bit
后,这个模型占用约 63GB
内存,包括 embedding layer
和 output layer
(它们保持 full FP16 precision
)。另外,为所有层存储 keys
和 values
的完整历史,这是 generation
任务的常见优化,对于最大 2048 tokens
又占用约额外 9GB
。因此,我们实际上可以将整个 quantized model
装入单个 80GB A100 GPU
中,可以通过在推理期间需要时动态地 dequantizing layers
来执行(使用 4-bit
模型将不会完全适合单个 GPU
内存)。作为参考,标准 FP16
执行需要 5
个 80GB GPU
;而 SOTA
的 8-bit LLM.int8() quantizer
需要 3
个这样的 GPU
。
接下来,我们考虑 language generation
,这是这些模型最吸引人的应用之一,目标是减少延迟。与 LLM.int8()
不同,其中 LLM.int8()
减少了内存成本但与 FP16 baseline
的 runtime
相同,我们展示了我们的 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
版本(在 5
个 GPU
上运行)相比,average time per token
快约 3.25
倍。
对于 NVIDIA A6000
(具有更低的内存带宽),这种策略甚至更有效:在 2
个 A6000 GPU
上执行 3-bit OPT-175B
模型将延迟从 FP16
版本的 589
毫秒(在 8
个 GPU
上)降低到 130
毫秒,延迟降低了 4.5
倍。
Zero-Shot Tasks
:虽然我们的重点是 language generation
,但我们还在一些流行的 zero-shot
任务上评估了 quantized models
的性能,即 LAMBADA
、 ARC (Easy and Challenge)
、和 PIQA
。 Figure 3
可视化了模型在 LAMBADA
上的性能(参见 Table 5
中的 "Lamb."
结果)。我们观察到之前类似的行为,但是一些异常情况是:
1)
:在 4-bit
,量化对所有模型来说似乎 “更容易”, 即使RTN
也表现相对良好。
2)
:在 3-bit
,RTN
崩溃 而 GPTQ
仍然提供良好的准确率。
我们在附录 A.4
中提供了更多结果。
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
下的准确率损失。
极端量化:最后,grouping
也使得在平均 2-bit per parameter
的极端量化上获得合理性能成为可能。Table 7
显示了在不同 group-size
下将最大模型量化为 2-bit
时在 WikiText2
上的结果。
在大约 2.2 bit
(group-size 128; using FP16 scale and 2-bit zero point per group
)时,困惑度的增加还不到 1.5
。
而在约 2.6 bit
(group-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
。
局限性:我们强调一些重要的局限性:
在技术上,我们的方法来自减少内存移动带来的加速,而没有导致计算减少。
注意,这是因为
GPU kernels
目前还不支持3-bit
整数和FP 16
的乘法,因此在推理过程中,3-bit
整数被逆量化为FP16
,然后进行FP16
和FP16
的乘法运算,这就是作者开发的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 》
)。