6.6.1. 训练后量化(PTQ)常见问题

6.6.1.1. 如何理解算子约束中提及的 BPU 加速和 CPU 计算两种形式?

  • BPU 加速:是指模型在板端推理时,该算子可以通过 BPU 硬件进行量化加速。其中,大部分算子(如 conv 等)是硬件直接支持的。 有些会被替换成其他算子实现加速(如 gemm 会被替换成 conv);还有一些则依赖特定的上下文(如 Reshape、Transpose 需要前后均为 BPU 算子)才能被动量化。

  • CPU 计算:对于模型中 BPU 硬件无法直接或间接加速的算子,工具链会将其放在 CPU 上计算,runtime 预测库也会在模型推理时自动完成执行硬件的异构调度。

6.6.1.2. 如何理解模型分段的性能影响?

当模型在 BPU 算子中间存在不能加速的 CPU 算子时,就会被切分成不同的 Subgraph(模型转换日志中会通过不同的 id 号进行区分),从而引入一定的性能损耗,具体包括两方面:

  • CPU 算子性能远低于 BPU 算子。

  • CPU 和 BPU 之间的异构调度还会引入量化、反量化算子(运行在 CPU 上),且因为内部计算需要遍历数据,所以其耗时会与 shape 大小成正比。

以上 CPU 算子和量化、反量化算子均可通过板端工具 hrt_model_exec 传入 profile_path 参数实测得到。地瓜机器人建议您尽量选择 BPU 算子搭建模型,以获取更好的性能表现。

6.6.1.3. 如何理解模型尾部部分 BPU 可加速算子运行在 CPU 上?

首先,我们需要理解以下两个概念:

  • X5 算法工具链目前只在模型尾部支持 Conv 算子以 int32 高精度输出,其他算子都只能以 int8 低精度输出。

  • 通常情况下,模型转换会在 optimization 阶段将 Conv 与其后的 BN 和 ReLU/ReLU6 融合在一起进行计算。 但由于 BPU 硬件本身限制,在模型尾部以 int32 高精度输出的 Conv 却并不支持算子融合。

所以如果模型以 Conv+ReLU/ReLU6 结尾,那么为了保证量化模型的整体精度,Conv 会默认以 int32 高精度输出,ReLU/ReLU6 则会跑在 CPU 上。 同理,其他尾部可加速算子运行在 CPU 上也都是默认精度优先的选择。不过,地瓜机器人支持在 yaml 文件将这些算子配置 run_on_bpu ,从而获取更好的性能表现,但会引入一定的精度损失。

6.6.1.4. 如何理解地瓜机器人的 default 校准方式?

为了减轻用户调试校准方案的工作量,地瓜机器人提供了 default 自动搜索策略,当前其内部逻辑如下:

../../../../_images/faq_default.png
  • Step1:尝试 Max、Max-Percentile 0.99995 和 KL 三种校准方法,计算得到分别的余弦相似度。 如果三种方法中的最高余弦相似度小于 0.995,进入 Step2;反之,返回最高相似度对应的阈值组合。

  • Step2:尝试 Max-Percentile 0.99995 和 perchannel 量化的组合方法,如果余弦相似度仍小于 0.995,进入 Step3。 反之,返回最高相似度对应的阈值组合。

  • Step3:选取 Step2 中最高余弦相似度对应的方法,应用非对称量化作为第 5 种方法,根据余弦相似度选取 5 种方案中的最佳方案, 返回对应的阈值组合。

6.6.1.5. 如何理解地瓜机器人的 mix 校准方式?

为了集成不同校准方法的优势,地瓜机器人提供了 mix 搜索策略,当前其内部逻辑如下:

../../../../_images/faq_mix.png
  • Step1:采用 KL 校准方法,计算当前模型中节点的量化敏感度(使用余弦相似度来衡量), 将值小于特定阈值的节点定义为量化敏感节点(对模型量化精度影响较大的节点)。

  • Step2:遍历所有量化敏感节点,在每一个节点上尝试 Max、Max-Percentile 0.99995 和 KL 三种校准方法, 并为该节点选出最佳的校准方法,最终得到 Mix 校准模型。

  • Step3:评估 Mix、Max、Max-Percentile 0.99995 和 KL 校准模型的累积误差情况,输出最优模型。

6.6.1.6. 如何理解 yaml 文件中的编译器优化等级参数?

在模型转换的 yaml 配置文件中,编译参数组提供了 optimize_level 参数来选择模型编译的优化等级,可选范围为 O0~O3。其中:

  • O0 不做任何优化,编译速度最快,适合在模型转换功能验证、调试不同校准方式时使用。

  • O3 优化等级最高,可以获得模型最佳性能,但编译时间也相对较长。

  • 在 O1~O3 范围内,优化等级越高,编译优化时的搜索空间就会越大。同时,一些比较耗时的优化策略也仅会在 O2/O3 等级才会启用。

  • 编译器的优化策略并不是算子粒度层面的,而是针对整个模型的全局优化。

6.6.1.7. 为何 nv12 模型 hb_perf 得出的输入大小和预测库不一致?

NV12 图像格式属于 YUV 颜色空间中的 YUV420SP 格式,是摄像头可直接输出的视频格式。由于一般在实际训练时不会使用这种格式, 因此底层硬件拿到摄像头输出的数据后,会先将其转换为 yuv444 的格式再进行后续推理(该转换过程用户不感知,板端推理时只需依据模型转换时配置的 input_type_rt 准备对应类型的数据即可)。 hb_perf 工具显示的是 nv12 数据的大小(即 NxHxWx3/2),而板端 hrt_model_exec model_info 获取到的数据大小则是模型真实输入的数据大小(即 NxHxWx3)。 且由于 nv12 数据已经不具有 channel 的概念了,板端部署时用户只需依据输入节点的 H 和 W 信息,准备对应大小的 nv12 数据即可。

6.6.1.8. 量化模型和上板 bin 模型的输入的数据排布是否一定一致?

onnx 模型和上板 bin 模型的输入数据排布 不一定完全一致 。上板 bin 的输入数据排布与 yaml 配置文件中的 input_layout_rt 对齐,但 quanti.onnx 的数据排布则会因为多种因素发生改变,例如:

  • 当模型的 input type rt 设置为 nv12 时,input_source 默认为 pyramid , 当输入为 pyramid 时,量化模型 quanti.onnx 的输入均为 NHWC。

  • 当 input type rt 为 yuv444/rgb/bgr 等类型时,input_source 默认为 ddr , 此时量化模型 quanti.onnx 的输入与原始浮点模型一致。

此外其他场景也有可能会出现***.onnx 与***.bin 输入数据排布不一致的情况。

因此,当您在 PC 端推理***.onnx 时,建议使用可视化工具查看一下 onnx 模型的输入 shape,并准备对应的数据。 当在板端推理.bin 模型时,则依据转换时配置的 input_layout_rt 或使用工具 hrt_model_exec model_info 以及 BPU SDK 相关 API(hbDNNGetInputTensorProperties())获取.bin 模型的输入 shape。 当您使用同一张图片推理 quanti.onnx 以及.bin 发现输出结果差异很大时,建议您先排查输入数据排布是否正确。

6.6.1.9. 如何编译得到多 batch 模型?

根据原模型种类,我们将分为动态输入模型和非动态输入模型来讨论这个问题。

注解

  • input_batch 参数仅在 input_shape 第一维为 1 的时候可以使用(模型为多输入时,需要所有输入的 input_shape 第一维均为 1),且此参数仅在原始 onnx 模型本身支持多 batch 推理时才能生效。该参数仅支持配置一个数值,模型为多输入时,该值将作用于模型的所有输入。

  • 每份校准数据 shape 大小,应和 input_shape 的大小保持一致。

动态输入模型:如果原模型为动态输入模型时,比如,? x3x224x224(动态输入模型必须使用 input_shape 参数指定模型输入信息)。

1.当配置 input_shape 为 1x3x224x224 时, 如果您想编译得到多 batch 的模型,可以使用 input_batch 参数,此时每份校准数据 shape 大小为 1x3x224x224。

2.当配置 input_shape 的第一维为大于 1 的整数时,原模型本身将会认定为多 batch 模型,将无法使用 input_batch 参数,且需要注意每份校准数据 shape 大小。例如配置 input_shape 为 4x3x224x224 时, 此时每份校准数据 shape 大小需要为 4x3x224x224。

非动态输入模型:

1.当输入的 input shape[0]为 1 时,可以使用 input_batch 参数,每份校准数据 shape 大小与原模型 shape 保持一致。

2.当输入的 input shape[0]不为 1 时,不支持使用 input_batch 参数。

6.6.1.10. 多输入模型在转换过程中,模型输入顺序发生变化,此种情况正常么?

此种情况是正常现象,多输入模型在转换过程中,模型输入顺序是有可能发生变化的。 可能发生的情况如下例所示:

  • 原始浮点模型输入顺序:input1、input2、input3。

  • original.onnx 模型输入顺序:input1、input2、input3。

  • quanti.onnx 模型输入顺序:input2、input1、input3。

  • bin 模型输入顺序:input3、input2、input1。

注意

  • 当您做精度一致性对齐时,请确保输入顺序是正确的,不然有可能会影响精度结果。

  • 如果您想查看 bin 模型输入的顺序,可以使用 hb_model_info 指令来查看,input_parameters info 分组中列出的输入顺序,即为 bin 模型的输入顺序。

6.6.1.11. 如何理解 PTQ 模型转换过程中的主动量化和被动量化?

在模型成功转换成 bin 模型后,可能会出现发现仍然有个别 op 运行在 CPU 上的情况,但回头仔细对照工具链算子约束列表,明明该 op 是符合算子约束条件的,也就是理论上该算子应该成功运行在 BPU 上,为什么仍然是 CPU 计算呢?

针对此问题,您可参考 地瓜机器人官方社区文章 ,该文章对模型转换工具链中内部的量化原理与背后的逻辑进行了介绍,并针对问题提供了几种解决方法。