6.1. PTQ 转换原理及流程¶
6.1.1. 概览¶
模型从训练到转换再到在开发板运行的过程如下图所示:
模型训练,指使用 TensorFlow、PyTorch、Caffe 等公开深度学习框架得到可用模型的过程,通过训练得到的可用模型将作为模型转换阶段的输入。 工具链本身不会提供训练相关的库或工具,具体支持的公开学习框架可以参考 浮点模型准备 章节中的说明。
模型转换,本阶段以模型训练得到的浮点模型为输入,通过模型结构优化、模型校准量化等重要步骤, 将浮点模型转换为可以在地瓜机器人计算平台高效运行的混合异构模型。 具体使用请参考 模型量化和编译 章节中的说明。
嵌入式应用开发,工具链支持了在 X86 仿真环境和真实嵌入式环境的应用开发能力,在不方便使用开发板的情况下, 您在仿真环境完成程序的调试和计算结果的验证。 为了降低仿真验证的代价,工具链提供的仿真库接口与嵌入式接口完全一致,只是采用了不同的编译配置。 具体使用方式请参考 嵌入式应用开发指导 章节中的说明。
自定义算子开发,本阶段是一个可选阶段,主要是解决模型存在工具链不支持算子的情况,如果您没有此种情况,可以直接忽略本阶段的处理。 具体使用方式请参考 自定义算子开发 章节中的说明。
下面为您详细介绍 PTQ 转换的流程与步骤相关内容。
6.1.2. PTQ 转换流程说明¶
模型转换是指将原始浮点模型转换为地瓜机器人混合异构模型的过程。
原始浮点模型(文中部分地方也称为浮点模型)是指您通过 TensorFlow/PyTorch 等等 DL 框架训练得到的可用模型,这个模型的计算精度为 float32。
混合异构模型是一种适合在地瓜机器人计算平台上运行的模型格式。
后文将反复使用到这两种模型名词,为避免理解歧义,请先理解这个概念再阅读下文。
配合地瓜机器人工具链的模型完整开发过程,需要经过 浮点模型准备 、 模型验证 、 模型转换 、 性能评估 和 精度评估 共五个重要阶段,如下图所示。
浮点模型准备 阶段的产出是输入到模型转换工具的浮点模型, 这些模型一般都是基于公开 DL 训练框架得到的, 需要您注意的是将模型导出为地瓜机器人工具支持的格式。 具体要求与建议请参考 浮点模型准备 章节。
模型验证 阶段用来确保算法模型是符合计算平台要求的。 地瓜机器人提供了指定工具完成此阶段检查,对于不符合要求的情况, 检查工具会明确给出不符合要求的具体算子信息,方便您结合算子约束的说明将模型调整过来。 具体使用请参考 验证模型 章节。
模型转换 阶段将完成浮点模型到地瓜机器人混合异构模型的转换。 为了模型能在地瓜机器人计算平台上高效运行,地瓜机器人转换工具内部会完成模型优化、量化和编译等关键步骤, 地瓜机器人的量化方法经过了长期的技术与生产验证,在大部分典型模型上可以保证精度损失小于 1%。 具体使用请参考 校准数据准备 及 模型量化与编译 章节。
性能评估 阶段提供了系列评估模型性能的工具。 在应用部署前,您可以使用这些工具验证模型性能是否达到应用要求。 对于部分性能不及预期的情况,也可以参考地瓜机器人提供的性能优化建议进行调优。 具体评估请参考 模型性能分析 章节。
精度评估 阶段提供了系列评估模型精度的工具。 大部分情况下,地瓜机器人转换后模型可以保持与原始浮点模型基本一致的精度效果, 在应用部署前,您可以使用地瓜机器人工具验证模型的精度是否符合预期。 对于部分精度不及预期的情况,也可以参考地瓜机器人提供的精度优化建议进行调优。 具体评估请参考 模型精度分析 章节。
注意
通常在模型转换后就已经得到了可以上板的模型, 但是为了确保您得到的模型性能和精度都是符合应用要求的, 地瓜机器人强烈建议每次转换后都完成后续的性能评估与精度评估步骤。
模型转换过程会生成 onnx 模型,该模型均为中间产物,只是便于验证模型精度情况, 因此不保证其在版本间的兼容性。若使用示例中的评测脚本对 onnx 模型单张或在测试集上进行评测时, 请使用当前版本工具生成的 onnx 模型进行操作。
6.1.3. 模型转换过程详解¶
那么如何使用浮点模型转换工具将 Caffe、TensorFlow、PyTorch 等开源框架训练好的浮点模型转换成地瓜机器人硬件上支持的定点模型呢?
一般情况下,从官网下载或者自己训练得到的模型,其阈值、权重等均为浮点数(float32),每个数占用 4 个字节。 但在嵌入式端运行时,若能将其内部数值从浮点数转化为定点数(int8),则每个数只占用 1 个字节,因此计算量可以大大减少。 因此,若能在不损失或损失较小的情况下将浮点模型转换为定点模型,则其性能会有显著提升。
模型的转换通常可分为以下几个步骤:
1.检查待转换的模型中是否包含不支持的 OP 类型。
2.准备好 20-100 张校准使用的图片,用于转换阶段的校准操作。
3.使用浮点模型转换工具将原始浮点模型转换为定点模型。
4.对转换后的模型进行性能和精度的评估,确保转换后的定点模型精度与之前相差不大。
5.在模拟器/开发板上运行模型,对模型的性能和精度进行验证。
6.1.3.1. 模型检查(hb_mapper checker)¶
注解
如果本过程您需在示例文件夹内进行,那么您需要先执行文件夹中的 00_init.sh 脚本以获取对应的原始模型和数据集。
模型在从浮点转换为定点模型之前,我们首先需要通过工具 hb_mapper checker 子命令检查一下,看看该模型是否包含不能在地瓜机器人硬件上运行的 OP。
如果存在,则会在该阶段提示不认识该 OP, hb_mapper checker 子命令使用方式可参考 模型检查命令 一节内容。
若过程中存在不支持 OP,则会出现如下提示:
ERROR HorizonRT not support these cpu operators: {不支持的OP名称}
小技巧
有关地瓜机器人硬件可支持的 OP 信息,请参见 工具链算子支持约束列表 章节内容。
若无不支持 OP,则会输出模型转换后的各 OP 的列表,以及各 OP 被划分在 CPU 还是 BPU 上执行。若验证结束且无报错,即可继续进行后续步骤。参见如下:
hb_mapper checker --model-type caffe --proto mobilenet_deploy.prototxt \
--model mobilenet.caffemodel --march bayes-e
2023-12-06 17:33:53,117 INFO log will be stored in ....
2023-12-06 17:33:53,117 INFO Start hb_mapper....
...
2023-12-06 17:33:53,118 INFO hb_mapper version 3.0.3
...
fc7 BPU id(0) HzSQuantizedConv
prob CPU -- Softmax
2023-12-06 17:33:53,329 INFO End to D-Robotics NN Model Convert.
2023-12-06 17:33:53,332 INFO ONNX model output num : 1
2023-12-06 17:33:53,351 INFO End model checking....
小技巧
若存在不支持 OP,可咨询地瓜机器人技术人员相关 OP 开发计划,或者参考 自定义算子开发 章节,通过 自定义算子(Custom OP) 功能添加该 OP。
6.1.3.2. 准备校准图片¶
注解
如果本过程您需在示例文件夹内进行,那么您需要先执行文件夹中的 00_init.sh 脚本以获取对应的原始模型和数据集。
在进行模型转换时,校准阶段需要 20-100 张图片输入进行校准操作。 由于模型的输入类型及 layout 的不同,输入的图片格式可以多种多样。 该阶段既可以输入原始图片(*.jpg 等), 也可以输入处理过的,满足模型输入要求的图片。 您可以直接从模型训练时的数据集中获取相应的校准图片,也可以自行处理图片生成校准数据集。
推荐您自行对校准图片进行前处理,将图片的通道(BGR/RGB),数据排布(NHWC/NCHW),图像大小及填充(Resize&Padding)等操作调整好后,
设置 yaml 文件(mobilenet_config.yaml) 中的 preprocess_on 参数为 False,那么工具则会通过二进制文件的方式将图片读入后送入校准阶段。
以 MobileNet 为例,则需要进行如下 transformer 的操作:
transformers = [
ShortSideResizeTransformer(short_size=256), # 短边Pad到256, 保持长宽比
CenterCropTransformer(crop_size=224), # 图像中心抠224*224的图像
HWC2CHWTransformer(), # 数据排布从NHWC转换到NCHW
RGB2BGRTransformer(data_format="CHW"), # 颜色通道从RGB转换为BGR
ScaleTransformer(scale_value=255), # 数据范围从 0-1 转为 0-255
]
小技巧
若模型训练时是 bgr/rgb 色彩空间的,则校准阶段传入工具的图片数据需要是 bgr/rgb 色彩空间的, 工具内部会自动完成从 bgr/rgb 到 yuv444/gray 等的色彩转换。
例如:示例中的 MobileNet 模型实际输入设置为 nv12,而 02_preprocess.sh 脚本转换结束后是 bgr 颜色空间的, 剩余的从 bgr 到 nv12 的转换是由工具内部自动补全的。
6.1.3.3. 模型转换(hb_mapper makertbin)¶
当通过上述 hb_mapper checker 子命令,确定了模型能够被转换成功后,
接下来可以使用 hb_mapper makertbin 子命令来将浮点模型转换为一个可以在地瓜机器人硬件上运行的定点模型。
该命令需要传入待转换模型的模型类型( caffe / onnx )以及一个包含转换要求的配置文件(*.yaml)。
具体的配置文件设置及各参数的含义,请参考 配置文件模板 和 配置文件具体参数信息 章节的介绍。
模型转换过程结束后,还会将原始模型与转换后的定点模型的相似程度打印在 log 中,
可根据 Cosine Similarity 字段来判断模型转换前后的相似度。
如下方所示,模型转换后的 Cosine Similarity 非常接近 1,
因此模型转换后的模型表现会与转换前的浮点模型非常相近。
2023-12-06 20:26:50,149 INFO Start hb_mapper....
......
2023-12-06 20:27:21,427 INFO End to compile the model with march bayes-e.
2023-12-06 20:27:21,429 INFO The converted model node information:
======================================================================================================================
Node ON Subgraph Type Cosine Similarity Threshold In/Out DataType
----------------------------------------------------------------------------------------------------------------------
HZ_PREPROCESS_FOR_data BPU id(0) HzSQuantizedPreprocess 0.999988 127.000000 int8/int8
conv1 BPU id(0) HzSQuantizedConv 0.999922 2.937425 int8/int8
conv2_1/dw BPU id(0) HzSQuantizedConv 0.999378 2.040827 int8/int8
conv2_1/sep BPU id(0) HzSQuantizedConv 0.996680 4.486579 int8/int8
conv2_2/dw BPU id(0) HzSQuantizedConv 0.997340 3.545496 int8/int8
conv2_2/sep BPU id(0) HzSQuantizedConv 0.996384 2.791299 int8/int8
conv3_1/dw BPU id(0) HzSQuantizedConv 0.994165 1.417208 int8/int8
conv3_1/sep BPU id(0) HzSQuantizedConv 0.985451 2.188753 int8/int8
conv3_2/dw BPU id(0) HzSQuantizedConv 0.994921 1.822225 int8/int8
conv3_2/sep BPU id(0) HzSQuantizedConv 0.994251 1.841765 int8/int8
conv4_1/dw BPU id(0) HzSQuantizedConv 0.988263 1.043535 int8/int8
conv4_1/sep BPU id(0) HzSQuantizedConv 0.990294 1.736999 int8/int8
conv4_2/dw BPU id(0) HzSQuantizedConv 0.992460 0.990603 int8/int8
conv4_2/sep BPU id(0) HzSQuantizedConv 0.993468 1.574677 int8/int8
conv5_1/dw BPU id(0) HzSQuantizedConv 0.988949 0.823123 int8/int8
conv5_1/sep BPU id(0) HzSQuantizedConv 0.990803 1.265912 int8/int8
conv5_2/dw BPU id(0) HzSQuantizedConv 0.990202 0.772344 int8/int8
conv5_2/sep BPU id(0) HzSQuantizedConv 0.983443 1.530479 int8/int8
conv5_3/dw BPU id(0) HzSQuantizedConv 0.986502 0.783812 int8/int8
conv5_3/sep BPU id(0) HzSQuantizedConv 0.977642 1.927324 int8/int8
conv5_4/dw BPU id(0) HzSQuantizedConv 0.982337 0.996043 int8/int8
conv5_4/sep BPU id(0) HzSQuantizedConv 0.962062 2.167391 int8/int8
conv5_5/dw BPU id(0) HzSQuantizedConv 0.978872 1.923361 int8/int8
conv5_5/sep BPU id(0) HzSQuantizedConv 0.960184 3.578415 int8/int8
conv5_6/dw BPU id(0) HzSQuantizedConv 0.980317 2.463874 int8/int8
conv5_6/sep BPU id(0) HzSQuantizedConv 0.981055 4.124151 int8/int8
conv6/dw BPU id(0) HzSQuantizedConv 0.998241 0.667692 int8/int8
conv6/sep BPU id(0) HzSQuantizedConv 0.985220 0.983833 int8/int8
pool6 BPU id(0) HzSQuantizedGlobalAveragePool 0.993602 11.415899 int8/int8
fc7 BPU id(0) HzSQuantizedConv 0.995105 5.843800 int8/int32
prob CPU -- Softmax 0.985517 -- float/float
2023-12-06 20:27:21,430 INFO The quantify model output:
=======================================================================
Node Cosine Similarity L1 Distance L2 Distance Chebyshev Distance
-----------------------------------------------------------------------
prob 0.985517 0.000385 0.000203 0.185123
2023-12-06 20:27:21,432 INFO End to D-Robotics NN Model Convert.
注解
该相似度为校准图片中的第一张的相似度情况,并不完全代表模型转换前后的精度。
在模型转换成功后,会在生成的文件夹 (默认为 model_output ) 中生成如下文件:
静态性能评估文件(可读性更好):
\*_subgraph_0.html静态性能评估文件:
\*_subgraph_0.json原始浮点模型:
\*_original_float_model.onnx优化后的浮点模型:
\*_optimized_float_model.onnx校准模型::
\*_calibrated_model.onnx定点模型:
\*_quantized_model.onnx上板使用的混合模型:
\*.bin
这几个模型文件是模型转换的几个关键阶段产出的文件,并会在后续阶段使用到。
注解
可调用 03_classification/01_mobilenet/mapper/03_build.sh 脚本, 来体验
hb_mapper makertbin子命令的使用效果。如果希望了解更多模型转换的工作流程,请阅读 模型量化与编译 一节内容。
6.1.3.4. 单张图片的模型推理¶
在运行浮点模型转换之后,得到了定点模型,还需对其自身的正确性进行验证。
您需要对模型的输入/输出结构比较了解,并能够正确地对模型输入图片做前处理以及模型输出的后处理解析,并自行编写模型运行脚本。
在此过程中可参照交付包中 03_classification/01_mobilenet/mapper/04_inference.sh 中的示例代码。代码逻辑如下:
import numpy as np
# 加载地瓜机器人依赖库
from horizon_tc_ui import HB_ONNXRuntime
from postprocess import postprocess
# 准备模型运行的输入,此处`input.npy`为处理好的数据
input_data = np.load("input.npy")
# 加载模型文件
sess = HB_ONNXRuntime(model_file = "***_quantized_model.onnx")
# 获取模型输入&输出节点信息
input_names = sess.input_names
output_names = sess.output_names
# 准备输入数据,这里我们假设此模型只有1个输入
input_info = {input_names[0]: input_data}
# 开始模型推理,推理的返回值是一个list,依次与output_names指定名称一一对应
output = sess.run(output_names, input_info)
# 后处理
top_five_label_probs = postprocess(output)
使用该脚本后,便可通过输入单张图片验证其自身的正确性。
该脚本的输入为一张斑马的图片,在经过前处理将图片数据从 rgb 处理到 input_type_rt 的中间类型(无需-128)后(由于示例 mobilenet 的 input_type_rt 是 nv12,对应的中间类型为 yuv444_128,
因此 infer_transformers 过程需要完成 rgb–>nv12–>yuv444,关于中间类型的介绍可参考 转换过程内部解读 ),
通过 HB_ONNXRuntime 命令传入模型进行推理,推理后进行后处理,最后打印出其最可能的 5 个种类。
运行后的输出如下所示,最可能的类别是 label: 340。
I0108 18:11:47.398328 140427646048000 cls_inference.py:89] The input picture is classified to be:
label 340: prob 0.97
label 292: prob 0.02
label 282: prob 0.00
label 83: prob 0.00
label 的类别使用的是 ImageNet 的类别,也可以在 01_common/test_data/classes.txt 中查到, 340 正是对应着斑马,因此该图片推理正确。
6.1.3.5. 模型性能验证¶
模型在开发板上的运行帧率也是一个很重要的性能指标,未免去开发者架设开发板环境的麻烦,
我们可以直接使用 hb_perf 子命令对转换出来的模型进行性能分析。
在 MobileNetv1 示例中,运行命令 hb_perf mobilenetv1_224x224_nv12.bin 后,即可在 hb_perf_result/mobilenetv1_224x224_nv12/ 目录下找到模型分析文件 mobilenetv1_224x224_nv12.html 。
[horizon@gpu-dev model_output]$ hb_perf mobilenetv1_224x224_nv12.bin
2023-12-06 19:40:21,305 INFO log will be stored in horizon/.../mobilenetv1/hb_perf.log
2023-12-06 19:40:21,322 INFO Start hb_perf....
2023-12-06 19:40:21,323 INFO hb_perf version 1.21.0
2023-12-06 19:40:21,375 INFO ********* mobilenetv1_224x224_nv12 perf **********
......
2023-12-06 19:40:21,875 INFO file stored at : horizon/.../mobilenetv1_224x224_nv12/mobilenetv1_224x224_nv12.html
从 mobilenetv1_224x224_nv12.html 文件中,我们可以看到模型整体的各项性能数据。
当模型分为多段时,还会对每一段在 BPU 上运行的部分单独有性能分析报告。
上图中各项性能分别为:
Model Name: 模型名称。BPU Model Latency(ms):模型整体耗时(单位为 ms)。Total DDR (loaded+stored) bytes per frame(MB per frame):模型整体 BPU 部分数据加载和存储所占用的 DDR 总量(单位为 MB/frame)。Loaded Bytes per Frame:模型运行每帧读取数据量。Stored Bytes per Frame:模型运行每帧存储数据量。
注解
上述 BPU Model Latency(ms) 是指模型中在 BPU 上执行部分的耗时,如果模型中有 CPU 上执行的部分,则该部分耗时并未被计算在内。
6.1.3.6. 模型精度验证¶
针对模型的精度验证,我们提供了脚本对模型转换后的精度进行评测。 需要编写代码使模型能够循环推理图片,并将结果与标准结果进行比较,得到精度结果。
因为精度评测时,需要对图片进行 前处理,对模型数据进行 后处理,所以我们提供了一个示例 Python 脚本。
其原理与单张推理一致,但需要在整个数据集上面运行。
使用该脚本后,便可通过读取数据集,对模型的输出结果进行评判,并输出评测结果。
运行该脚本耗费时间较长,但可以通过设置 PARALLEL_PROCESS_NUM 环境变量来设置运行评测的线程数量。
在执行结束后得到的输出如下所示:
===REPORT-START{MAPPER-EVAL}===
0.7011
===REPORT-END{MAPPER-EVAL}===
可以看到转换后的定点模型精度为 0.7011。
注解
在不同的系统下,由于依赖库版本不同,转换得到的模型精度可能会略有差别。
同时由于版本更迭,得到的定点模型精度可能也会略有差别。
如果在使用模型转换工具后得到的定点模型有精度损失的话, 您可以参考 模型精度验证及调优建议 来进行问题查究。
6.1.3.7. [参考]支持的校准方法¶
目前我们支持了以下的校准方法:
1.default
default 是一个自动搜索的策略,会尝试从系列校准量化参数中获得一个相对效果较好的组合。
2.mix
mix 是一个集成多种校准方法的搜索策略,能够自动确定量化敏感节点,并在节点粒度上从不同的校准方法中挑选出最佳方法,
最终构建一个融合了多种校准方法优势的组合校准方式。
3.KL
KL 校准方法是借鉴了 TensorRT 提出的解决方案 , 使用 KL 熵值来遍历每个量化层的数据分布,通过寻找最低的 KL 熵值,来确定阈值。 这种方法会导致较多的数据饱和和更小的数据量化粒度,在一些数据分布比较集中的模型中拥有着比 max 校准方法更好的效果。
4.max
max 校准方法是在校准过程中,自动选择量化层中的最大值作为阈值。 这种方法会导致数据量化粒度较大,但也会带来比 KL 方法更少的饱和点数量,适用于那些数据分布比较离散的神经网络模型。
5.load
使用 QAT 导出的模型时,需使用此参数。
6.skip
若您只想尝试对模型性能进行验证,但对精度没有要求,则可以尝试 skip 方式进行校准。
该方式会使用 max+内部生成的随机校准数据进行校准,不需要您准备校准数据,比较适合初次尝试对模型结构进行验证。
注意
需要您注意的是,使用 skip 方式时,因该方式使用 max+内部生成的随机校准数据进行校准,故得到的模型不可用于精度验证。
6.1.3.8. [参考]OP 列表¶
若想了解更多关于当前工具链支持的算子列表及约束条件,请参见 工具链算子支持约束列表 章节内容。