使用 NVIDIA TensorRT 的量化感知训练实现 INT8 推理的 FP32 精度_神经网络
深度学习正在彻底改变行业提供产品和服务的方式。这些服务包括用于计算机视觉的对象检测、分类和分割,以及用于基于语言的应用程序的文本提取、分类和摘要。这些应用程序必须实时运行。

大多数模型都采用浮点 32 位算法进行训练,以利用更宽的动态范围。但是,在推理时,与降低精度的推理相比,这些模型可能需要更长的时间来预测结果,从而导致实时响应的一些延迟,并影响用户体验。

在许多情况下,最好使用降低精度或 8 位整数。挑战在于,在训练后简单地对权重进行四舍五入可能会导致模型精度较低,尤其是当权重具有较宽的动态范围时。这篇博文简单介绍了量化感知训练 (QAT),以及如何在训练期间实施假量化,以及如何使用 NVIDIA TensorRT 8.0 进行推理。


文章目录

概述

模型量化是一种流行的深度学习优化方法,其中模型数据——网络参数和激活——从浮点表示转换为较低精度的表示,通常使用 8 位整数。这有几个好处:

  • 在处理 8 位整数数据时,NVIDIA GPU 使用更快、更便宜的 8 位Tensor 核心来计算卷积和矩阵乘法运算。这会产生更多的计算吞吐量,这在计算受限的层上尤其有效。
  • 将数据从内存移动到计算元素(NVIDIA GPU 中的流式多处理器)需要时间和精力,同时也会产生热量。将激活和参数数据的精度从 32 位浮点数降低到 8 位整数会导致数据减少 4 倍,从而节省电力并减少产生的热量。
  • 某些层受带宽限制(内存受限)。这意味着它们的实现花费了大部分时间来读取和写入数据,因此减少它们的计算时间并不会减少它们的整体运行时间。带宽限制层从减少的带宽需求中获益最多。
  • 减少的内存占用意味着模型需要更少的存储空间,参数更新更小,缓存利用率更高,等等。

量化方法

量化有很多好处,但参数和数据精度的降低很容易损害模型的任务精度。考虑到 32 位浮点数可以表示区间 [-3.4e38, 3.40e38] 中大约 40 亿个数字。这个可表示数字的区间也称为动态范围。两个相邻可表示数字之间的距离是表示的精度。

浮点数在动态范围内分布不均匀,大约一半的可表示浮点数位于 [-1,1] 区间内。换句话说,[-1, 1] 区间中可表示的数字将比 [1, 2] 中的数字具有更高的精度。[-1, 1] 中可表示的 32 位浮点数的高密度有助于深度学习模型,其中参数和数据的大部分分布质量都在零附近。

但是,使用 8 位整数表示法,您只能表示 2^ 8 个不同的值。这 256 个值可以均匀分布或非均匀分布,例如,为了在零附近获得更高的精度。所有主流的深度学习硬件和软件都选择使用统一表示,因为它支持使用高吞吐量并行或矢量化整数数学管道进行计算。

要将浮点张量 ( x_{f})的表示转换为8 位表示 ( x_{q}),使用比例因子将浮点张量的动态范围映射到 [-128, 127]:

使用 NVIDIA TensorRT 的量化感知训练实现 INT8 推理的 FP32 精度_网络_02
这是对称量化,因为动态范围关于原点对称。圆形的是一个应用一些舍入策略将有理数舍入为整数的函数;and夹子是一个函数,可以剪掉落在 [-128, 127] 区间之外的异常值。TensorRT 使用对称量化来表示激活数据和模型权重。

图 1 的顶部是任意浮点张量 的图x_{f},描绘为其元素分布的直方图。我们选择了一个对称范围的系数来表示量化张量:[ -amax, 最大]。这里,最大是要表示的绝对值最大的元素。要计算量化比例,请将浮点动态范围划分为 256 个相等的部分:

使用 NVIDIA TensorRT 的量化感知训练实现 INT8 推理的 FP32 精度_数据_03
此处显示的计算比例的方法使用您可以用有符号 8 位整数表示的完整范围:[-128, 127]。TensorRT 显式精度 (Q/DQ) 网络在量化权重和激活时使用此范围。

选择使用 8 位整数表示的动态范围与舍入操作引入的误差之间存在紧张关系。更大的动态范围意味着来自原始浮点张量的更多值在量化张量中得到表示,但这也意味着使用更低的精度并引入更大的舍入误差。

选择较小的动态范围会减少舍入误差,但会引入限幅误差。超出动态范围的浮点值被剪裁为动态范围的最小值/最大值。

使用 NVIDIA TensorRT 的量化感知训练实现 INT8 推理的 FP32 精度_神经网络_04
为了解决精度损失对任务准确性的影响,已经开发了各种量化技术。这些技术可以归为两类之一:训练后量化 (post-training quantization, PTQ) 或量化感知训练 (quantization-aware training, QAT)。

顾名思义,PTQ 是在训练高精度模型之后执行的。使用 PTQ,量化权重很容易。您可以访问权重张量并测量它们的分布。量化激活更具挑战性,因为必须使用真实输入数据测量激活分布。

为此,使用代表任务真实输入数据的小数据集来评估经过训练的浮点模型,并收集有关层间激活分布的统计数据。作为最后一步,模型激活张量的量化尺度是使用多个优化目标之一确定的。这个过程是校准,使用的代表性数据集是校准数据集。

有时 PTQ 无法达到可接受的任务精度。这是您可以考虑使用 QAT 的时候。QAT 背后的想法很简单:如果在训练阶段包含量化误差,就可以提高量化模型的准确性。它使网络能够适应量化的权重和激活。

有多种方法可以执行 QAT,从未训练模型开始到预训练模型开始。所有配方都改变了训练方案,通过在训练图中插入伪量化操作来模拟数据和参数的量化,从而将量化误差包含在训练损失中。这些操作被称为“假”,因为它们对数据进行量化,但随后立即对数据进行反量化,因此操作的计算保持浮点精度。这个技巧在深度学习框架中没有太大改变的情况下增加了量化噪声。

在前向传递中,您对浮点权重和激活进行伪量化,并使用这些伪量化的权重和激活来执行层的操作。在向后传递中,您使用权重的梯度来更新浮点权重。为了处理量化梯度,除了未定义的点外,几乎所有地方都为零,您可以使用 (直通估计器(STE),它将梯度按原样通过伪量化算子传递。当 QAT 过程完成后,伪量化层持有量化尺度,用于量化模型用于推理的权重和激活。

使用 NVIDIA TensorRT 的量化感知训练实现 INT8 推理的 FP32 精度_深度学习_05
PTQ 是两者中更流行的方法,因为它简单且不涉及训练管道,这也使其成为更快的方法。然而,QAT 几乎总是能产生更好的准确性,有时这是唯一可接受的方法。

TensorRT 中的量化

TensorRT 8.0 支持使用两种不同处理模式的 INT8 模型。第一种处理模式使用 TensorRT 张量动态范围 API,并机会性地使用 INT8 精度(8 位有符号整数)计算和数据来优化推理延迟。

使用 NVIDIA TensorRT 的量化感知训练实现 INT8 推理的 FP32 精度_数据_06
当 TensorRT 执行完整的 PTQ 校准配方以及当 TensorRT 使用预配置的张量动态范围时,将使用此模式(图 3)。另一种 TensorRT INT8 处理模式用于处理具有QuantizeLayer/DequantizeLayer层的浮点 ONNX 网络并遵循明确的量化规则。有关差异的更多信息,请参阅TensorRT 开发人员指南中的显式量化与 PTQ 处理。

用于 PyTorch的TensorRT 量化工具包通过提供方便的 PyTorch 库来帮助生成可优化的 QAT 模型,从而对 TensorRT 进行了补充。该工具包提供了一个 API,用于自动或手动为 QAT 或 PTQ 准备模型。

API 的核心是TensorQuantizer模块,它可以量化、伪量化或收集张量的统计信息。它与 一起使用QuantDescriptor,它描述了张量应该如何被量化。层层TensorQuantizer叠叠的是量化模块,这些模块被设计为 PyTorch 全精度模块的直接替代品。这些是方便的模块,用于TensorQuantizer对模块的权重和输入进行伪量化或收集统计信息。

API 支持将 PyTorch 模块自动转换为其量化版本。也可以使用 API 手动完成转换,在您不想量化所有模块的情况下,它允许部分量化。例如,某些层可能对量化更敏感,让它们未量化可提高任务准确性。

使用 NVIDIA TensorRT 的量化感知训练实现 INT8 推理的 FP32 精度_权重_07
NVIDIA 量化白皮书中详细描述了针对 QAT 的 TensorRT 特定配方,其中包括对量化方法的更严格讨论,以及在各种学习任务上比较 QAT 和 PTQ 的实验结果。

通过构建 TensorRT Q/DQ 网络创建的计划文件包含量化的权重和操作,并已准备好部署。EfficientNet 是需要 QAT 来保持准确性的网络之一。下图比较了 PTQ 和 QAT。
使用 NVIDIA TensorRT 的量化感知训练实现 INT8 推理的 FP32 精度_数据_08

结论

在这篇文章中,我们简要介绍了基本的量化概念和 TensorRT 的量化工具包,然后回顾了 TensorRT 8.0 如何处理 Q/DQ 网络。我们对量化工具包提供的 ResNet50 QAT 示例进行了快速演练。

ResNet50 可以使用 PTQ 进行量化,不需要 QAT。然而,EfficientNet 需要 QAT 来保持准确性。EfficientNet B0基线浮点Top1精度为77.4,PTQ Top1精度为33.9,QAT Top1精度为76.8。

参考
​​​https://developer.nvidia.com/blog/achieving-fp32-accuracy-for-int8-inference-using-quantization-aware-training-with-tensorrt/​

其他资料:
​​​从TensorRT与ncnn看CNN卷积神经网络int8量化算法​