地平线PTQ快速模型转换与性能评测

1. 理论介绍

1.1 为什么需要模型转换

由于嵌入式端资源受限,为了减少模型存储和计算开销,各家公司通常会将服务器上训练得到的浮点模型通过量化、编译等操作转换成对嵌入式芯片平台上友好的目标平台模型,然后再进行板端推理部署,大致流程如下图所示。-

-
为了实现将浮点模型量化、编译以及部署等操作,各家公司都推出了自己的一套工具,业内称之为“工具链”。量化层面,大多有两种方式:后量化(PTQ) 和 量化感知训练(QAT),其中PTQ在使用层面相对简单一些。-
下面以地平线工具链为例,介绍用户可以如何使用hb_mapper工具完成PTQ方案模型转换。

1.2 如何实现模型转换

1.2.1 模型转换流程

走PTQ通路实现模型转换,只需要使用hb_mapper这一个量化编译工具即可实现,当然,hb_mapper工具需要一些输入:浮点模型、校准数据、yaml配置文件。下面分别来介绍一下这三者。-

浮点模型是基于公开的深度学习框架训练得到的,地平线直接支持Caffe1.0和ONNX(opset_version=10/11 且 ir_version≤7)两种, PyTorch、TensorFlow、PaddlePaddle等通过转到ONNX实现间接支持,在地平线开发者社区提供了不同框架转ONNX的教程,欢迎有需要的同学们查看:Pytorch导出ONNX及模型可视化教程PaddlePaddle导出ONNX及模型可视化教程TensorFlow2导出ONNX及模型可视化教程

校准数据用于统计模型量化参数,从训练/验证集中筛选约 100 份典型样本,确保其中不包含纯色、无目标的脏数据即可,在性能评测时可不准备校准数据。

yaml配置文件指一些可配置参数集锦,绝大部分参数使用默认配置即可。

模型量化编译主要包括:模型结构优化、参数量化、模型编译等操作,得到最适合板端部署的指令集,也就是板端部署的bin模型,通常称之为混合异构模型,重点是,这个过程不需要开发者干预!

1.2.2 fast-perf模式(面向性能评测)

为尽可能简化操作步骤,加速用户模型性能评测流程,从J5 OE v1.1.52,X3 OE v2.6.2,J3 OE v1.17.2版本开始,我们新增了fast-perf模型转换模式,可省去yaml文件和校准数据的准备过程,实现一行命令直接编译得到板端最高性能的 bin 模型(由于校准数据是随机生成的,该模型只可用于性能评测)。具体使用方法为:

hb_mapper makertbin --fast-perf --march bayes --model model.onnx --model-type onnx

在 fast-perf 模式下,工具内部会自动完成如下操作:

  • 将 BPU 可执行算子尽可能运行在 BPU 上(即可通过 yaml 文件中 node_info 参数指定在 BPU 上运行的算子)
  • 删除模型首尾部可删除的 CPU 算子,包括:量化/反量化节点、Transpose、Cast、Reshape 等
  • 以性能最高的 O3 优化等级编译模型

1.3 性能评测简介

性能评测,顾名思义就看模型能跑多"快"的,这个快主要有两个指标衡量,一个是单帧延迟latency,一个是帧率FPS。-
单帧延时latency体现了单个模型处理一帧数据所需的时间,是衡量芯片能满足实时性要求的一个重要指标,但因为不同计算平台有多核、大小核、异构计算等不同的架构和设计,所以单帧延时指标有时并不能体现芯片的全部性能,例如双核 BPU 的 J5 在评测单帧延时时就会有一个核心处于空闲状态。-
帧率FPS体现了计算平台在满载/接近满载状态下,单位时间能够处理的图像总帧数。在真实场景中,计算平台要并发处理多个摄像头的数据,所以越大的吞吐量才能满足更大的数据处理要求,更贴合实际性能表现,也能作为统一的指标综合体现不同芯片架构的能力。-
地平线提供了两个工具hb_perf和hrt_model_exec分别用来在开发机中预估性能(静态性能评估)和在板端实测性能(动态性能评估),关于性能不符合预期的情况,欢迎查看《模型性能分析与调优》。-

1.3.1 静态性能评估简介

hb_perf 工具用于在开发机中预估BPU部分模型的性能,这部分称之为静态性能评测。在静态性能评测时,大家可以从产出物中获取到量化编译后模型中BPU部分算子粒度的预估耗时和BPU部分模型的预估latency与FPS,如下图所示:-

-

注意:图中的latency和FPS不含CPU部分的计算评估,如果希望查看CPU+BPU部分的总耗时信息,就需要在开发板上实测性能了。-
也可以获取到混合异构bin模型的结构图,如下图:-

-
其中,深蓝色的表示BPU部分,灰色的表示CPU部分。-
当我们在进行性能调优时,可以通过静态性能评估的方式查看模型BPU部分算子粒度的耗时信息,进而进行针对性的优化,特别是在缺乏硬件开发板的时候,静态性能评测可以粗略估计出模型的性能情况。

1.3.2 动态性能评估简介

hrt_model_exec工具,可以实现通过一行命令即可在板端测出模型实际运行耗时,这部分称之为动态性能评测,hrt_model_exec存放在OE包ddk/package/board/hrt_tools/bin目录下,使用方式可见 hrt_model_exec工具介绍

理论介绍完毕,下面我们一起进入实操环节~

2. 模型转换实操(开发机)

在跟着本文进行实操前,请确保您的 开发机环境(J5开发环境部署 or XJ3开发环境部署)和地平线板端环境(J5运行环境部署 or XJ3运行环境部署) 已准备完成。-
为了方便大家复现和演示,准备的文件均从OE开发包中获取。

2.1 进入开发环境

本文根据教程 docker镜像环境部署 进行演示,大家也可以根据 地平线PTQ环境本地安装 进入开发环境:

cd horizon_j5_open_explorer_v{version}-py38_{date}
bash run_docker.sh data cpu
# 上面命令进入有问题的话可以换成:
#docker run -it --rm -v ${PWD}:/open_explorer  openexplorer/ai_toolchain_ubuntu_20_j5_gpu:v{version}

2.2 使用fast-perf进行快速模型转换

ddk/samples/ai_toolchain/model_zoo/mapper/classification/efficientnet_lite_onnx/路径下efficientnet_lite0_fp32.onnx模型为例,通过fast-perf模式进行模型转换

hb_mapper makertbin --fast-perf --model efficientnet_lite0_fp32.onnx --model-type onnx --march bayes

模型转换的生成物都在model_output文件夹下,内容如下:

model_output
    |-- model.bin  
    |-- model_calibrated_model.onnx      
    |-- model_optimized_float_model.onnx
    |-- model_original_float_model.onnx
    |-- model_quantized_model.onnx
    |-- pre-alpha_subgraph_0.html
    `-- pre-alpha_subgraph_0.json

其中model.bin就是用来实现性能评测的混合异构模型,其它的xxx.onnx属于中间产物,主要用于精度评测。

3. 性能评测实操

3.1 静态性能评测(开发机)

使用hb_perf工具进行静态性能评估,命令如下:

hb_perf model_output/efficientnet_lite0_fp32.bin

会生成一个hb_perf_result文件夹,里面model.png就是关于model.bin的结构图,如下所示:-

3.2 动态性能评测(开发板)

将转换产出物efficientnet_lite0_fp32.bin传到板端,建议放置在/userdata/文件夹下。

  • 先查看当前板端是否有其它程序正在运行:

    top

  • 通过如下命令评测latency:单核单线程跑1000帧看平均latency

    ./hrt_model_exec perf --model_file model.bin --core_id 1 --thread_num 1 --frame_count 1000

  • 通过如下命令评测FPS:双核多线程跑1000帧看平均FPS

    ./hrt_model_exec perf --model_file model.bin --core_id 0 --thread_num 8 --frame_count 1000

至此,模型转换与性能评测完成,更详细性能评测信息欢迎参考:PTQ性能评测及结果解读。

请问最后的hrt_model_exec示例,core_id为0时,你们手册里写的any,这算是双核么?而且在编译得到bin模型的时候,yaml中明确写了J5不支持双核模型,既然不支持双核模型,那为什么要测试双核多线程呢??

J5不支持双核。XJ3支持双核,意思是能用两个BPU同时推理同一帧,算是一个线程。J5的any core指的是任意核调度,由板端推理库决定当前任务运行在哪个核上。