4.1.1.6. 模型量化与编译

转换模型阶段会完成浮点模型到地瓜机器人混合异构模型的转换,经过这个阶段,您将得到一个可以在地瓜机器人计算平台上运行的模型。 在进行转换之前,请确保已经顺利通过了 验证模型 小节的过程。

模型转换使用 hb_mapper makertbin 工具完成,转换期间会完成模型优化和校准量化等重要过程,校准需要依照模型预处理要求准备校准数据, 您可以参考 校准数据准备 章节内容对校准数据进行预先准备。 为了方便您全面了解模型转换,本节将依次介绍转换工具使用、转换内部过程解读、转换结果解读和转换产出物解读。

4.1.1.6.1. 使用 hb_mapper makertbin 工具转换模型

hb_mapper makertbin 提供两种模式,开启 fast-perf 模式和不开启 fast-perf 模式。

fast-perf 模式开启后,会在转换过程中生成可以在板端运行最高性能的 bin 模型,工具内部主要进行以下操作:

  • 将 BPU 可执行算子尽可能运行在 BPU 上(即可通过 yaml 文件中 node_info 参数指定在 BPU 上运行的算子)。

  • 删除模型首尾可删除的 CPU 算子,包括:Quantize/Dequantize、Transpose、Cast、Reshape 等。

  • 以性能最高的 O3 优化等级编译模型。

hb_mapper makertbin 命令使用方式如下:

不开启 fast-perf 模式:

hb_mapper makertbin --config ${config_file}  \
                    --model-type  ${model_type}

开启 fast-perf 模式:

hb_mapper makertbin --fast-perf --model ${caffe_model/onnx_model} --model-type ${model_type} \
                    --proto ${caffe_proto} \
                    --march ${march} \
                    --input-shape ${input_node_name} ${input_shape}
hb_mapper makertbin的命令行参数说明:
--help

显示帮助信息并退出。

-c, --config

模型编译的配置文件,为 yaml 格式,文件名使用.yaml 后缀。

--model-type

caffe 或者 onnx

--fast-perf

开启 fast-perf 模式,该模式开启后,会在转换过程中生成可以在板端运行最高性能的 bin 模型,方便您用于后续的模型性能评测。

如您开启了 fast-perf 模式,还需要进行如下配置:

--model Caffe 或 ONNX 浮点模型文件。

--proto 用于指定 Caffe 模型 prototxt 文件。

--march BPU 的微架构。X3 系列处理器请设置为 bernoulli2 (默认)。

-i, --input-shape 可选参数,指定模型的输入节点的 shape 信息,目前此配置仅在开启 fast-perf 时生效。使用方式为:

  • 指定单个输入节点的 shape 信息,使用方式为 --input-shape input_1 1x3x224x224

  • 指定多个输入节点的 shape 信息,使用方式为 --input-shape input_1 1x3x224x224 --input-shape input_2 1x3x224x224

注意

如您未指定 --input-shape 参数,此时工具将仅支持动态输入节点第一维为[-1, 0, ?]的模型,默认会将动态输入节点的第一维设置为 1。

4.1.1.6.1.1. 配置文件模板

一份完整的配置文件模板如下:

注解

此处配置文件仅作展示,在实际模型配置文件中 caffe_modelonnx_model 两种只存在其中之一。

即,要么是 Caffe 模型,要么是 ONNX 模型。即 caffe_model + prototxt 或者 onnx_model 二选一。

# 模型参数组
model_parameters:
  # 原始Caffe浮点模型描述文件
  prototxt: '***.prototxt'

  # 原始Caffe浮点模型数据模型文件
  caffe_model: '****.caffemodel'

  # 原始Onnx浮点模型文件
  onnx_model: '****.onnx'

  # 转换的目标处理器架构
  march: 'bernoulli2'

  # 模型转换输出的用于上板执行的模型文件的名称前缀
  output_model_file_prefix: 'mobilenetv1'

  # 模型转换输出的结果的存放目录
  working_dir: './model_output_dir'

  # 指定转换后混合异构模型是否保留输出各层的中间结果的能力
  layer_out_dump: False

  # 指定模型的输出节点
  output_nodes: "OP_name"

  # 批量删除某一类型的节点
  remove_node_type: Dequantize

  # 删除指定名称的节点
  remove_node_name: "OP_name"

# 输入信息参数组
input_parameters:
  # 原始浮点模型的输入节点名称
  input_name: "data"

  # 原始浮点模型的输入数据格式(数量/顺序与input_name一致)
  input_type_train: 'bgr'

  # 原始浮点模型的输入数据排布(数量/顺序与input_name一致)
  input_layout_train: 'NCHW'

  # 原始浮点模型的输入数据尺寸
  input_shape: '1x3x224x224'

  # 网络实际执行时,输入给网络的batch_size,默认值为1
  input_batch: 1

  # 在模型中添加的输入数据预处理方法
  norm_type: 'data_mean_and_scale'

  # 预处理方法的图像减去的均值, 如果是通道均值,value之间必须用空格分隔
  mean_value: '103.94 116.78 123.68'

  # 预处理方法的图像缩放比例,如果是通道缩放比例,value之间必须用空格分隔
  scale_value: '0.017'

  # 转换后混合异构模型需要适配的输入数据格式(数量/顺序与input_name一致)
  input_type_rt: 'yuv444'

  # 输入数据格式的特殊制式
  input_space_and_range: 'regular'

  # 转换后混合异构模型需要适配的输入数据排布(数量/顺序与input_name一致),若input_type_rt配置为nv12,则此处参数不需要配置
  input_layout_rt: 'NHWC'

# 校准参数组
calibration_parameters:
  # 模型校准使用的标定样本的存放目录
  cal_data_dir: './calibration_data'

  # 指定校准数据二进制文件的数据存储类型。
  cal_data_type: 'float32'

  # 开启图片校准样本自动处理(skimage read; resize到输入节点尺寸)
  #preprocess_on: False

  # 校准使用的算法类型
  calibration_type: 'kl'

  # max 校准方式的参数
  max_percentile: 1.0

  # 强制指定OP在CPU上运行
  run_on_cpu: "OP_name"

  # 强制指定OP在BPU上运行
  run_on_bpu: "OP_name"

  # 指定是否针对每个channel进行校准
  per_channel: False

  # 指定输出节点的数据精度
  optimization: set_model_output_int8

# 编译参数组
compiler_parameters:
  # 编译策略选择
  compile_mode: 'latency'

  # 是否打开编译的debug信息
  debug: True

  # 模型运行核心数
  core_num: 1

  # 模型编译的优化等级选择
  optimize_level: 'O2'

  # 指定名称为data的输入数据来源
  input_source: {"data": "pyramid"}

  # 指定模型的每个function call的最大可连续执行时间
  max_time_per_fc: 1000

  # 指定编译模型时的进程数
  jobs: 8

# 自定义算子参数组
custom_op:
  # 自定义op的校准方式
  custom_op_method: register

  # 自定义OP的实现文件, 该文件可由模板生成, 详情见自定义OP相关文档
  op_register_files: sample_custom.py

  # 自定义OP实现文件所在的文件夹, 请使用相对路径
  custom_op_dir: ./custom_op

配置文件主要包含模型参数组、输入信息参数组、校准参数组、编译参数组和自定义算子参数组。 在您的配置文件中,每个参数组位置都需要存在,具体参数分为可选和必选,可选参数可以不配置。

以下是具体参数信息,参数会比较多,我们依照上述的参数组次序介绍。 可选/必选表示该参数项在配置文件中是否必须进行配置。

4.1.1.6.1.2. 配置文件具体参数信息

🛠️ 模型参数组

🛠️ 输入信息参数组

🛠️ 校准参数组

🛠️ 编译参数组

🛠️ 自定义算子参数组

4.1.1.6.1.3. param_value 配置

具体参数的设置形式为:param_name:  'param_value' ,参数存在多个值时使用 ';' 符号分隔: param_name:  'param_value1; param_value2; param_value3'

小技巧

当模型为多输入模型时,强烈建议您将 input_shape 等参数们显式的写出,以免造成参数对应顺序上的错误。

注意

  • 请注意,如果设置 input_type_rtnv12yuv444 ,则模型的输入尺寸中不能出现奇数。

  • 请注意,目前 X3 上暂不支持 input_type_rtyuv444input_layout_rtNCHW 组合的场景。

4.1.1.6.2. 转换内部过程解读

模型转换完成浮点模型到地瓜机器人混合异构模型的转换。 为了使得这个异构模型能快速高效地在嵌入式端运行, 模型转换重点在解决 输入数据处理模型优化编译 两个问题,本节会依次围绕这两个重点问题展开。

输入数据处理 方面地瓜机器人的边缘计算平台会为某些特定类型的输入通路提供硬件级的支撑方案, 但是这些方案的输出不一定符合模型输入的要求。 例如视频通路方面就有视频处理子系统,为采集提供图像裁剪、缩放和其他图像质量优化功能,这些子系统的输出往往是 yuv420 格式图像, 而我们的算法模型往往是基于 bgr/rgb 等一般常用图像格式训练得到的。 地瓜机器人针对此种情况提供的固定解决方案是,每个转换模型都提供两份输入信息描述, 一份用于描述原始浮点模型输入( input_type_traininput_layout_train), 另一份则用于描述我们需要对接的边缘平台输入数据( input_type_rtinput_layout_rt)。

图像数据的 mean/scale 也是比较常见的操作,显然 yuv420 等边缘平台数据格式不再适合做这样的操作, 因此,我们也将这些常见图像前处理固化到了模型中。 经过以上两种处理后,转换产出的异构模型的输入部分将变成如下图状态。

../../../../_images/input_data_process.png

上图中的数据排布就只有 NCHW 和 NHWC 两种数据排布格式,N 代表数量、C 代表 channel、H 代表高度、W 代表宽度, 两种不同的排布体现的是不同的内存访问特性。在 TensorFlow 模型 NHWC 较常用,Caffe 中就都使用 NCHW, 地瓜机器人平台不会限制使用的数据排布,但是有两条要求:第一是 input_layout_train 必须与原始模型的数据排布一致; 第二是在边缘平台准备好与 input_layout_rt 一致排布的数据,正确的数据排布指定是顺利解析数据的基础。

工具会根据 input_type_rtinput_type_train 指定的数据格式自动添加数据转换节点,根据地瓜机器人的实际生产经验, 并不是任意 type 组合都是需要的,为了避免您误用,我们只开放了一些固定的 type 组合如下表。

input_type_train \ input_type_rt

nv12

yuv444

rgb

bgr

gray

featuremap

yuv444

Y

Y

N

N

N

N

rgb

Y

Y

Y

Y

N

N

bgr

Y

Y

Y

Y

N

N

gray

N

N

N

N

Y

N

featuremap

N

N

N

N

N

Y

注解

表格中第一行是 input_type_rt 中支持的类型,第一列是 input_type_train 支持的类型, 其中的 Y/N 表示是否支持相应的 input_type_rtinput_type_train 的转换。 在转换得到的最终产出 bin 模型中, input_type_rtinput_type_train 是一个内部的过程, 您只需要关注 input_type_rt 的数据格式即可。 正确理解每种 input_type_rt 的要求,对于嵌入式应用准备推理数据很重要,以下是对 input_type_rt 每种格式的说明:

  • rgb、bgr 和 gray 都是比较常见的图像格式,注意每个数值都采用 UINT8 表示。

  • yuv444 是一种常见的图像格式,注意每个数值都采用 UINT8 表示。

  • nv12 是常见的 yuv420 图像格式,每个数值都采用 UINT8 表示。

  • nv12 有个比较特别的情况是 input_space_and_range 设置 bt601_video , 较于常规 nv12 情况,它的数值范围由[0,255]变成了[16,235],每个数值仍然采用 UINT8 表示。 请注意, bt601_video 仅在 input_type_trainbgrrgb 时支持通过 input_space_and_range 进行配置。

  • featuremap 适用于以上列举格式不满足您需求的情况,此 type 每个数值采用 float32 表示。 例如雷达和语音等模型处理就常用这个格式。

小技巧

以上 input_type_rtinput_type_train 是固化在工具链的处理流程中,如果您非常确定不需要转换, 将两个 input_type 设置成一样就可以了,一样的 input_type 会做直通处理,不会影响模型的实际执行性能。

同样的,数据前处理也是固化在流程中,如果您不需要做任何前处理,通过 norm_type 配置关闭这个功能即可,不会影响模型的实际执行性能。

模型优化编译 方面完成了模型解析、模型优化、模型校准与量化、模型编译几个重要阶段,其内部工作过程如下图所示。

../../../../_images/model_optimization.png

模型解析阶段 对于 Caffe 浮点模型会完成到 ONNX 浮点模型的转换。 在原始浮点模型上会根据转换配置中的配置参数决定是否加入数据预处理节点,此阶段产出一个 original_float_model.onnx。 这个 ONNX 模型计算精度仍然是 float32,在输入部分加入了一个数据预处理节点。

理想状态下,这个预处理节点应该完成 input_type_rtinput_type_train 的完整转换, 实际情况是整个 type 转换过程会配合地瓜机器人处理器硬件完成,ONNX 模型里面并没有包含硬件转换的部分。 因此 ONNX 的真实输入类型会使用一种中间类型,这种中间类型就是硬件对 input_type_rt 的处理结果类型, 数据 layout(NCHW/NHWC)会保持原始浮点模型的输入 layout 一致。 每种 input_type_rt 都有特定的对应中间类型,如下表:

nv12

yuv444

rgb

bgr

gray

featuremap

yuv444_128

yuv444_128

RGB_128

BGR_128

GRAY_128

featuremap

注解

表格中第一行加粗部分是 input_type_rt 指定的数据类型,第二行是特定 input_type_rt 对应的中间类型, 这个中间类型就是 original_float_model.onnx 的输入类型。每个类型解释如下:

  • *_128 指的是其数据类型减去 128 的结果,每个数值采用 int8 表示。

  • featuremap 是一个张量数据,每个数值采用 float32 表示。

模型优化阶段 实现模型的一些适用于地瓜机器人平台的算子优化策略,例如 BN 融合到 Conv 等。 此阶段的产出是一个 optimized_float_model.onnx,这个 ONNX 模型的计算精度仍然是 float32,经过优化后不会影响模型的计算结果。 模型的输入数据要求还是与前面的 original_float_model 一致。

模型校准阶段 会使用您提供的校准数据来计算必要的量化参数,通过校准数据计算得到的每个节点对应的量化参数并将其保存在校准节点中,此阶段的产出是 calibrated_model.onnx。

模型量化阶段 使用校准得到的参数完成模型量化,此阶段的产出是一个 quantized_model.onnx。 这个模型的计算精度已经是 int8,使用这个模型可以评估到模型量化带来的精度损失情况。 这个模型要求输入的基本数据格式和 layout 仍然与 original_float_model 一样,不过取值范围已经发生了变化, 整体较于 original_float_model 输入的变化情况描述如下:

  • 数据 layout 均使用 NHWC。

  • input_type_rt 的取值为非 featuremap 时,则输入的数据类型均使用 INT8, 反之, 当 input_type_rt 取值为 featuremap 时,则输入的数据类型则为 float32。

数据排布 layout 关系对应如下例:

  • 原模型输入 layout:NCHW。

  • input_layout_train: NCHW。

  • origin.onnx 输入 layout:NCHW。

  • calibrated_model.onnx 输入 layout:NCHW。

  • quanti.onnx 输入 layout:NHWC。

即:input_layout_train、origin.onnx、calibrated_model.onnx、quanti.onnx 输入的 layout 与原模型输入的 layout 一致。

注意

请注意,如果 input_type_rt 为 nv12 时,对应 quanti.onnx 的输入 layout 都是 NHWC。

模型编译阶段 会使用地瓜机器人模型编译器,将量化模型转换为地瓜机器人平台支持的计算指令和数据, 这个阶段的产出一个*.bin 模型,这个 bin 模型是后续将在地瓜机器人边缘嵌入式平台运行的模型,也就是模型转换的最终产出结果。

4.1.1.6.3. 转换结果解读

本节将依次介绍模型转换成功状态的解读、转换不成功的分析方式。 确认模型转换成功,需要您从 makertbin 状态信息、相似度信息和 working_dir 产出三个方面确认。 makertbin 状态信息方面,转换成功将在控制台输出信息尾部给出明确的提示信息如下:

2021-04-21 11:13:08,337 INFO Convert to runtime bin file successfully!
2021-04-21 11:13:08,337 INFO End Model Convert

相似度信息也存在于 makertbin 的控制台输出内容中,在 makertbin 状态信息之前,其内容形式如下:

======================================================================
Node    ON   Subgraph  Type     Cosine Similarity  Threshold
----------------------------------------------------------------------
...    ...     ...     ...       0.999936           127.000000
...    ...     ...     ...       0.999868           2.557209
...    ...     ...     ...       0.999268           2.133924
...    ...     ...     ...       0.996023           3.251645
...    ...     ...     ...       0.996656           4.495638

上面列举的输出内容中,Node、ON、Subgraph、Type 与 hb_mapper checker 工具的解读是一致的, 请参考前文 检查结果解读 ; Threshold 是每个层次的校准阈值,用于异常状态下向地瓜机器人技术支持反馈信息,正常状况下不需要关注; Cosine Similarity 反映的 Node 指示的节点中,原始浮点模型与量化模型输出结果的余弦相似度。

注意

需要您特别注意的是,Cosine Similarity 只是指明量化后数据稳定性的一种参考方式,对于模型精度的影响不存在明显的直接关联关系。 一般情况下,输出节点的相似度低于 0.8 就有了较明显的精度损失,当然由于与精度不存在绝对的直接关联, 完全准确的精度情况还需要您参考 模型精度分析与调优 的介绍。

转换产出存放在转换配置参数 working_dir 指定的路径中,成功完成模型转换后, 您可以在该目录下得到以下文件(*部分是您通过转换配置参数 output_model_file_prefix 指定的内容):

  • *_original_float_model.onnx

  • *_optimized_float_model.onnx

  • *_calibrated_model.onnx

  • *_quantized_model.onnx

  • *.bin

转换产出物解读 介绍了每个产出物的用途。 不过在上板运行前,我们强烈建议您完成 验证模型模型性能分析与调优 介绍的性能&精度评测过程,避免将模型转换问题延伸到后续嵌入式端。

如果以上验证模型转换成功的三个方面中,有任一个出现缺失都说明模型转换出现了错误。 一般情况下,makertbin 工具会在出现错误时将错误信息输出至控制台, 例如我们在 Caffe 模型转换时不配置 prototxtcaffe_model 参数,工具给出如下提示。

2021-04-21 14:45:34,085 ERROR Key 'model_parameters' error:
Missing keys: 'caffe_model', 'prototxt'
2021-04-21 14:45:34,085 ERROR yaml file parse failed. Please double check your input
2021-04-21 14:45:34,085 ERROR exception in command: makertbin

如果以上步骤不能帮助您发现问题,欢迎在地瓜机器人唯一官方技术社区(https://developer.d-robotics.cc/)提出您的问题, 我们将在 24 小时内给您提供支持。

4.1.1.6.4. 转换产出物解读

上文提到模型成功转换的产出物包括以下部分,本节将介绍每个产出物的用途:

  • *_original_float_model.onnx

  • *_optimized_float_model.onnx

  • *_calibrated_model.onnx

  • *_quantized_model.onnx

  • *.bin

*_original_float_model.onnx 的产出过程可以参考 转换内部过程解读 的介绍, 这个模型计算精度与转换输入的原始浮点模型是一模一样的,有个重要的变化就是为了适配地瓜机器人平台添加了一些数据预处理计算。 一般情况下,您不需要使用这个模型,在转换结果出现异常时,如果能把这个模型提供给地瓜机器人的技术支持,将有助于帮助您快速解决问题。

*_optimized_float_model.onnx 的产出过程可以参考 转换内部过程解读 的介绍, 这个模型经过一些算子级别的优化操作,常见的就是算子融合。 通过与 original_float 模型的可视化对比,您可以明显看到一些算子结构级别的变化,不过这些都不影响模型的计算精度。 一般情况下,您不需要使用这个模型,在转换结果出现异常时,如果能把这个模型提供给地瓜机器人的技术支持,将有助于帮助您快速解决问题。

*_calibrated_model.onnx 的产出过程可以参考 转换内部过程解读 的介绍, 这个模型是模型转换工具链将浮点模型经过结构优化后,通过校准数据计算得到的每个节点对应的量化参数并将其保存在校准节点中得到的中间产物。

*_quantized_model.onnx 的产出过程可以参考 转换内部过程解读 的介绍, 这个模型已经完成了校准和量化过程,量化后的精度损失情况可以从这里查看。 这个模型是精度验证过程中必须要使用的模型,具体使用方式请参考 模型精度分析与调优 部分的介绍。

*.bin 就是可以用于在地瓜机器人计算平台上加载运行的模型, 配合 嵌入式应用开发指导 部分介绍的内容, 您就可以将模型快速在计算平台上部署运行。不过为了确保模型的性能与精度效果是符合您的预期的, 我们强烈建议完成 模型性能分析与调优模型精度分析与调优 介绍的性能和精度分析过程后再进入到应用开发和部署。