50张图解密大模型量化技术:INT4、INT8、FP32、FP16、GPTQ、GGUF、BitNet

由于大型语言模型(LLMs)通常过于庞大,这些模型可能包含数十亿个参数,通常需要具有大量显存的GPU来加速推理,无法在消费级硬件上运行。
因此,越来越多的研究集中在通过改进训练、适配器等方法使这些模型变得更小。一种用于降低计算复杂度、减少内存占用、加速推理的优化方法称为量化。量化的核心目标是将模型中的浮点数权重和激活值转换为低精度数值表示,同时保持模型的准确性和性能尽可能不受影响

后面将利用超过50个定制图表,逐步探索相关概念,探讨各种方法、使用案例以及量化背后的原理,帮助理解量化!

第一部分:LLM的“问题”

LLM因其包含的参数数量足够大而得名。如今,这些模型通常包含数十/百/千亿个参数(主要是权重),存储这些参数的成本可能相当高。

在推理过程中,激活值是由输入和权重相乘生成的,这些激活值同样可能非常庞大。

因此,我们希望尽可能高效地表示数数十/百/千亿个参数,尽量减少存储所需的空间。

下面先探讨数值是如何表示的,然后再对其进行优化。

如何表示数值

通常,数值以浮点数(在计算机科学中称为float)表示:带有小数点的正数或负数。

这些值由“”或二进制数字表示。IEEE-754标准描述了如何使用位来表示三个功能之一:符号指数小数部分(或尾数)。

这三个方面可以用来计算给定位值对应的数值:在这里插入图片描述

我们用来表示一个值的位数越多,通常它的精度就越高:

内存限制

我们可用的位数越多,可以表示的数值范围就越大。

给定表示可以表示的数值范围称为动态范围,而两个相邻值之间的距离称为精度在这里插入图片描述

这些位的一个巧妙特性是,我们可以计算设备存储给定值所需的内存。由于内存中的一个字节有8位,我们可以为大多数浮点表示创建一个基本公式。

注意:在实践中,推理期间所需的(显)存大小还与其他因素有关,如上下文大小和架构。

现在假设我们有一个包含700亿个参数的模型。大多数模型通常以32位浮点数(通常称为全精度)表示,这将需要280GB的内存来加载模型。

因此,尽量减少表示模型参数所需的位数(以及在训练期间!)非常有吸引力。然而,随着精度的降低,模型的准确性通常也会降低。

我们希望在减少表示值的位数的同时保持准确性……这就是量化的用武之地!

第二部分:量化简介

量化的目标是将模型参数的精度从较高的位宽(如32位浮点数)降低到较低的位宽(如8位整数)。

在减少表示原始参数的位数时,通常会损失一些精度(粒度)。

为了说明这种效果,我们可以拿任何一张图片,只用8种颜色来表示它:在这里插入图片描述

请注意放大后的部分看起来比原始图像更“颗粒化”,因为我们只能用更少的颜色来表示它。

量化的主要目标是减少表示原始参数所需的位数(颜色),同时尽可能保留原始参数的精度。

常见数据类型

首先,让我们看看常见的数据类型以及使用它们而不是32位(称为全精度FP32)表示的影响。

FP16

让我们看一个从32位到16位(称为半精度FP16)浮点数的例子:在这里插入图片描述

请注意,FP16可以表示的值范围比FP32小得多。

BF16

为了获得与原始FP32相似的值范围,bfloat 16被引入作为一种“截断FP32”类型:

BF16使用与FP16相同的位数,但可以表示更广泛的值范围,通常用于深度学习应用中。

INT8

当我们进一步减少位数时,就会进入整数表示而非浮点数表示的领域。举例来说,从FP32到INT8(仅8位),结果是原始位数的四分之一:

根据硬件不同,整数计算可能比浮点计算更快,但情况并非总是如此。不过,使用更少的位数进行计算通常会更快。

对于每次位数的减少,都会执行一个映射,将初始的FP32表示“压缩”到更低的位数。

在实践中,我们不需要将整个FP32范围[-3.4e38, 3.4e38]映射到INT8。我们只需要找到一种方法将数据范围(模型参数)映射到INT8。

常见的压缩/映射方法包括对称量化非对称量化,它们都是线性映射的形式。

让我们探讨这些方法,将FP32量化为INT8。

对称量化

在对称量化中,原始浮点值的范围被映射到量化空间中围绕零的对称范围。在之前的例子中,请注意量化前后的范围仍然围绕零中心。

这意味着浮点空间中的零在量化空间中正好是零。

对称量化的一个很好的例子是绝对值最大量化(absmax)。

给定一个值列表,我们取最大绝对值(α)作为执行线性映射的范围。

注意,[-127, 127]的值范围表示受限范围。不受限的范围是[-128, 127],具体取决于量化方法。

由于它是围绕零的线性映射,公式非常简单。

我们首先使用以下公式计算一个缩放因子(s):

  • b是我们想要量化到的字节数(8),

  • α最大绝对值,

然后,我们使用s来量化输入x

填入值后,我们将得到以下结果:在这里插入图片描述
要检索原始的FP32值,我们可以使用之前计算的缩放因子s)来反量化量化后的值。在这里插入图片描述

应用量化然后反量化过程以检索原始值如下:

你可以看到某些值,如3.083.02被分配到INT8中的36。当你反量化这些值以返回FP32时,它们会失去一些精度,并且不再可区分。

这通常被称为量化误差,我们可以通过找到原始值和反量化值之间的差异来计算它。

通常,位数越少,量化误差往往越大。

非对称量化

相比之下,非对称量化并不是围绕零对称的。相反,它将浮点范围的最小值(β)和最大值(α)映射到量化范围的最小值和最大值。

我们将探讨的方法称为零点量化


注意,0的位置发生了变化?这就是为什么它被称为非对称量化。在[-7.59, 10.8]的范围内,最小值/最大值到0的距离不同。

由于其偏移位置,我们必须计算INT8范围的零点以执行线性映射。与之前一样,我们还必须计算一个缩放因子s),但使用INT8范围[-128, 127]的差值。

请注意,由于需要计算INT8范围中的零点z)以调整权重,这个过程稍微复杂一些。

与之前一样,让我们填入公式:

要将INT8量化的值反量化为FP32,我们需要使用之前计算的缩放因子s)和零点z)。

除此之外,反量化是直接的:

当我们将对称量化和非对称量化并列时,我们可以快速看到两者之间的区别:

请注意对称量化的零中心特性与非对称量化的偏移特性。

范围映射和裁剪

在我们之前的例子中,我们探讨了如何将给定向量中的值范围映射到更低位数的表示。虽然这允许映射向量的全部值范围,但它有一个主要缺点,即异常值

假设你有一个包含以下值的向量:

请注意,其中一个值比其他值大得多,可以被视为异常值。如果我们映射这个向量的全部范围,所有小值将被映射到相同的低位表示,并失去它们的区分性:

这是我们之前使用的绝对值最大量化方法。请注意,如果我们不应用裁剪,非对称量化也会发生相同的行为。

相反,我们可以选择裁剪某些值。裁剪涉及设置原始值的不同动态范围,使得所有异常值都获得相同的值。

在下面的例子中,如果我们手动将动态范围设置为[-5, 5],所有超出该范围的值将被映射到-127或127,无论它们的值是多少:

主要优点是非异常值的量化误差显著减少。然而,异常值的量化误差会增加。

校准

在示例中,我展示了一种选择任意范围[-5, 5]的简单方法。选择这个范围的过程称为校准,其目标是找到一个范围,尽可能多地包含值,同时最小化量化误差。

执行此校准步骤并不适用于所有类型的参数。

权重(和偏置)

我们可以将LLM的权重和偏置视为静态值,因为它们在运行模型之前是已知的。例如,Llama 3的~20GB文件主要由其权重和偏置组成。

由于偏置(数百万)比权重(数十亿)少得多,偏置通常保持在较高精度(如INT16),而量化的主要努力集中在权重上。

对于静态且已知的权重,选择范围的校准技术包括:

  • 手动选择输入范围的百分位数

  • 优化原始权重和量化权重之间的均方误差(MSE)。

  • 最小化原始值和量化值之间的(KL散度)

选择百分位数,例如,将导致与我们之前看到的裁剪行为类似。

激活值

在LLM中不断更新的输入通常被称为“激活值”。在这里插入图片描述

请注意,这些值被称为激活值,因为它们通常通过某些激活函数,如sigmoid或relu。

与权重不同,激活值在推理期间随着每次输入数据的变化而变化,因此很难准确地量化它们。

由于这些值在每次隐藏层后更新,我们只有在推理期间输入数据通过模型时才知道它们是什么。

总的来说,校准权重和激活值的量化方法有两种:

  • 训练后量化(PTQ)

    • 训练后进行量化
  • 量化感知训练(QAT)

    • 训练/微调期间进行量化

第三部分:训练后量化

最流行的量化技术之一是训练后量化(PTQ)。它涉及在训练模型量化模型的参数(包括权重和激活值)。

权重的量化使用对称或非对称量化。

然而,激活值的量化需要模型的推理来获取它们的潜在分布,因为我们不知道它们的范围。

激活值的量化有两种形式:

  • 动态量化

  • 静态量化

动态量化

在动态量化中,每次数据通过隐藏层后,激活值会被收集:在这里插入图片描述

然后使用这些激活值的分布来计算量化输出所需的零点z)和缩放因子s):

每次数据通过新层时,这个过程都会重复。因此,每一层都有自己独立的zs值,因此有不同的量化方案。

静态量化

与动态量化相比,静态量化不会在推理期间计算零点z)和缩放因子s),而是提前计算。

为了找到这些值,使用一个校准数据集并将其输入模型以收集这些潜在的分布:

收集这些值后,我们可以计算推理期间进行量化所需的sz值。

在实际推理时,sz值不会重新计算,而是全局应用于所有激活值进行量化。

一般来说,动态量化往往更准确,因为它只为每个隐藏层计算sz值。然而,它可能会增加计算时间,因为这些值需要计算。

相比之下,静态量化准确性较低,但速度更快,因为它已经知道用于量化的sz值。

4位量化的领域

将量化降低到8位以下已被证明是一项困难的任务,因为每减少一位,量化误差都会增加。幸运的是,有几种聪明的方法可以将位数减少到6位、4位,甚至2位(尽管通常不建议使用这些方法将位数降低到4位以下)。

我们将探讨HuggingFace上常用的两种方法:

  • GPTQ(整个模型在GPU上)

  • GGUF(可能将某些层卸载到CPU上)

GPTQ

GPTQ 可以说是实践中用于 4 位量化的最著名方法之一。

它使用非对称量化,并逐层进行,每层在继续下一层之前独立处理:

在这个逐层量化过程中,它首先将层的权重转换为逆Hessian。这是模型损失函数的二阶导数,告诉我们模型输出对每个权重变化的敏感度。

简而言之,它基本上展示了层中每个权重的(重要性

与 Hessian 矩阵中较小值相关的权重更为重要,因为这些权重的微小变化可能导致模型性能的显著变化。

极低值表示更“重要”的权重。

接下来,我们量化和反量化权重矩阵中第一行的权重:

这个过程允许我们计算量化误差 (q),我们可以使用之前计算的逆 Hessian (h_1) 来加权。

本质上,我们根据权重的重要性创建一个加权量化误差:

接下来,我们将这个加权量化误差重新分配到行中的其他权重上。这允许保持网络的整体功能和输出。

例如,如果我们要对第二个权重(即 .3 (x_2))进行此操作,我们将添加量化误差 (q) 乘以第二个权重的逆 Hessian (h**_2**)
在这里插入图片描述

我们可以对给定行中的第三个权重进行相同的过程:

我们迭代这个过程,重新分配加权量化误差,直到所有值都被量化。

这种方法之所以有效,是因为权重通常彼此相关。因此,当一个权重有量化误差时,相关权重会相应更新(通过逆 Hessian)。

GGUF

虽然 GPTQ 是一种很好的量化方法,可以在 GPU 上运行完整的 LLM,但你并不总是有这种能力。相反,我们可以使用 GGUF 将 LLM 的任何层卸载到 CPU 上。

这允许你在没有足够 VRAM 时同时使用 CPU 和 GPU。

GGUF 量化方法经常更新,可能取决于位量化的级别。然而,一般原理如下。

首先,给定层的权重被分割为“超级”块,每个块包含一组“子”块。从这些块中,我们提取比例因子 (s) 和 α

为了量化给定的“子”块,我们可以使用之前使用的 absmax 量化。记住,它将给定权重乘以比例因子 (s)

比例因子使用“子”块中的信息计算,但使用“超级”块中的信息进行量化,该块有自己的比例因子:

[

这种块量化方法使用“超级”块的缩放因子(s_super)来量化“子”块的缩放因子(s_sub)。

每个缩放因子的量化精度可能不同,“超级”块的缩放因子通常比“子”块的缩放因子具有更高的精度。

为了说明这一点,我们来看一些量化精度(2 位、4 位和 6 位)的例子:

注意:根据量化类型,可能需要额外的最小值(m)来调整零点。这些值的量化方式与缩放因子(s)相同。

如何您和我一样,GPU 匮乏,并且没有最新最好的 GPU,那么 GGUF 是一种很棒的格式。

第四部分:量化感知训练

在第三部分中,我们看到了如何在训练之后对模型进行量化。这种方法的缺点是,这种量化没有考虑实际的训练过程。

这就是量化感知训练(Quantization Aware Training, QAT)的用武之地。与训练后量化(Post-Training Quantization, PTQ)不同,QAT 的目标是在训练过程中学习量化过程。

由于量化过程已经在训练中被考虑,QAT 通常比 PTQ 更准确。它的工作原理如下:

在训练过程中,引入所谓的“伪”量化。这个过程首先将权重量化到例如 INT4,然后再反量化回 FP32:

这个过程允许模型在训练过程中考虑量化过程、损失计算和权重更新。

QAT 试图探索损失曲面中的“宽”最小值,以最小化量化误差,因为“窄”最小值往往会导致较大的量化误差。

例如,假设我们在反向传播中没有考虑量化。我们会选择根据梯度下降得到最小损失的权重,但这可能会引入较大的量化误差,尤其是当它处于“窄”最小值时。

相比之下,如果我们考虑量化,就会选择位于“宽”最小值的权重,从而显著降低量化误差。

因此,尽管在高精度(例如 FP32)下,PTQ 的损失可能更低,但 QAT 在低精度(例如 INT4)下的损失更低,而这正是我们所追求的。


1 位 LLM 时代的到来:BitNet

将模型量化到 4 位已经非常小了,但如果我们进一步减少呢?

这就是 BitNet 的用武之地,它将模型的权重表示为单个 1 位,权重值仅为 -11

它通过将量化过程直接注入 Transformer 架构来实现这一点。

记住,Transformer 架构是大多数 LLM 的基础,由涉及线性层的计算组成:

这些线性层通常以更高精度(如 FP16)表示,这也是大多数权重所在的地方。

BitNet 将这些线性层替换为一种称为 BitLinear 的新层:

与普通线性层一样,BitLinear 层根据权重和激活值的乘积计算输出。

不同的是,BitLinear 层使用 1 位表示权重,激活值则使用 INT8:

与量化感知训练(QAT)类似,BitLinear 在训练过程中执行一种“伪”量化,以分析权重和激活值量化的效应:

注意:在论文中,作者使用了 γ 而不是 α,但为了保持一致性,我在这里使用了 α。另外,这里的 β 与我们在零点量化中使用的 β 不同,它表示平均绝对值。

让我们逐步了解 BitLinear 的工作原理。


权重量化

在训练过程中,权重以 INT8 格式存储,然后使用一种基本策略(称为 signum 函数)将其量化为 1 位。

本质上,它将权重分布中心化到 0,然后将左侧的所有值设为 -1,右侧的所有值设为 1:

此外,它还会跟踪一个值 β(平均绝对值),稍后将在反量化中使用。


激活值量化

为了量化激活值,BitLinear 使用 absmax 量化 将激活值从 FP16 转换为 INT8,因为矩阵乘法(×)需要更高的精度。

此外,它还会跟踪 α(激活值的最大绝对值),稍后将在反量化中使用。


反量化

我们跟踪了 α(激活值的最大绝对值)β(权重的平均绝对值),这些值将帮助我们将激活值从低精度反量化回原始精度(例如 FP16)。

输出激活值将通过 {α, β} 进行重新缩放,以恢复到原始精度:

以上就是整个过程!这种方法相对简单,允许模型仅使用两个值(-11)进行表示。

使用这种方法,作者发现随着模型规模的增大,1 位模型与 FP16 训练模型之间的性能差距逐渐缩小。然而,这种趋势仅适用于较大模型(>300 亿参数),对于较小模型,性能差距仍然较大。


所有大语言模型都在 1.58 位

BitNet 1.58b 是为了改进上述提到的扩展性问题而提出的。在这种新方法中,模型的每个权重不再是简单的 -11,而是可以取 0,形成三元表示。有趣的是,仅仅加入 0 就极大地改进了 BitNet,并且能够实现更快的计算。

0 的力量

为什么加入 0 是如此重要的改进?

这与矩阵乘法有关!

首先,我们来看矩阵乘法是如何工作的。在计算输出时,我们需要将权重矩阵与输入向量相乘。以下是权重矩阵第一层的第一个乘法运算的可视化:

请注意,这个乘法运算涉及两个操作:将单个权重与输入相乘,然后将它们全部相加

相比之下,BitNet 1.58b 可以跳过乘法操作,因为三元权重本质上告诉我们:

  • +1:我想要这个值
  • 0:我不想要这个值
  • -1:我想要减去这个值

因此,当你使用 1.58 位量化时,你只需要执行加法操作:


这不仅可以显著加速计算,还可以实现特征过滤

通过将权重设置为 0,你可以忽略它,而不是像在 1 位表示中那样只能选择加或减。


量化

为了执行权重量化,BitNet 1.58b 使用了 absmean 量化,这是之前提到的 absmax 量化 的一种变体。

它通过权重的绝对均值(α)来压缩权重分布,并将值四舍五入到 -101

与 BitNet 相比,激活值量化的唯一区别在于,激活值的范围不再是 [0, 2ᵇ⁻¹],而是通过 absmax 量化 调整为 [-2ᵇ⁻¹, 2ᵇ⁻¹]。

以上就是 1.58 位量化的全部内容!它主要依赖于两个技巧:

  • 加入 0 以实现三元表示 [-1, 0, 1]
  • 使用 absmean 量化 对权重进行量化

130 亿参数的 BitNet 1.58b 在延迟、内存使用和能耗方面比 30 亿参数的 FP16 LLM 更高效”。

因此,我们得到了轻量级模型,因为它们的计算效率仅为 1.58 位!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI仙人掌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值