使用 XNNPack 加速动态量化推理
2024 年 4 月 9 日
作者:Alan Kelly,软件工程师

我们很高兴地宣布,XNNPack 的全连接和二维卷积运算符现在支持动态范围量化。XNNPack 是 TensorFlow Lite 的 CPU 后端,CPU 为 ML 推理提供了最广泛的覆盖范围,并且仍然是 TensorFlow Lite 的默认目标。因此,提高 CPU 推理性能是重中之重。通过为全连接和卷积运算符添加对动态范围量化的支持,我们**将**TensorFlow Lite 的 XNNPack 后端的推理性能**提高了四倍**,与单精度基线相比。这意味着更多由 AI 提供支持的功能可以部署到旧的和低端设备上。

以前,XNNPack 为用户提供了两种选择:全整数量化,其中权重和激活存储为带符号的 8 位整数,或者半精度(fp16)或单精度(fp32)浮点推理。在本文中,我们将展示动态范围量化的优势。

动态范围量化

与全量化模型类似,动态量化模型在模型转换期间将全连接和卷积运算符的权重量化为 8 位整数。所有其他张量都没有量化,它们保持为 float32 张量。在模型推理期间,浮点层激活在传递到全连接和卷积运算符之前被转换为 8 位整数。每个激活张量行的量化参数(零点和比例)是根据观察到的激活范围动态计算的。由于激活充分利用了 8 个量化位,因此最大程度地提高了量化过程的准确性。在全量化模型中,这些参数在模型转换期间是固定的,基于使用代表性数据集观察到的激活值的范围。全量化和动态范围量化之间的第二个区别是,全连接和卷积运算符的输出是 32 位浮点格式,而不是全量化运算符的 8 位整数。使用动态范围量化,我们获得了全量化的大部分性能提升,但整体精度更高。

传统上,此类模型的推理是使用 TensorFlow Lite 的原生运算符完成的。现在,动态量化模型可以从 XNNPack 对全连接和二维卷积运算符的高度优化的每个架构实现中受益。这些运算符针对 XNNPack 支持的所有架构进行了优化(ARM、ARM64、x86 SSE/AVX/AVX512 和 WebAssembly),包括最新的 ArmV9 处理器,例如 Pixel 8 的 Tensor G3 CPU 或 OnePlus 11 的 SnapDragon 8 Gen 2 CPU。

如何使用它?

使用动态范围量化需要两个步骤。首先,必须从 TensorFlow 转换模型,使其支持动态范围量化。已经使用动态范围量化转换的现有模型无需重新转换。通过启用 converter.optimizations = [tf.lite.Optimize.DEFAULT] 转换器标志,可以在模型转换期间启用动态范围量化。与全整数量化不同,不需要代表性数据集,不支持的运算符也不会阻止转换成功。因此,对于非专家用户而言,动态范围量化比全整数量化更易于访问。

从 TensorFlow 2.17 开始,动态量化的 XNNPack 推理将在预构建二进制文件中默认启用。如果您想尽快使用它,可以使用夜间 TensorFlow 构建。

混合精度推理

在我们之前的文章中,我们介绍了使用半精度推理获得的令人印象深刻的性能提升。现在可以在 XNNPack 中结合使用半精度和动态范围量化,以在具有硬件 fp16 支持的设备上获得最佳的设备上 CPU 推理性能(如今出售的大多数手机都具有这种支持)。全连接和二维卷积运算符可以输出 fp16 数据而不是 fp32。于 2018 年发布的 Pixel 3 是第一款支持 fp16 的 Pixel 机型。与 fp32 相比,fp16 使用的一半位来存储浮点值,这意味着由于尾数明显较短(10 位对 23 位),每个值的相对精度会降低。并非所有模型都支持 fp16 推理,但是如果模型支持它,由于 CPU 可以每条指令处理两倍的数据,因此向量化浮点运算符的计算成本可以减半。具有计算密集型浮点运算符(例如批矩阵乘法和 Softmax)的动态量化模型也可以从 fp16 推理中受益。

性能改进

下面,我们展示了对四个公开模型的基准测试,这些模型涵盖了常见的计算机视觉任务

  1. EfficientNetV2 - 图像分类和特征提取
  2. Inception-v3 - 图像分类
  3. Deeplab-v3 - 语义分割
  4. Stable Diffusion - 图像生成(扩散模型)

每种模型都尽可能地转换了三次:全浮点、全 8 位有符号整数量化和动态范围量化。由于不支持的运算符,Stable Diffusion 的扩散模型无法使用全整数量化进行转换。下面显示了与使用 TFLite 内核的原始 float32 模型相比的加速情况。

  • FP32 指的是基线 float32 模型。
  • QS8 指的是使用 XNNPack 的全有符号 8 位整数量化。
  • QD8-F32 指的是使用 XNNPack 的动态量化 8 位整数,具有 fp32 激活。
  • QD8-F16 指的是使用 XNNPack 的动态量化 8 位整数,具有 fp16 激活。
  • Graph showing speed-up versus float32 on pixel 8

    下面显示了与 TFLite 的动态量化的全连接和卷积运算符相比的加速情况。只需使用最新版本的 TensorFlow Lite,您就可以从这些加速中受益。

    Graph showing speed-up versus TFLite DQ on Pixel 8

    我们可以清楚地看到,动态范围量化与全整数量化的性能相当,在某些情况下甚至可以超过全整数量化的性能。Stable Diffusion 的扩散模型运行速度比原始 float32 模型快 6.2 倍!这对设备上性能来说是一个巨大的变化。

    我们预计全整数量化应该比动态范围量化更快,因为所有运算都是使用整数运算计算的。此外,动态范围量化还需要额外的开销,即将浮点激活转换为量化的 8 位整数。令人惊讶的是,在测试的三个模型中的两个模型中,情况并非如此。使用TFLite 的分析器分析模型,解开了谜团。这些模型运行速度较慢是由于量化伪影的组合造成的,当输入和输出比例的比率落在某个范围内时,量化算术效率更高,以及 XNNPack 中缺少的操作支持。这些量化参数在模型转换期间根据提供的代表性数据集确定。由于比例比率超出了最佳范围,因此必须采用次优路径,导致性能下降。

    最后,我们证明了使用混合精度推理时模型精度基本保持不变,我们将使用 fp32 激活的动态量化的 Stable Diffusion 模型生成的图像与使用 fp16 激活生成的图像进行比较,随机数生成器使用相同的数字进行播种,以验证将 fp16 激活用于扩散模型不会影响生成的图像的质量。

    side by side comparison of images generated using fp16 inference on the left and fp32 inference on the right
    使用 fp16 推理生成的图像(左)和 fp32 推理生成的图像(右)

    两种生成的图像都是可爱的猫,与给定的提示相符。这些图像无法区分,这强烈表明扩散模型适合使用 fp16 推理。当然,对于所有神经网络而言,任何量化策略都应该使用大型验证数据集进行验证,而不仅仅是一个单一的测试。

    结论

    全整数量化很困难,转换模型很困难,容易出错,而且无法保证精度。代表性数据集必须真正具有代表性,才能最大限度地减少量化误差。动态范围量化在全整数量化和 fp32 推理之间提供了一种折衷方案:模型的大小与全量化模型相似,性能提升通常也相似,有时甚至超过了全量化模型。使用 Stable Diffusion,我们展示了动态范围量化和 fp16 推理可以结合使用,从而带来重大的性能改进。XNNPack 的动态范围量化现在为Gemini、Google Meet 和 Chrome OS 音频降噪提供支持,并将在今年的许多其他产品中推出。现在,我们开源用户可以使用相同的技术,因此您可以使用上面链接的模型并按照“如何使用它”部分中的说明进行尝试!

    致谢

    我们要感谢 Frank Barchard 和 Quentin Khan 对 TensorFlow Lite 和 XNNPack 中的动态范围量化推理做出的贡献。

下一篇文章
Faster Dynamically Quantized Inference with XNNPack

作者:Alan Kelly,软件工程师我们很高兴地宣布,XNNPack 的全连接和二维卷积运算符现在支持动态范围量化。XNNPack 是 TensorFlow Lite 的 CPU 后端,CPU 提供了最广泛的 ML 推理覆盖范围,并且仍然是 TensorFlow Lite 的默认目标。因此,提高 CPU 推理性能是重中之重。我们将推理速度提升了四倍