大语言模型(LLM)量化基础知识(一)

请大家关注我的知乎博客:- 派神 - - 知乎

随着大型语言模型 (LLM) 的参数数量的增长,与其支持硬件(加速器内存)增长速度之间的差距越来越大,如下图所示:

上图显示,从 2017 年到 2022 年,语言模型的大小显著增加:

  •  2017 年: Transformer 模型(0.05B 参数)
  • 2018 年: GPT(0.11B 参数)、BERT(0.34B 参数)
  • 2020 年: GPT-2(1.5B 参数)、MegatronLM(8.3B 参数)
  • 2021 年: GPT-3(175B 参数)、T-NLG(17B 参数)
  • 2022 年: MT-NLG(530B 参数)

加速器(一般指GPU)是专门的硬件,用于加速机器学习训练。它们的内存容量对于训练大型模型至关重要。图中显示加速器内存的增长速度远低于模型大小的增长速度:

  • 2017 年: TPUv2(16GB)
  • 2018 年: V100(32GB)
  • 2020 年: TPUv3(32GB)
  • 2021 年: A100(40GB)
  • 2022 年: A100(80GB)
  • 在 2023 年至 2024 年期间,最大且最常用的模型的参数量大约在 700 亿左右。

上图显示了模型大小和加速器内存之间不断增长的差距。“差距”表示模型大小的增长速度远远超过了硬件内存容量的增长速度。这种差距对 LLM 的训练和部署提出了重大挑战。2022 年,模型规模达到了顶峰,但到了 2023 年,人们发现中等规模的模型(~70B 参数)在实际应用中更加实用和高效。然而加速器内存的增长速度没有跟上模型大小的增长速度。 这突出了对更高效的训练技术、模型压缩方法和专用硬件的需求,以克服这一瓶颈。

大型模型的规模和复杂性会限制其访问性和实用性,因此需要找到解决方案,将一个大型、复杂的模型转换为一个更小、更高效的模型,同时保留其核心功能,从而提高可访问性和实用性。 这使得在资源有限的环境中部署和使用模型成为可能。

模型压缩的方法

为了将一个大型、复杂的模型转换为一个更小、更高效的模型,我们需要使用一些模型压缩的方法,下面我们来介绍几种模型压缩的方法: 1.剪枝(Pruning),2.知识蒸馏(Knowledge Distillation),3.量化(Quantization),这里我们会深入讲解 第三种 量化(Quantization)方法,对于剪枝(Pruning)和知识蒸馏(Knowledge Distillation)我们只做简单介绍。

1.剪枝(Pruning)

剪枝(Pruning)的核心思想是移除对模型性能提升不大的连接或神经元,从而减小模型的大小和复杂度:

2.知识蒸馏(Knowledge Distillation)

知识蒸馏(Knowledge Distillation)的核心思想是使用一个已经训练好的大型模型(教师模型)来指导一个较小型模型(学生模型)的训练,从而将大型模型的知识“蒸馏”到小型模型中。 

知识蒸馏指的是使用一个训练好的大型模型(教师模型)来指导小型模型(学生模型)的训练,从而使小型模型获得与大型模型相近的性能,实现模型压缩的目的。 

3. 量化(Quantization)

在讲解量化方法之前,我们先回归一下神经网络:

上图是神经网络的一个隐藏层,展示了线性层 followed by 激活函数的计算过程,其中:

  • w₁, b₁, w₂, b₂, w₃, b₃: 这些是神经网络的权重(Weights,蓝色w) 和偏差(Biases,紫色b)。每个神经元都有一组对应的权重和偏差。
  • x: 橙色箭头和 x 指的是输入向量。
  • a₁, a₂, a₃: 这些是每个神经元的输出,也就是激活值(Activations)。
  • 公式 aᵢ = g(wᵢ ⋅ x + bᵢ): 这展示了线性层 followed by 激活函数的计算过程。其中:
    •     wᵢ ⋅ x 表示权重向量和输入向量的点积。
    •     + bᵢ 表示加上偏差。
    •     g() 表示激活函数。
  • 公式 g(z) = 1 / (1 + e⁻ᶻ): 这定义了激活函数 g(z) 为 sigmoid 函数。sigmoid 函数将线性层的输出映射到 0 到 1 之间,引入非线性。

在神经网络中,我们可以量化权重和激活值,其中:

  • 权重 (w̄):神经网络参数
  • 激活值 (a):在神经网络层中传播的值
  • 例如,在线性层中,a = g(w̄ ⋅ x + b);a 是激活值;w̄ 和 b 是权重。这里用一个线性层的例子进一步解释了激活值、权重和偏差的关系。

有了神经网络的基础知识后,下面我们来真正进入主题,我们来讨论一下模型压缩中的一种重要技术:量化(Quantization)。 它通过降低模型参数的精度来减小模型的大小和所需的存储空间,如下图所示:

量化的核心思想是以较低的精度存储模型的参数,在上图中:

  • 左侧表格 (FP32): 展示了使用单精度浮点数 (FP32) 存储的模型参数。每个值占用 4 个字节。
  • FP32 to INT8: 表示将参数从 FP32 转换为 8 位整数 (INT8) 的量化过程。
  • 右侧表格 (INT8): 展示了量化后的模型参数,使用 INT8 存储。每个值占用 1 个字节

这里如果以FP32 格式存储,每个值需要 4 字节存储空间,9 个值共需 36 字节。而以INT8 格式存储,每个值只需要 1 字节存储空间,同样的 9 个值只需 9 字节。

这里展示量化如何通过降低数值精度(从 FP32 到 INT8)来显著减少模型的存储空间(从 36 字节到 9 字节)。 虽然精度有所损失,但在很多情况下,这种损失对模型性能的影响是可接受的,并且可以换取更小的模型尺寸和更快的推理速度。

然而量化是会有代价的,那就是它会产生量化误差error,如下图所示:

这里我们将FP32 转换为 INT8 导致了精度损失。 每个误差值是原始 FP32 值和量化后 INT8 值之间的差。例如,第一个值 13.5 被量化成 13,误差为 0.5。最先进的(state-of-the-art)量化方法背后的全部挑战是避免性能下降的前提下尽可能的降低这个误差。

下面我们来介绍一些机器学习中不同的数据表示方式,这里会重点介绍整数和浮点数类型的区别,如下图所示:

这里我们将FP32 转换为 INT8 导致了精度损失。 每个误差值是原始 FP32 值和量化后 INT8 值之间的差。例如,第一个值 13.5 被量化成 13,误差为 0.5。最先进的(state-of-the-art)量化方法背后的全部挑战是避免性能下降的前提下尽可能的降低这个误差。

整数 (Integer, int8):

  • Integer (int8): 表示 8 位整数类型。
  • 绿色方块序列:用 8 个绿色方块直观地表示了 int8 类型,每个方块代表一个比特。其中包含的数字 “1 0 0 0 1 0 0 1” 是一个 int8 数值的二进制表示示例。

浮点数 (Floating Point, FP32, FP16, BF16):

  • 三种常见的浮点数类型:单精度浮点数 (FP32)、半精度浮点数 (FP16) 和 Brain Floating Point (BF16)
  • 彩色条形图:用不同颜色的条形图展示了 32 位浮点数 (FP32) 的组成部分及各自占用的位数:
    • 符号位 (Sign):1 位,用于表示正负。
    • 指数位 (Exponent):8 位,用于表示数值的范围(大小)。
    • 尾数位 (Fraction):23 位,用于表示数值的精度。
    • 总共 32 位。

上面我们介绍了整数 (int8) 和浮点数 (FP32, FP16, BF16)的组成部分。 并重点突出了浮点数的三个组成部分(符号、指数、尾数)及其各自的作用,并以 FP32 为例展示了这些部分是如何构成一个 32 位浮点数的。 这有助于理解不同数据类型在精度和存储空间上的权衡,以及它们在机器学习中的应用。 虽然图片中没有明确指出 FP16 和 BF16 的具体组成,但它们与 FP32 的相似性,只是精度和范围有所不同。

下面我们来介绍一种最简单的量化方法:线性量化 (Linear Quantization)

线性量化的原理是将一个较大范围的浮点数线性映射到一个较小范围的整数。如下图所示:

在上图中:

  • 蓝色线段 (FP32): 代表使用单精度浮点数 (FP32) 表示的数值范围,从 -234.1 到 251.51。
  • 红色线段 (INT8): 代表使用 8 位整数 (INT8) 表示的数值范围,从 -128 到 127。
  • 虚线: 连接 FP32 和 INT8 的值,展示了线性映射的关系。例如,FP32 中的 -234.1 映射到 INT8 中的 -128,FP32 中的 251.51 映射到 INT8 中的 127。

这里我们推荐使用 Hugging Face 的 Quanto 工具将线性量化应用于实际模型。

上图清晰地展示了线性量化的过程:将浮点数范围映射到整数范围。 它还指出了可以使用 Quanto 工具进行实际操作,并提示了量化技术在大语言模型中的重要应用。 通过上图我们可以更容易理解量化是如何工作的,以及为什么它可以用于模型压缩。

4.整数的表示

整数 (Integer)的两种表示方法:无符号整数 (Unsigned Integer)和有符号整数 (Signed Integer),下面我们以 8 位整数为例进行了说明:

无符号整数 (Unsigned Integer):

  • n 位无符号整数范围:这里给出了 n 位无符号整数的取值范围,从 0 到 2 的 n 次方减 1。
  • 范围:以 8 位无符号整数 (torch.uint8) 为例,说明其取值范围是 0 到 255。
  • 绿色方块序列:用 8 个绿色方块直观地表示了 8 位无符号整数,每个方块代表一个字节(byte)。 数值 “1 0 0 0 1 0 0 1” 是一个示例。
  • 计算过程:下方展示了如何将二进制 “1 0 0 0 1 0 0 1” 转换为十进制 137 的过程,每个byte乘以 2 的相应幂次再求和。

有符号整数 (Signed Integer):

  • 表示方法:有符号整数使用补码 (Two's Complement) 表示法。
  • n 位有符号整数的取值范围:这里给出了 n 位有符号整数的取值范围,从 -2 的 (n-1) 次方到 2 的 (n-1) 次方减 1。
  • 8 位有符号整数 (torch.int8) 取整范围:这里以 8 位有符号整数 (torch.int8) 为例,说明其取值范围是 -128 到 127。
  • 红绿方块序列:用一个红色方块和 7 个绿色方块表示 8 位有符号整数,红色方块代表符号位(1 表示负数)。 数值 “1 0 0 0 1 0 0 1” 是一个示例。
  • 计算过程:下方展示了如何将补码表示的二进制 “1 0 0 0 1 0 0 1” 转换为十进制 -119 的过程。最高位(符号位)的权重为负,其余位计算方式与无符号整数相同。

这里我们看到无符号整数只能表示非负数(0和正数),而有符号整数可以表达负数,0和整数,并且有符号数采用的是补码 (Two's Complement) 表示法,在补码中,最高位代表负的 2 的幂次方,其余位则按照标准的二进制转十进制方法计算。

在上图中将二进制 "1 0 0 0 1 0 0 1" 转换为十进制的方法如下:

  1. 识别符号位: 最左边的byte (1) 是符号位。 1 表示这是一个负数。
  2. 剩余字节(byte)位计算: 除了符号位之外的其余byte按照正常的二进制到十进制转换方法计算: 0 * 2⁶ + 0 * 2⁵ + 0 * 2⁴ + 1 * 2³ + 0 * 2² + 0 * 2¹ + 1 * 2⁰ = 0 + 0 + 0 + 8 + 0 + 0 + 1 = 9
  3. 符号位权重: 在 8 位补码中,符号位的权重是 -2⁷ (-128)。
  4. 最终计算: 将符号位的权重和剩余byte计算结果相加: -128 + 9 = -119

因此,二进制 "1 0 0 0 1 0 0 1" 的 8 位补码表示对应的十进制数是 -119。

或许有读者不熟悉补码 (Two's Complement),下面我们就来介绍一下补码:

补码 (Two's Complement) 是一种用于表示有符号整数的二进制编码方式。它之所以被广泛使用,是因为它可以将加法和减法运算统一起来,简化了计算机硬件的设计。

补码的作用:

  • 表示正负数: 补码用最高位(最左边的位)作为符号位,0 表示正数,1 表示负数。
  • 简化运算: 使用补码,加法和减法可以用相同的电路实现,无需额外的减法电路。 这是补码最主要的优势。
  • 唯一表示零: 与原码和反码不同,补码中零只有一个表示形式,避免了歧义。

补码的计算方法:

对于一个 n 位的整数:

  • 正数: 正数的补码与其二进制表示相同。
  • 负数: 负数的补码计算方法如下:
    • 取其绝对值的二进制表示。
    • 将所有byte位取反(0 变 1,1 变 0)。
    • 将结果加 1。

举例说明 (8 位):

  • +5

    • 二进制:00000101
    • 补码:00000101 (与原码相同)

  • -5

    • 绝对值的二进制:00000101
      取反:11111010
      加 1:11111011 (这是 -5 的补码)

补码的运算:

  • 加法: 直接将两个补码相加,忽略最高位的进位。
  • 减法: 将被减数与减数的补码相加,等同于加上减数的相反数。

补码的用途:

  • 计算机硬件: 几乎所有现代计算机都使用补码来表示和运算整数。 这是因为补码简化了 ALU(算术逻辑单元)的设计,可以只用加法器实现加减法运算。
  • 编程语言: 许多编程语言的底层也使用补码来表示整数。
  • 数字信号处理: 在 DSP 中,补码也用于表示和处理数字信号。

补码是一种高效的二进制表示法,它简化了计算机的运算,并且能够清晰地表示正负数和零。 它的广泛应用使得计算机能够更快速、高效地进行整数运算。

下面我们介绍一下在PyTorch 中不同整数数据类型的表示方法,如下图所示:

上门图片中的表格展示了在 PyTorch 中如何使用不同的整数类型。它列出了每种类型的正式名称 (torch.dtype) 和更常用的别名(如果存在),方便开发者在代码中使用。 例如,你可以使用torch.int32或torch.int来表示 32 位有符号整数。 了解这些数据类型及其别名对于编写高效的 PyTorch 代码至关重要,尤其是在处理需要特定整数类型的数据或进行模型量化时。

下面我们来分别介绍一下在PyTorch 中 8 位无符号整数 (torch.uint8) 和有符号整数 (torch.int8) 的表示范围:

在上图中:

  • Unsigned integer: [0, 2ⁿ - 1]: 表明是无符号整数,并给出了 n 位无符号整数的通用取值范围公式,从 0 到 2 的 n 次方减 1。

  • torch.iinfo(torch.uint8): 展示了如何在 PyTorch 中使用 torch.iinfo() 函数获取 torch.uint8 类型的信息。 注意这里标注了 "two 'i's" 并配上了眼睛 👀 表情符号,强调了函数名中有两个 "i",提醒用户不要拼写错误,这是一个很贴心的细节。

  • iinfo(min=0, max=255, dtype=uint8): 这是 torch.iinfo() 函数的输出结果,显示了 torch.uint8 的最小值 (0)、最大值 (255) 和数据类型 (uint8)。

上图展示了 PyTorch 中torch.uint8类型的取值范围,并演示了如何使用torch.iinfo()函数获取数据类型的信息。 强调了 "two 'i's" 的细节,有助于用户避免常见的拼写错误。 这对于理解 PyTorch 中整数类型的表示和使用至关重要,尤其是在图像处理等需要处理像素值(通常在 0 到 255 之间)的情况下。

下面我们来介绍一下在PyTorch 中 8 位有符号整数 (torch.int8) 的表示范围,以及补码表示法:

  • ​​​​​​​[-2ⁿ⁻¹, 2ⁿ⁻¹ - 1]: 这里给出 n 位有符号整数(补码表示)的通用取值范围公式。
  • "torch.int8": 表示这是一个关于 torch.int8 类型的示例。
  • "torch.iinfo(torch.int8)": 展示了如何在 PyTorch 中使用 torch.iinfo() 函数获取 torch.int8 类型的信息。
  • "iinfo(min=-128, max=127, dtype=int8)": torch.iinfo() 函数的输出结果,显示了 torch.int8 的最小值 (-128)、最大值 (127) 和数据类型 (int8)。

这里我们演示了,在PyTorch 中 torch.int8 类型的取值范围,并强调了使用补码表示法。 还演示了如何使用torch.iinfo()函数获取数据类型的信息。 这对于理解 PyTorch 中整数类型的表示和使用至关重要,特别是对于模型量化等需要处理低精度数值的情况。

下面我们来看看如何在 PyTorch 中使用torch.iinfo()函数获取不同有符号整型数据类型的信息,如下图所示:

图中展示了三个使用 torch.iinfo() 函数的例子,分别对应三种不同的整型数据类型:

  • torch.iinfo(torch.int64): 调用 torch.iinfo() 函数,传入 torch.int64 数据类型,这将返回一个 torch.iinfo 对象,其中包含了 torch.int64 类型的各种属性信息,例如最大值、最小值等。

  • torch.iinfo(torch.int32): 调用 torch.iinfo() 函数,传入 torch.int32 数据类型。

  • torch.iinfo(torch.int16): 调用 torch.iinfo() 函数,传入 torch.int16 数据类型。

上图展示了如何使用torch.iinfo()函数获取 PyTorch 中不同整型数据类型的属性信息。 虽然图中没有显示torch.iinfo()函数的输出结果,但它告诉我们如何使用该函数来查询int64、int32和int16的信息,例如它们的取值范围、精度等。 通过这些信息,开发者可以更好地理解和使用 PyTorch 中的整型数据类型。

5.浮点数的表示

下面我们来介绍一下浮点数的三个组成部分及其在不同浮点数格式中的作用,如下图所示:

浮点数的三个组成部分包括:​​​​​​​

  • Sign(符号): 正数或负数(始终为 1 位)。 用于表示数值的正负。
  • Exponent(指数): 影响可表示的数值范围。 指数部分决定了数值的大小范围,类似于科学计数法中的指数。
  • Fraction(尾数): 影响数值的精度。 尾数部分决定了数值的精度,类似于科学计数法中的有效数字。

FP32、BF16、FP16 和 FP8 都是浮点数格式,它们对指数和尾数部分使用了特定数量的位。 这意味着不同格式的浮点数在数值范围和精度上有所不同,这取决于它们分配给指数和尾数的位数。 符号位始终是 1 位。

下面我们来介绍一下 FP32(单精度浮点数)的格式以及它如何表示不同范围的数值。

 

上图中展示了FP32 的三个组成部分以及它们各自占用的位数:

  • ​​​​​​​Sign(符号位): 1 位,红色部分,用于表示正负(0 为正,1 为负)。
  • Exponent(指数位): 8 位,绿色部分,用于表示数值的范围(大小)。
  • Fraction(尾数位): 23 位,蓝色部分,用于表示数值的精度。
  • Total: 总共 32 位,对应“单精度”。

上图数轴和下方的公式解释了 FP32 如何表示不同范围的数值:

  • ​​​​​​​0: 零是一个特殊值,通常表示为所有位都为 0。
  • Subnormal values(非规格化值): 指数位全为 0 (E = 0) 的情况。 这部分数值非常接近于 0,用于表示非常小的数。 其范围大约是 1.4 x 10⁻⁴⁵ 到 1.2 x 10⁻³⁸。 公式为 (-1)ˢ * F * 2⁻¹²⁶,其中:
    • S 是符号位。
    • F 是尾数位表示的小数部分。
  • Normal values(规格化值): 指数位不全为 0 且不全为 1 (E ≠ 0) 的情况。 这是最常用的范围,可以表示大多数的浮点数。 其范围大约是 1.2 x 10⁻³⁸ 到 3.4 x 10³⁸。 公式为 (-1)ˢ * (1 + F) * 2ᴱ⁻¹²⁷,其中:
    • S 是符号位。
    • F 是尾数位表示的小数部分。
    • E 是指数位表示的无符号整数。

数轴上的分段:

数轴上的方括号和数值表示了不同范围的边界:

  • 2⁻¹⁴⁹ : 非规格化值的最小值(接近于 0)。
  • (1 - 2⁻²³)2⁻¹²⁶: 非规格化值的最大值。
  • 2⁻¹²⁶: 规格化值的最小值。
  • (1 + 1 - 2⁻²³)2¹²⁷: 规格化值的最大值(接近于 FP32 能表示的最大值)。​​​​​​​

上图清晰地展示了 FP32 浮点数的格式、不同组成部分的作用,以及如何表示不同范围的数值,包括非常接近于零的非规格化值和更大范围的规格化值。 它还提供了计算 FP32 数值的公式,有助于更深入地理解浮点数的表示方式。

接下来我们再来介绍一下BF16(Brain Floating Point)的格式以及它如何表示不同范围的数值。

上图中展示了BF16 的三个组成部分以及它们各自占用的位数:

  • ​​​​​​​Sign(符号位): 1 位 (红色),表示数值的正负(0 为正,1 为负)。
  • Exponent(指数位): 8 位 (绿色),表示数值的范围(大小)。 与 FP32 相同。
  • Fraction(尾数位): 7 位 (蓝色),表示数值的精度。 比 FP32 的 23 位少。
  • Total: 总共 16 位,因此被称为“半精度”。

数轴和数值范围:

数轴和下方的公式解释了 BF16 如何表示不同范围的数值:

  • ​​​​​​​0: 零是一个特殊值,通常表示为所有位都为 0。
  • Subnormal values(非规格化值): 指数位全为 0 (E = 0)。用于表示非常接近 0 的小数。范围大约是 9.2 x 10⁻⁴¹ 到 1.2 x 10⁻³⁸。 公式:(-1)ˢ * F * 2⁻¹²⁶,其中:
    • S 为符号位。
    • F 为尾数位表示的小数部分 (0 ≤ F < 1)。 注意,BF16 的尾数位只有 7 位,精度比 FP32 低。
  • Normal values(规格化值): 指数位不全为 0 且不全为 1 (E ≠ 0)。这是最常用的范围。范围大约是 1.2 x 10⁻³⁸ 到 3.4 x 10³⁸。 公式:(-1)ˢ * (1 + F) * 2ᴱ⁻¹²⁷,其中:
    • S 为符号位。
    • F 为尾数位表示的小数部分 (0 ≤ F < 1)。
    • E 为指数位表示的无符号整数。

数轴上的分段和边界值:

数轴上的方括号和数值表示了不同范围的边界:

  • ​​​​​​​2⁻¹³³: 非规格化值的最小正值。
  • (1 - 2⁻⁷)2⁻¹²⁶: 非规格化值的最大值,也是最小规格化值。
  • 2⁻¹²⁶: 规格化值的最小正值。
  • (1 + 1 - 2⁻⁷)2¹²⁷: 规格化值的最大值。

与FP32的比较:

  • ​​​​​​​BF16 的指数位宽度与 FP32 相同,因此它们表示的数值范围大致相同。
  • BF16 的尾数位宽度比 FP32 小得多,因此 BF16 的精度比 FP32 低。
  • BF16 在深度学习训练中被广泛使用,因为它在数值范围和精度之间取得了平衡,可以减少内存使用和计算量,同时保持合理的模型精度。

上图清晰地解释了 BF16 浮点数的格式、数值范围、精度以及如何表示不同类型的数值。 通过与 FP32 的比较,可以看出 BF16 牺牲了一定的精度来换取更小的存储空间和更快的计算速度。

接下来,我们来介绍一些FP16(半精度浮点数)的格式、数值范围以及如何表示不同类型的数值(包括非规格化值和规格化值):

上图中列出了 FP16 的三个组成部分及它们占用的位数:

  • ​​​​​​​Sign(符号位): 1 位 (红色),表示数值的正负(0 为正,1 为负)。
  • Exponent(指数位): 5 位 (绿色),表示数值的范围(大小)。
  • Fraction(尾数位): 10 位 (蓝色),表示数值的精度。
  • Total: 总共 16 位。

数轴和数值范围:

数轴和下方的公式解释了 FP16 如何表示不同范围的数值:

  • ​​​​​​​0: 零是一个特殊值,通常表示为所有位都为 0。
  • Subnormal values(非规格化值): 指数位全为 0 (E = 0)。用于表示非常接近 0 的小数。范围大约是 6.0 x 10⁻⁸ 到 6.1 x 10⁻⁵。 公式:(-1)ˢ * F * 2⁻¹⁴,其中:
    • S 为符号位。
    • F 为尾数位表示的小数部分 (0 ≤ F < 1)。
  • Normal values(规格化值): 指数位不全为 0 且不全为 1 (E ≠ 0)。这是最常用的范围。范围大约是 6.1 x 10⁻⁵ 到 6.5 x 10⁴。 公式:(-1)ˢ * (1 + F) * 2ᴱ⁻¹⁵,其中:
    • S 为符号位。
    • F 为尾数位表示的小数部分 (0 ≤ F < 1)。
    • E 为指数位表示的无符号整数。

数轴上的分段和边界值:

数轴上的方括号和数值表示了不同范围的边界:

  • ​​​​​​​2⁻²⁴: 非规格化数的最小正值。
  • (1 - 2⁻¹⁰)2⁻¹⁴: 非规格化数的最大值,也是最小规格化值。
  • 2⁻¹⁴: 规格化数的最小正值。
  • (1 + 1 - 2⁻¹⁰)2¹⁵: 规格化数的最大值。

与FP32的比较:

  • ​​​​​​​FP16 的指数位和尾数位都比 FP32 少,因此 FP16 的数值范围和精度都比 FP32 低。
  • FP16 在深度学习训练中被广泛使用,因为它比 FP32 占用更少的内存和带宽,可以加快训练速度。 但是,使用 FP16 需要注意数值范围和精度 limitations,避免出现下溢或上溢等问题。

总而言之,上图清晰地解释了 FP16 浮点数的格式、不同组成部分的作用,以及如何表示不同范围的数值。 通过与 FP32 的比较,可以看出 FP16 牺牲了数值范围和精度来换取更小的存储空间和更快的计算速度。

三种浮点数数据类型的比较(FP32、FP16 和 BF16)

这里主要比较FP32、FP16 和 BF16的精度和最大值,如下图所示:

上图的表格中有三列:

  • ​​​​​​​Data Type(数据类型): 列出了三种浮点数类型:FP32(单精度)、FP16(半精度)和 BF16(Brain Floating Point)。
  • Precision(精度): 比较了三种数据类型的精度。
  • FP32:精度最高 (best)。
  • FP16:精度次之 (better)。
  • BF16:精度较低,但仍然不错 (good)。
  • maximum(最大值): 比较了三种数据类型可以表示的最大值。
  • FP32:最大值约为 10³⁸。
  • FP16:最大值约为 10⁴。
  • BF16:最大值约为 10³⁸。

上图清晰地展示了 FP32、FP16 和 BF16 之间在精度和数值范围上的差异。FP32 提供最高的精度和最大的数值范围,但需要更多的存储空间。FP16 降低了精度和数值范围,以节省存储空间。BF16 则在数值范围和精度之间取得了平衡,在保持与 FP32 相似数值范围的同时,降低了精度以减少存储空间和计算成本,使其成为深度学习训练中的常用选择。这也说明 BF16 在某些应用场景下的优势。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/885071.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【comfyui教程】ComfyUI 现已支持 Stable Diffusion 3.5 Medium!人人都能轻松上手的图像生成利器

前言 ComfyUI 现已支持 Stable Diffusion 3.5 Medium&#xff01;人人都能轻松上手的图像生成利器 大家翘首以盼的Stable Diffusion 3.5 Medium模型终于来了&#xff01;就在今天&#xff0c;Stability AI 正式推出了这款“亲民版”平衡模型&#xff0c;让创作者们得以在消费…

大模型微调技术 --> LoRA 系列之 AdaLoRA

AdaLoRA 1.摘要 之前的微调方法(如低秩更新)通常将增量更新的预算均匀地分布在所有预训练的权重矩阵上&#xff0c;并且忽略了不同权重参数的不同重要性。结果&#xff0c;微调结果不是最优的。 为了弥补这一差距&#xff0c;我们提出了AdaLoRA&#xff0c;它根据权重矩阵的…

带你搞懂红黑树的插入和删除

文章目录 1. 红黑树1.1 红黑树的概念1.2 红黑树的性质1.3 红黑树节点的定义1.4 红黑树的插入找到插入的位置调节平衡 1.5 红黑树的删除删除节点平衡调整 1.6 红黑树和AVL树的比较 1. 红黑树 1.1 红黑树的概念 红黑树也是一种二叉搜索树,但是在每一个节点上增加了一个存储位表…

揭秘全向轮运动学:机动艺术与上下位机通信的智慧桥梁

✨✨ Rqtz 个人主页 : 点击✨✨ &#x1f308;Qt系列专栏:点击 &#x1f388;Qt智能车上位机专栏: 点击&#x1f388; 本篇文章介绍的是有关于全向轮运动学分析&#xff0c;单片机与上位机通信C代码以及ROS里程计解算的内容。 目录 大纲 ROS&#xff08;机器人操作系统&…

移远通信推出八款天线新品,覆盖5G、4G、Wi-Fi和LoRa领域

近日&#xff0c;全球领先的物联网整体解决方案供应商移远通信宣布&#xff0c;再次推出八款高性能天线新品&#xff0c;进一步丰富其天线产品阵容&#xff0c;更好地满足全球客户对高品质天线的更多需求。具体包括5G超宽带天线YECT005W1A和YECT004W1A、5G天线YECT028W1A、4G天…

【设计模式系列】桥接模式(十三)

一、什么是桥接模式 桥接模式&#xff08;Bridge Pattern&#xff09;是一种结构型设计模式&#xff0c;其核心目的是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式主要用于处理那些在设计时无法确定实现细节的场合&#xff0c;或者需要在多个实现之间…

Java多态和继承(下篇)

今天接着学习多态和继承 目录 1 继承1.1 再谈初始化1.2 protect关键字1.3 继承方式1.4 final 关键字1.5 组合 2 多态2.1 多态的概念2.2 多态实现条件2.3 重写2.4 向上转型和向下转型2.4.1 向上转型2.4.2 向下转型 2.5 多态的优缺点2.6 避免在构造方法中使用重写的方法 总结 1 继…

动态规划理论基础和习题【力扣】【算法学习day.25】

前言 ###我做这类文档一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非常非常高滴&am…

数据结构之顺序表(C语言)

1 线性表 线性表是n个具有相同特性的数据元素的有限序列&#xff0c;是一种在实际中广泛应用的数据结构&#xff0c;常见的线性表有&#xff1a;顺序表、链表、栈、队列、字符串等。 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条直线。但是在物理结构上并不一定是…

Qt——窗口

一.窗口概述 Qt 窗口是通过 QMainWindow 类来实现的。 QMainWindow是一个为用户提供主窗口程序的类&#xff0c;继承QWidget类&#xff0c;并且提供一个预定义的布局。包含一个菜单栏&#xff08;menu bar&#xff09;&#xff0c;多个工具栏&#xff08;tool bars&#xff0…

长亭那个检测能力超强的 WAF,出免费版啦

告诉你们一个震撼人心的消息&#xff0c;那个检测能力超强的 WAF——长亭雷池&#xff0c;他推出免费社区版啦&#xff0c;体验地址见文末。 八年前我刚从学校毕业&#xff0c;在腾讯做安全研究&#xff0c;看到宇森在 BlackHat 上演讲的议题 《永别了&#xff0c;SQL 注入》 …

漏洞分析 | Spring Framework路径遍历漏洞(CVE-2024-38816)

漏洞概述 VMware Spring Framework是美国威睿&#xff08;VMware&#xff09;公司的一套开源的Java、JavaEE应用程序框架。该框架可帮助开发人员构建高质量的应用。 近期&#xff0c;网宿安全演武实验室监测到Spring Framework在特定条件下&#xff0c;存在目录遍历漏洞&…

tp接口 入口文件 500 错误原因

一、描述 二、可能的原因 1、runtime目录没权限 2、关闭了Tp记录日志的功能 3、关闭debug调试模式 4、关闭了debug模式还是报错 一、描述 Thinkphp项目本地正常&#xff0c;上传到线上后静态文件访问正常&#xff0c;访问tp接口报500错误。 经调试发现&#xff0c;在php入…

第07章 运算符的使用

一、算数运算符 算术运算符主要用于数学运算&#xff0c;其可以连接运算符前后的两个数值或表达式&#xff0c;对数值或表达式进行加 &#xff08;&#xff09;、减&#xff08;-&#xff09;、乘&#xff08;*&#xff09;、除&#xff08;/&#xff09;和取模&#xff08;%&a…

十七 MyBatis的注解式开发

十七、MyBatis的注解式开发 mybatis中也提供了注解式开发方式&#xff0c;采用注解可以减少Sql映射文件的配置。 当然&#xff0c;使用注解式开发的话&#xff0c;sql语句是写在java程序中的&#xff0c;这种方式也会给sql语句的维护带来成本。 官方是这么说的&#xff1a; 使…

用 Python 写了一个天天酷跑(附源码)

Hello&#xff0c;大家好&#xff0c;给大家说一下&#xff0c;我要开始装逼了 这期写个天天酷跑玩一下叭&#xff01; 制作一个完整的“天天酷跑”游戏涉及很多方面&#xff0c;包括图形渲染、物理引擎、用户输入处理、游戏逻辑等。由于Python是一种高级编程语言&#xff0c;…

Kettle——CSV文件转换成excel文件输出

1.点击—文件—新建—转换 拖入两个组件&#xff1a; 按shift&#xff0b;鼠标左击建立连接&#xff0c;并点击主输出步骤&#xff0c; 点击CSV文件输入&#xff0c;选择浏览的csv文件&#xff0c;然后点击确定 同样&#xff0c;Excel也同上&#xff0c;只是要删除这个xls 并…

高效管理iPhone存储:苹果手机怎么删除相似照片

在使用iPhone的过程中&#xff0c;我们经常会遇到存储空间不足的问题&#xff0c;尤其是当相册中充满了大量相似照片时。这些照片不仅占用了宝贵的存储空间&#xff0c;还可能使iPhone出现运行卡顿的情况。因此&#xff0c;我们迫切需要寻找苹果手机怎么删除相似照片的方法&…

用示例来看C2Rust工具的使用和功能介绍

C2Rust可以将C语言的源代码转换成Rust语言的源代码。下面是一个简单的C语言代码示例&#xff0c;以及使用c2Rust工具将其转换为Rust安全代码的过程。 C语言源代码示例 // example.c #include <stdio.h>int add(int a, int b) {return a b; }int main() {int result a…

赛普EAP平台 Download.aspx 任意文件读取漏洞复现

0x01 产品描述&#xff1a; ‌赛普EAP平台‌是一款专门为房地产企业打造的数字化管理系统&#xff0c;旨在帮助企业实现业务流程的优化、管理效率的提升和客户体验的改善。该系统集成了项目管理、销售管理、客户关系管理、财务管理、报表分析等多个模块&#xff0c;能够满足企业…