3.2. 算法模型 PTQ 量化+上板 快速上手

本章节中,我们将为您介绍训练后量化 PTQ 方案的基本使用流程,便于您实现快速上手。 这里我们以 MobileNet-v1 模型为例,为您进行使用演示,详细内容将在后续章节为您展开介绍,基本工作流程如下图所示。

../../../_images/quickstart.png

注意

请注意,在您进行以下操作前,请确保您已经参考 环境部署 章节完成了开发机和开发板上的环境安装。

3.2.1. 浮点模型准备

OE 包在 ddk/samples/ai_toolchain/horizon_model_convert_sample 路径下为您提供了丰富的 PTQ 模型示例, 其中 MobileNet-v1 模型示例位于 03_classificarion/01_mobilenet 路径下。

请先执行其中的 00_init.sh 脚本来获取示例对应的校准数据集和原始模型。 示例模型的模型来源和相关说明请参考 如何准备模型 章节。

如您需要转换私有模型,请参考 浮点模型准备 章节内容 提前准备好 caffe1.0 或 opset=10/11 的 onnx 模型。下表为不同框架到 ONNX 模型格式转换的参考方案:

3.2.2. 模型验证

在浮点模型准备好之后,我们建议先进行快速的模型验证,以确保其符合计算平台的支持约束。 对于 Caffe1.0 框架的 MobileNet-v1 模型,我们可以在命令行中键入以下命令完成模型验证:

hb_mapper checker --model-type caffe \
                  --proto mobilenet_deploy.prototxt \
                  --model mobilenet.caffemodel \
                  --march bernoulli2

对于 ONNX 格式的 Efficientnet_lite0 模型,则键入以下命令:

hb_mapper checker --model-type onnx \
                  --model efficientnet_lite0_fp32.onnx \
                  --march bernoulli2

其中,两个模型文件都可从 ddk/samples/model_zoo/mapper/classification 路径获取。 而 hb_mapper checker 工具的主要参数如下,更多参数说明还请参考 验证模型 章节。

以 MobileNet-v1 模型为例,您可以使用 01_check.sh 脚本快速完成模型验证。

01_check.sh 脚本文件中的主要内容如下所示:

set -ex
cd $(dirname $0) || exit
model_type="caffe"
proto="../../../01_common/model_zoo/mapper/classification/mobilenet/mobilenet_deploy.prototxt"
caffe_model="../../../01_common/model_zoo/mapper/classification/mobilenet/mobilenet.caffemodel"
march="bernoulli2"

hb_mapper checker --model-type ${model_type} \
                  --proto ${proto} --model ${caffe_model} \
                  --march ${march}

如果模型验证不通过,请根据终端打印或在当前路径下生成的 hb_mapper_checker.log 日志文件确认报错信息和修改建议, 更多说明请参考 验证模型 章节。

3.2.3. 模型转换

模型验证通过后,就可以使用 hb_mapper makertbin 工具进行模型转换,参考命令如下:

hb_mapper makertbin --config mobilenet_config.yaml \
                    --model-type caffe

其中, mobilenet_config.yaml 为模型转换对应的配置文件,将在 Yaml 配置文件 中进行介绍。 model-type 则用于指定检查输入的模型类型, 可配置为 caffe 或者 onnx,不同模型类型对应的配置文件参数会稍有不同。

另外,PTQ 方案的模型量化还需要依赖一定数量预处理后的样本进行校准,将在 校准数据预处理 中进行介绍。

3.2.3.1. Yaml 配置文件

Yaml 配置文件共包含 4 个必选参数组( model_parametersinput_parameterscalibration_parameterscompiler_parameters )和 1 个可选参数组( custom_op ),每个参数组下也区分必选和可选参数(可选参数默认隐藏),具体要求和填写方式可以参考模型示例 及 模型量化与编译 章节。以下为 MobileNet-v1 模型的配置文件:

# 模型转化相关的参数
model_parameters:

  # Caffe浮点网络数据模型文件
  caffe_model: 'mobilenet.caffemodel'

  # Caffe网络描述文件
  prototxt: 'mobilenet_deploy.prototxt'

  # 适用BPU架构
  march: "bernoulli2"

  # 指定模型转换过程中是否输出各层的中间结果,如果为True,则输出所有层的中间输出结果
  layer_out_dump: False

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

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

# 模型输入相关参数, 若输入多个节点, 则应使用';'进行分隔, 使用默认缺省设置则写None
input_parameters:

  # (选填) 模型输入的节点名称, 此名称应与模型文件中的名称一致, 否则会报错, 不填则会使用模型文件中的节点名称
  input_name: ""

  # 网络实际执行时,输入给网络的数据格式,包括 nv12/rgb/bgr/yuv444/gray/featuremap
  input_type_rt: 'nv12'

  # 网络训练时输入的数据格式,可选的值为rgb/bgr/gray/featuremap/yuv444
  input_type_train: 'bgr'

  # 网络训练时输入的数据排布, 可选值为 NHWC/NCHW
  input_layout_train: 'NCHW'

  # (选填) 模型网络的输入大小, 以'x'分隔, 不填则会使用模型文件中的网络输入大小,否则会覆盖模型文件中输入大小
  input_shape: ''

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

  # 网络输入的预处理方法,主要有以下几种:
  # no_preprocess 不做任何操作
  # data_mean 减去通道均值mean_value
  # data_scale 对图像像素乘以data_scale系数
  # data_mean_and_scale 减去通道均值后再乘以scale系数
  norm_type: 'data_mean_and_scale'

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

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

# 模型量化相关参数
calibration_parameters:

  # 模型量化的参考图像的存放目录,图片格式支持Jpeg、Bmp等格式,输入的图片
  # 应该是使用的典型场景,一般是从测试集中选择20~100张图片,另外输入
  # 的图片要覆盖典型场景,不要是偏僻场景,如过曝光、饱和、模糊、纯黑、纯白等图片
  # 若有多个输入节点, 则应使用';'进行分隔
  cal_data_dir: './calibration_data_bgr'

  # 校准数据二进制文件的数据存储类型,可选值为:float32, uint8. 若有多个输入节点, 则应使用';'进行分隔
  cal_data_type: 'float32'

  # 模型量化的算法类型,支持default、mix、kl、max、load,通常采用default即可满足要求
  # 如不符合预期可先尝试修改为mix 仍不符合预期再尝试kl或max
  # 当使用QAT导出模型时,此参数则应设置为load
  # 相关参数的技术原理及说明请您参考用户手册中的PTQ原理及步骤中参数组详细介绍部分
  calibration_type: 'max'

  # 该参数为'max'校准方法的参数,用以调整'max'校准的截取点。此参数仅在calibration_type为'max'时有效。
  # 该参数取值范围:0.5 ~ 1.0。常用配置选项有:0.99999/0.99995/0.99990/0.99950/0.99900。
  max_percentile: 0.9999

# 编译器相关参数
compiler_parameters:

  # 编译策略,支持bandwidth和latency两种优化模式;
  # bandwidth以优化ddr的访问带宽为目标;
  # latency以优化推理时间为目标
  compile_mode: 'latency'

  # debug默认为True,即打开编译器的debug模式,能够输出性能仿真的相关信息,如帧率、DDR带宽占用等
  debug: True

  # 优化等级可选范围为O0~O3
  # O0不做任何优化, 编译速度最快,优化程度最低,
  # O1-O3随着优化等级提高,预期编译后的模型的执行速度会更快,但是所需编译时间也会变长。
  # 推荐用O2做最快验证
  optimize_level: 'O3'

其中,ONNX 模型无需配置 model_parameters 参数组中的 caffe_modelprototxt 参数,而是替换为配置 onnx_model 参数。

input_parameters 参数组中的 input_type_rtinput_type_train 参数分别用于指定模型在板端实际部署时会接收到的数据类型 (如 nv12)和本身训练时的数据类型(如 rgb)。当两种数据类型不一致时,转换工具会自动在模型前端插入一个能 BPU 加速的预处理节点,以完成对应的颜色空间转换。 同时,该参数组中的 norm_typemean_valuescale_value 参数还能用于配置图片输入模型的数据归一化操作, 配置后转换工具也会将其集成进预处理节点实现 BPU 加速。数据归一化的计算公式为:

\(data\_norm = (data - mean\_value) * scale\_value\)

calibration_parameters 参数组中的 cal_data_dir 参数需要配置预处理好的校准数据文件夹路径, 预处理方式的说明请参考 校准数据预处理

3.2.3.2. 校准数据预处理

注意

  • 请注意,在进行此步之前,请确保您已经通过执行对应示例目录下的 00_init.sh 脚本完成了校准数据集的获取。

  • 如果当前只关注模型性能,那么可以将 yaml 文件中的 calibration_type 参数直接配置为 skip ,并跳过本小节, 工具会在模型转换时自动忽略 cal_data_dir 参数。

PTQ 方案的校准数据一般是从训练集或验证集中筛选 100 份左右(可适当增减)的典型数据,并应避免非常少见的异常样本, 如纯色图片、不含任何检测或分类目标的图片等。筛选出的校准数据还需进行与模型 inference 前一致的预处理操作, 处理后保持与原始模型一样的数据类型( input_type_train )、layout ( input_layout_train )和尺寸( input_shape )。

对于校准数据的预处理,地瓜机器人建议直接参考示例代码进行修改使用。以 MobileNet-v1 模型为例,preprocess.py 文件中 的 calibration_transformers 函数的包含了其校准数据的前处理 transformers,处理完的校准数据与其 yaml 配置文件保持一致,即:

  • input_type_train : ‘bgr’

  • input_layout_train :’NCHW’

def calibration_transformers():
    transformers = [
        ShortSideResizeTransformer(short_size=256),
        CenterCropTransformer(crop_size=224),
        HWC2CHWTransformer(),
        RGB2BGRTransformer(data_format="CHW"),
        ScaleTransformer(scale_value=255),
    ]
    return transformers

其中,transformers 都定义在 ../../../01_common/python/data/transformer.py 文件中,具体说明 请参考 图片处理 transformer 说明 ,您可以按需选用或者自定义修改及扩展。

注意

需要注意的是,如果已经在 yaml 文件中配置了 mean_valuescale_value 参数进行数据归一化来启用 BPU 加速,那么应避免在此处的 transformers 中重复操作。

修改完 preprocess.py 文件后,即可修改 02_preprocess.sh 脚本并执行,以完成校准数据的预处理。

bash 02_preprocess.sh

02_preprocess.sh 脚本文件的主要内容如下:

set -e -v
cd $(dirname $0) || exit

python3 ../../../data_preprocess.py \
  --src_dir ../../../01_common/calibration_data/imagenet \
  --dst_dir ./calibration_data_bgr \
  --pic_ext .bgr \
  --read_mode skimage \
  --saved_data_type float32

data_preprocess.py 文件的传参说明如下:

  • src_dir 为原始校准数据路径。

  • dst_dir 为处理后数据的存放路径,可自定义。

  • pic_ext 为处理后数据的文件后缀,主要用于帮助记忆数据类型,可不配置。

  • read_mode 为图片读取方式,可配置为 skimage 或 opencv。需要注意的是,skimage 读取的图片类型为 RGB, 数据范围为 0-1,而 opencv 读取的图片类型为 BGR,数据范围为 0-255。

  • saved_data_type 为处理后数据的保存类型。

如果您选择自行编写 python 代码实现校准数据预处理,那么可以使用 numpy.tofile 命令将其保存为 float32 格式的二进制文件, 工具链校准时会基于 numpy.fromfile 命令进行读取。

3.2.3.3. 转换模型

准备完校准数据和 yaml 配置文件后,即可一步命令完成模型解析、图优化、校准、量化、编译的全流程转换, 内部过程详解请参考 转换内部过程解读 章节。 以 MobileNet-v1 模型为例的模型转换参考命令如下:

hb_mapper makertbin --config mobilenet_config.yaml \
                    --model-type caffe

转换完成后,会在 yaml 文件配置的 working_dir 路径下保存各阶段流程产出的模型文件和编译器预估的 模型 BPU 部分的静态性能评估文件,详细说明请参考 转换产出物解读 章节。

|-- MOBILENET_subgraph_0.html        # 静态性能评估文件(可读性更好)
|-- MOBILENET_subgraph_0.json        # 静态性能评估文件
|-- mobilenetv1_224x224_nv12.bin     # 用于在地瓜机器人计算平台上加载运行的模型
|-- mobilenetv1_224x224_nv12_calibrated_model.onnx
|-- mobilenetv1_224x224_nv12_optimized_float_model.onnx
|-- mobilenetv1_224x224_nv12_original_float_model.onnx
`-- mobilenetv1_224x224_nv12_quantized_model.onnx

3.2.4. 性能快速验证

针对转换生成的 xxx.bin 模型文件,地瓜机器人既支持先在开发机端预估模型 BPU 部分的的静态性能, 也在板端提供给了无需任何代码开发的可执行工具快速评测动态性能,以下将分别进行介绍。 更详细的说明和性能调优建议请参考 模型性能分析与调优 章节。

3.2.4.1. 静态性能评估

转换模型 所述,模型成功转换后会在 working_dir 路径下生成包含模型静态性能预估的 html 和 json 文件,两者内容相同, 但 html 文件的可读性更好。以下为 MobileNet-v1 模型转换生成的 html 文件,其中:

  • Summary 选项卡提供了编译器预估的模型 BPU 部分性能(不包含 CPU 算子性能预估)。

../../../_images/summary_tab.png
  • Temporal Statistics 选项卡内则主要提供了模型一帧推理时间内的带宽占用情况。

../../../_images/temporal_statistics_tab.png
  • Layer Details 选项卡提供了每一层 BPU 算子的计算量、原始算子输出 shape、对齐后的算子输出 shape、计算耗时、数据搬运耗时的信息以及编译后 layer 活跃时间段(不代表该 layer 执行时间,通常为多个 layer 交替/并行执行)。

../../../_images/layer_details_tab.png

针对 xxx.bin 模型,地瓜机器人在开发机环境还提供了 hb_perf 工具 重新生成静态性能预估文件。其使用方式如下, 详细说明请参考 使用 hb_perf 工具估计性能 章节。

hb_perf xxx.bin

当模型的静态性能已经不符合预期时,请参考 模型性能优化 章节进行性能调优。

3.2.4.2. 动态性能评估

当模型的静态性能符合预期后,我们可以进一步上板实测模型的动态性能,其参考方式如下:

1.首先请确保已按照 环境部署 章节完成开发板环境部署。

2.将转换生成的 xxx.bin 模型拷贝至开发板 /userdata 文件夹下任意路径。

3.通过 hrt_model_exec perf 工具快捷评估模型的耗时和帧率。

# 将模型拷贝至开发板
scp model_output/mobilenetv1_224x224_nv12.bin root@{board_ip}:/userdata

# 登录开发板评测性能
ssh root@{board_ip}
cd /userdata

# 单BPU核单线程串行状态下评测latency
hrt_model_exec perf --model_file mobilenetv1_224x224_nv12.bin --thread_num 1 --frame_count 1000

# 双BPU核多线程并发状态下评测FPS
hrt_model_exec perf --model_file mobilenetv1_224x224_nv12.bin --core_id 0 --thread_num 8 --frame_count 1000

hrt_model_exec 工具的主要参数说明如下,更多说明请参考 hrt_model_exec 工具介绍 章节。

注解

  • 如果您在板端无法找到 hrt_model_exec 工具,可以再执行一次 OE 包中 ddk/package/board 路径下的 install.sh 脚本。

  • 评测 Latency 时一般采用单线程串行的推理方式,可以指定 thread_num 为 1。

  • 评测 FPS 时一般采用多线程并发的推理方式来占满 BPU 资源,此时可以配置 core_id 为 0,并配置 thread_num 为多线程。

  • 如果您配置了 profile_path 参数,程序需要正常运行结束才会生成 profiler.logprofiler.csv 日志文件,请勿使用 Ctrl+C 命令中断程序。

当模型的动态性能不符合预期时,请参考 模型性能优化 章节进行性能调优。

3.2.5. 精度验证

当模型的性能验证符合预期后,即可进行后续的精度验证。请首先确保您已经准备好相关的评测数据集,并挂载在 Docker 容器中。 示例模型使用的数据集可以从以下链接获取:

如果您在数据准备过程中有遇到问题,可以前往 地瓜机器人开发者社区 发帖进行求助。

转换模型 所述,模型转换会生成 xxx_quantized_model.onnxxxx.bin 两个量化模型,两者输出是保持数值一致的。 您也可以在开发机环境使用 hb_verifier 工具进行一致性验证,参考命令如下, 详细说明请参考 hb_verifier 工具 章节。

hb_verifier -m quanti.onnx,model.bin -b *.*.*.* -s True (-i 选填)

hb_verifier 工具的参数说明如下:

相比于 xxx.bin ,地瓜机器人更建议优先在开发机 Python 环境评测 xxx_quantized_model.onnx 模型的量化精度,其评测方式更加简单快捷, 具体请见 开发机 Python 环境验证xxx.bin 在板端基于 C++代码的评测说明请见 开发板 C++环境验证 , 更详细的精度验证和优化建议请参考 模型精度分析与调优 章节。

3.2.5.1. 开发机 Python 环境验证

以 MobileNet-v1 模型为例,mobilenetv1_224x224_nv12_quantized_model.onnx 量化模型的单张推理和验证集精度评测示例请参考 示例目录中的 04_inference.sh05_evaluate.sh 脚本,参考命令如下:

# 测试量化模型单张图片推理结果
bash 04_inference.sh

# 测试浮点模型单张图片推理结果(可选)
bash 04_inference.sh origin

# 测试量化模型精度,请确保您的评测数据集已正确挂载在Docker容器中
bash 05_evaluate.sh

# 测试浮点模型精度(可选)
bash 05_evaluate.sh origin

两个脚本会分别调用 ../../cls_inference.py../../cls_evaluate.py 文件进行推理, 以 cls_inference.py 文件为例,代码中的主要接口使用逻辑如下:

from horizon_tc_ui import HB_ONNXRuntime
from preprocess import infer_image_preprocess
from postprocess import postprocess

def inference(sess, image_name, input_layout):
  if input_layout is None:
        input_layout = sess.layout[0]
    # 前处理
    image_data = infer_image_preprocess(image_name, input_layout)
    input_name = sess.input_names[0]
    output_names = sess.output_names
    # 模型推理
    output = sess.run(output_names, {input_name: image_data})
    # 后处理
    top_five_label_probs = postprocess(output)

def main(model, image, input_layout):
    sess = HB_ONNXRuntime(model_file=model)
    sess.set_dim_param(0, 0, '?')
    inference(sess, image, input_layout)

if __name__ == '__main__':
    main()

其中,infer_image_preprocess 函数的前处理操作来源于 校准数据预处理 章节 所述 preprocess.py 文件,相比于 calibration_transformers 函数会额外增加 input_type_rtinput_type_train (参数说明请见 Yaml 配置文件 章节)颜色空间的转换来对齐模型实际部署时的输入数据类型,具体代码如下:

def infer_transformers(input_layout="NHWC"):
    transformers = [
        ShortSideResizeTransformer(short_size=256),
        CenterCropTransformer(crop_size=224),
        RGB2BGRTransformer(data_format="HWC"),
        ScaleTransformer(scale_value=255),
        BGR2NV12Transformer(data_format="HWC"),
        NV12ToYUV444Transformer((224, 224),
                                yuv444_output_layout=input_layout[1:]),
    ]
    return transformers

def infer_image_preprocess(image_file, input_layout):
    transformers = infer_transformers(input_layout)
    image = SingleImageDataLoader(transformers,
                                  image_file,
                                  imread_mode='skimage')
    return image

需要注意的是, xxx.bin 模型对于 input_type_rtinput_type_train 颜色空间的转换会配合处理器硬件完成。 而模型转换生成的几个 ONNX 模型前端插入的预处理节点不包含硬件转换逻辑,所以其实际输入只是一种中间类型,对应硬件 对 input_type_rt 类型的处理结果。下表为每种 input_type_rt 数据类型对应的中间类型。 以 MobileNet-v1 模型为例,其 input_type_rt 配置为 nv12,此处 transformers 中就会从 BGR 处理成 NV12, 再处理成 YUV444。

input_type_rt

nv12

yuv444

rgb

bgr

gray

featuremap

中间类型

yuv444_128

yuv444_128

RGB_128

BGR_128

GRAY_128

featuremap

注解

_128 表示数据会减去 128,由 uint8 类型转换为 int8 类型。在不涉及数据损失的转换场景下,该转换可通过 HB_ONNXRuntime 内部完成, 如涉及混合类型输入等会出现数据损失的转换,需先自行完成对应数据转换的处理,再进行推理。

3.2.5.2. 开发板 C++环境验证

在开发板端,地瓜机器人也提供了一套适配所有硬件平台的嵌入式端预测库 LibDNN,来帮助用户快速完成模型的部署工作, 并提供了相关示例。您可以首先参考 模型部署 章节学习模型部署和 BPU SDK API 接口的基础使用, 再参考 AI-Benchmark 章节学习示例模型精度评测的完整代码框架。

3.2.5.2.1. 模型部署

OE 包提供了模型部署的基础示例,以便于用户学习 LibDNN 预测库 API 接口的使用方式, 示例的详细说明可以参考 基础示例包使用说明 章节。

注意

请注意,在您进行模型部署前,需要先获取上板使用的模型:

  • ddk/samples/ai_toolchain/model_zoo/runtime/ai_benchmark 目录下, 执行 resolve_ai_benchmark_ptq.sh

  • ddk/samples/ai_toolchain/model_zoo/runtime/horizon_runtime_sample 目录下, 执行 resolve_runtime_sample.sh

其中,示例目录下的 code/00_quick_start/src/run_mobileNetV1_224x224.cc 文件提供了 MobileNet-v1 模型 从 DDR 读取数据,到模型推理,再执行后处理出分类结果的完整流程代码。

run_mobileNetV1_224x224.cc 中的主要代码逻辑包括以下 6 个步骤,代码中所涉及的 API 接口的具体说明 可以参考 BPU SDK API 手册 章节。

1.加载模型,获取模型句柄。

2.准备模型输入输出 tensor,申请对应的 BPU 内存空间。

3.读取模型输入数据,并放入申请好的输入 tensor 中。

4.推理模型,获取模型输出。

5.基于输出 tensor 中的数据实现模型后处理。

6.释放相关资源。

int main(int argc, char **argv) {

  // Step1: get model handle
  {
    hbDNNInitializeFromFiles(&packed_dnn_handle, &modelFileName, 1);
    hbDNNGetModelNameList(&model_name_list, &model_count, packed_dnn_handle);
    hbDNNGetModelHandle(&dnn_handle, packed_dnn_handle, model_name_list[0]);
  }

  // Step2: prepare input and output tensor
  std::vector<hbDNNTensor> input_tensors;
  std::vector<hbDNNTensor> output_tensors;
  int input_count = 0;
  int output_count = 0;
  {
    hbDNNGetInputCount(&input_count, dnn_handle);
    hbDNNGetOutputCount(&output_count, dnn_handle);
    input_tensors.resize(input_count);
    output_tensors.resize(output_count);
    prepare_tensor(input_tensors.data(), output_tensors.data(), dnn_handle);
  }

  // Step3: set input data to input tensor
  {
    // read a single picture for input_tensor[0], for multi_input model, you
    // should set other input data according to model input properties.
    read_image_2_tensor_as_nv12(FLAGS_image_file, input_tensors.data());
  }

  // Step4: run inference
  {
    // make sure memory data is flushed to DDR before inference
    for (int i = 0; i < input_count; i++) {
      hbSysFlushMem(&input_tensors[i].sysMem[0], HB_SYS_MEM_CACHE_CLEAN);
    }

    hbDNNInferCtrlParam infer_ctrl_param;
    HB_DNN_INITIALIZE_INFER_CTRL_PARAM(&infer_ctrl_param);
    hbDNNInfer(&task_handle,
               &output,
               input_tensors.data(),
               dnn_handle,
               &infer_ctrl_param);
    // wait task done
    hbDNNWaitTaskDone(task_handle, 0);
  }

  // Step5: do postprocess with output data
  std::vector<Classification> top_k_cls;
  {
    // make sure CPU read data from DDR before using output tensor data
    for (int i = 0; i < output_count; i++) {
      hbSysFlushMem(&output_tensors[i].sysMem[0], HB_SYS_MEM_CACHE_INVALIDATE);
    }

    get_topk_result(output, top_k_cls, FLAGS_top_k);
    for (int i = 0; i < FLAGS_top_k; i++) {
      VLOG(EXAMPLE_REPORT) << "TOP " << i << " result id: " << top_k_cls[i].id;
    }
  }

  // Step6: release resources
  {
    // release task handle
    hbDNNReleaseTask(task_handle);
    // free input mem
    for (int i = 0; i < input_count; i++) {
      hbSysFreeMem(&(input_tensors[i].sysMem[0]));
    }
    // free output mem
    for (int i = 0; i < output_count; i++) {
      hbSysFreeMem(&(output_tensors[i].sysMem[0]));
    }
    // release model
    hbDNNRelease(packed_dnn_handle);
  }

  return 0;
}

该示例运行的参考方式如下:

# 开发机环境执行交叉编译,生成可执行程序
cd open_explorer/ddk/samples/ai_toolchain/horizon_runtime_sample/code
bash build_xj3.sh

# 拷贝xj3目录至板端
mkdir ..xj3/runtime
scp -r ../xj3/ root@{board_ip}:/userdata
# 拷贝模型文件至板端
scp -r ../../model_zoo/runtime/horizon_runtime_sample/mobilenetv1/ root@{board_ip}:/userdata/xj3/model/runtime

# 登录开发板环境
ssh root@{board_ip}
# 进入xj3/script/目录下,执行相应运行脚本即可
cd /userdata/xj3/script/00_quick_start/
bash run_mobilenetV1.sh

3.2.5.2.2. AI-Benchmark

OE 包在 ddk/samples/ai_benchmark 路径下还提供了典型分类、检测、分割、光流示例模型板端性能和精度评测的示例包,您可以基于这些示例进行进一步的应用开发。 更多说明您可参考 AI-Benchmark 使用说明 章节。

3.2.6. 应用开发

当模型的性能和精度验证都符合预期后,即可参考 嵌入式应用开发指导 章节实现上层应用的具体开发。