征程6工具链模型X86推理方式说明

J6工具链模型X86推理方式说明

X86 推理是指 开发机(X86 CPU/GPU)上针对不同阶段的模型:ONNX模型、Hbir模型和hbm模型,进行相应的推理验证。绝大多数的推理验证不需要实际开发板,但是使用hbm_infer需要"board_ip"来连续开发板。以下是工具链常见的几种推理方式说明。

ONNX模型

HBRuntime推理库

HBRuntime是地平线提供的一套x86端模型推理库,支持PTQ链路各阶段产出的ONNX模型进行推理,并通过dict的数据格式传入推理接口中。

使用流程详见如下链:HBRuntime推理库

使用示例如下:

Python 复制代码
import numpy as np
# 加载地平线依赖库
from horizon_tc_ui.hb_runtime import HBRuntime

# 准备模型运行的输入,此处`input.npy`为处理好的数据
data = np.load("input.npy")    
# 加载模型文件,根据实际模型进行设置
# ONNX模型
sess = HBRuntime("model.onnx")

# 获取输入&输出节点名称
input_names = sess.input_names
output_names = sess.output_names

# 准备输入数据,根据实际输入类型和layout进行准备,配置格式要求为字典形式,输入名称和输入数据组成键值对
# 如模型仅有一个输入
input_feed = {input_names[0]: data}  # 直接获取字符串列表
# 如模型有多个输入
input_feed = {input_names[0]: data1, input_names[1]: data2}
# 进行模型推理,推理的返回值是一个list,依次与output_names指定名称一一对应
output = sess.run(output_names, input_feed)

ORTExecutor

ORTExecutor 是 HMCT(Horizon Model Convert Toolkit)提供的 ONNX 模型推理封装接口,底层基于onnxruntime。

Python 复制代码
import numpy as np
import onnx
from hmct.api import ORTExecutor

# 1. 加载 ONNX 模型
onnx_model = onnx.load("model.onnx")          # 需要 onnx.ModelProto 对象

# 2. 创建 ORTExecutor
executor = ORTExecutor(onnx_model)

# 3. 创建 Session
session = executor.create_session()

# 4. 获取输入输出信息
inputs = executor.get_inputs()                 # list[NodeArg]
outputs = executor.get_outputs()               # list[NodeArg]

# 5. 推理(返回 Dict[str, np.ndarray])
input_feed = {inputs[0].name: data)}           # 通过 NodeArg.name 获取
result = executor.inference(input_feed)        # Dict: {output_name: ndarray}

Hbir 模型 (.bc)

编译器feed接口

feed() 是 hbdk4.compiler 中 Function 对象的方法,用于对 hbir(即.bc 模型)进行推理。

接口信息详见:模型推理使用示例

需要注意的是feed()只接受 np.ndarray 和 torch.Tensor 两种 Python 对象类型。.npy的输入数据不能直接传给该接口,需要先 np.load() 加载成 np.ndarray。该接口所需要的输入格式和输出格式一致,均包装成字典。使用示例如下:

Python 复制代码
import numpy as np
from hbdk4.compiler import load

# 加载 BC 模型
model = load("model.bc")
fn = model.functions[0]

# 查看输入输出信息
for i in fn.flatten_inputs:
    print(f"输入: {i.name}, shape={i.type.shape}, dtype={i.type.torch_dtype}")
for o in fn.flatten_outputs:
    print(f"输出: {o.name}, shape={o.type.shape}, dtype={o.type.torch_dtype}")

# 从 npy 文件加载输入数据
input_data = np.load("input.npy")

# 准备输入并推理
output = fn.feed({fn.flatten_inputs[0].name: input_data})

# output 是 Dict[str, np.ndarray]
print(output[fn.flatten_outputs[0].name].shape)

HBRuntime推理库

HBRuntime是地平线提供的一套x86端模型推理库,支持对转换过程中产出的HBIRbc模型进行推理,并通过dict的数据格式传入推理接口中。

使用流程详见如下链:HBRuntime推理库

推理的原理是基于hbdk4 的 load() + function.feed()。因此需要注意hbdk的版本是否匹配。使用示例如下:

Python 复制代码
import numpy as np
# 加载地平线依赖库
from horizon_tc_ui.hb_runtime import HBRuntime

# 准备模型运行的输入,此处`input.npy`为处理好的数据
data = np.load("input.npy")    
# 加载模型文件,根据实际模型进行设置
# HBIR模型
sess = HBRuntime("model.bc")

# 获取输入&输出节点名称
input_names = sess.input_names
output_names = sess.output_names

# 准备输入数据,根据实际输入类型和layout进行准备,配置格式要求为字典形式,输入名称和输入数据组成键值对
# 如模型仅有一个输入
input_feed = {input_names[0]: data}
# 如模型有多个输入
input_feed = {input_names[0]: data1, input_names[1]: data2}
# 进行模型推理,推理的返回值是一个list,依次与output_names指定名称一一对应
output = sess.run(output_names, input_feed)

hrt_model_exec

使用 X86 版本的 hrt_model_exec 工具进行模型信息查看和单帧推理,支持推理 quantized.bc 模型及 hbm 模型,相同quantized.bc编译的hbm,可以使用相同输入文件进行推理。

hrt_model_exec详细介绍与使用示例请参考 hrt_model_exec工具介绍

该工具推理功能支持多输入模型的推理,支持图片输入、二进制文件输入、文本文件输入及NumPy数组文件输入,输入数据用逗号隔开。 模型的输入信息可以通过 model_info 进行查看。

hrt_model_exec工具模型输入说明详见:模型输入说明章节。

X86 仿真环境使用 hrt_model_exec 工具推理 quantized.bc,但需要 hbdk4相关的库 和 hrt_model_exec(UCP)的版本要匹配,如:UCP 3.14.7 配套 HBDK 4.9.7。

需要注意的是,板端的hrt_model_exec不支持推理quantized.bc。

Python 复制代码
# 1、不加 dump(只跑推理,看时间)
# --frame_count 1 只跑一帧 default为200
hrt_model_exec infer --model_file simple_quantized_model.bc --input_file input.npy --frame_count 1

# 2、加 dump(需要验证一致性的时候,额外保存输入输出文件)
hrt_model_exec infer \
    --model_file simple_quantized_model.bc \
    --input_file input.npy \
    --frame_count 1 \
    --enable_dump true \
    --dump_path /tmp/output_dir
 
 # 3、该工具还支持:反量化输出和去除 Padding
 hrt_model_exec infer \
    --model_file model.bc \
    --input_file input.npy \
    --frame_count 1 \
    --enable_dump true \
    --dequantize_process true \
    --remove_padding_process true   

该命令还有以下两个关键的参数配置:

  • --dump_format来控制模型的输出格式,默认为bin的输出。
  • --dump_precision控制txt 格式时的小数精度,默认 9 位。

其他参数配置详见:参数说明章节。

UCP推理库(C++)

注意:X86 上推理hbm是指令级仿真,速度非常慢。推荐推理 quantized.bc,定点部分和 hbm 二进制一致。

使用 UCP 推理接口进行验证代码的开发,支持推理 quantized.bc 模型及 hbm 模型。UCP 仿真库接口与嵌入式接口完全一致,只是采用了不同的编译配置。

X86 仿真环境使用 UCP 推理接口推理 hbm 模型前,需要设置 HB_UCP_SIM_PLATFORM_TYPE 环境变量用以指定要模拟的 BPU 架构。

Python 复制代码
板端链接:deps_aarch64/ucp/lib/libhbucp.so
X86链接: deps_x86/ucp/lib/libhbucp.so        ← 换这个

# 1. 设置仿真平台类型(必需,否则不知道仿真哪个架构)
export HB_UCP_SIM_PLATFORM_TYPE=nash-e   # J6E
# export HB_UCP_SIM_PLATFORM_TYPE=nash-m # J6M

UCP 推理接口使用示例请参考 模型推理应用开发指导 章节。

hbm 模型

注意:X86 上推理hbm是指令级仿真,速度非常慢。推荐推理 quantized.bc,定点部分和 hbm 二进制一致。因此只建议使用3.1节的方式进行推理。其他方法仅做示例补充,了解即可。

hbm_infer

hbm_infer是一个X86+板端联合通信模式的Validation工具,在X86端使用Python代码做模型前后处理工作,由板端Server执行实际推理过程,用于提升模型精度评测效率,降低开发成本。和其他的python推理接口一样传入的数据形状只需要和模型的输入validShape 一致即可,不需要padding。

使用流程详见如下链接:hbm_infer工具

用户只需传 host + local_hbm_path 即可一键完成 SSH部署 + 文件上传 + gRPC连接。使用demo如下:

Python 复制代码
import time
import torch
from hbm_infer.hbm_rpc_session import HbmRpcSession

def run_hbm_infer(run_epoch=10):
    # 创建session
    sess = HbmRpcSession(
        host=<available_ip>,
        local_hbm_path=<local_hbm_path>
    )
    # 准备输入数据
    input_data = {
        'img': torch.ones((1, 3, 224, 224), dtype=torch.int8)
    }
    # 执行推理并返回结果
    for i in range(run_epoch):
        output_data = sess(input_data)
        print([output_data[k].shape for k in output_data])
    # 关闭server
    sess.close_server()

if __name__ == '__main__':
    run_hbm_infer()

使用该工具推理需要注意输入的合法性检查以及数据预处理相关操作:

  1. 合法检查:
    1. 名称检查:input dict 的 key 必须与 get_input_info() 返回的输入名称完全匹配。
    2. 类型检查:不显式做数据类型强制转换,需要用户保证 tensor_type与模型预期一致。
    3. shape 检查:需要用户确保 shape 与模型的 valid_shape 匹配,动态维度用 input_valid_shape 或 input_stride 指定。
  2. 数据预处理建议:
    1. 对于 NV12 等 Pyramid/Resizer 输入,hbm_infer 不会自动做颜色空间转换或归一化,用户需按 input_type_rt 准备好数据(如将 RGB 转为 Y/UV 分量的 NV12 格式)。
    2. 如果配置了 mean_value/scale_value,这些归一化由模型内部完成,用户不需要手动减均值除方差。

编译器feed接口(不推荐)

feed() 是 hbdk4.compiler 中 Function 对象的方法,用于对hbm模型进行推理。

接口信息详见:模型推理使用示例

具体使用方式和输入输出信息和见本文21节。针对该接口的输入的合法性检查以及数据预处理需注意:

  1. 合法检查(由 hbdk runtime 做):
    1. 数据类型校验:输入的 numpy dtype 必须与模型预期的 tensor_type 兼容。
    2. Shape 校验:静态维度必须完全匹配;动态维度同样需要满足 shape 约束,不匹配时会抛出异常。
    3. 数量校验:输入 tensor 的数量必须与模型定义一致。
    4. 没有隐式的布局转换(NCHW/NHWC),需要用户按模型预期准备。
  2. 数据预处理:同 hbm_infer的相关方式。

HBRuntime推理库(不推荐)

HBRuntime是地平线提供的一套x86端模型推理库,支持对地平线工具链转换过程中产出的HBM模型进行推理,并通过dict的数据格式传入推理接口中。HBRuntime是X86端推理库,你传入的数据形状只需要和模型的输入一致即可,不需要padding。

使用流程详见如下链:HBRuntime推理库

HB_HBMRuntime 底层会加载 hbdk4-runtime 的动态库,因此需要注意hbdk的版本是否匹配。使用示例如下:

Python 复制代码
import numpy as np
# 加载地平线依赖库
from horizon_tc_ui.hb_runtime import HBRuntime

# 准备模型运行的输入,此处`input.npy`为处理好的数据
data = np.load("input.npy")    
# 加载模型文件,根据实际模型进行设置
# HBM模型
sess = HBRuntime("model.hbm")
# 获取输入&输出节点名称
input_names = sess.input_names
output_names = sess.output_names

# 准备输入数据,根据实际输入类型和layout进行准备,配置格式要求为字典形式,输入名称和输入数据组成键值对
# 如模型仅有一个输入
input_feed = {input_names[0]: data}
# 如模型有多个输入
input_feed = {input_names[0]: data1, input_names[1]: data2}
# 进行模型推理,推理的返回值是一个list,依次与output_names指定名称一一对应
output = sess.run(output_names, input_feed)
  1. 合法检查:
    1. 输入 tensor 数量检查:feed dict 中提供的输入数量必须与模型输入数量一致。
    2. 输入名称匹配:feed 的 key 必须匹配模型注册的输入名称。
    3. 数据类型对齐:如果 feed 的数据类型与模型预期的 tensor_type 不匹配,runtime 会尝试隐式转换或报错。
    4. Shape 校验:静态 shape 必须完全匹配;动态 shape 需要满足 valid_shape 约束。
  2. 数据预处理:同 hbm_infer的相关方式。

hrt_model_exec(仅推荐模型信息查看)

hrt_model_exec使用方式和板端相同,但需要配置HB_UCP_SIM_PLATFORM_TYPE环境变量用以指定要模拟的 BPU 架构

具体可参考:hrt_model_exec infer使用示例

Python 复制代码
# 推理hbm需要设置仿真平台
export HB_UCP_SIM_PLATFORM_TYPE=nash-e   # J6E
# export HB_UCP_SIM_PLATFORM_TYPE=nash-m # J6M

推理接口的详细链接如下:模型推理

鉴于 hbm 在 X86 端推理速度较慢,因此只建议在 X86端查看model_info。

具体可参考:hrt_model_exec model_info使用示例

相关推荐
地平线开发者1 小时前
【征程6】校准量化中HistogramObserver解析
算法
OuO-22 小时前
笔试强训 Day 34:ISBN 号码、kotori 和迷宫、矩阵最长递增路径
java·算法·矩阵
程序喵大人3 小时前
【C++进阶】STL算法与函数对象 - 04 find、count和any_of把查询写成意图
开发语言·c++·算法
豆沙沙包?3 小时前
c++中引用(P7-P11)
java·c++·算法
不会代码的小猴3 小时前
标准模板库(STL)
开发语言·c++·笔记·算法
ZhouDevin3 小时前
算法论文/高效微调4——DoRA:权重分解的低秩适配方法
算法
AI探索先锋4 小时前
A* 路径规划:四种算法的进化史-学习
学习·算法
旖旎夜光4 小时前
LeetCode 202:快乐数(双指针问题) —— 题解
数据结构·c++·算法·leetcode·双指针
cpp_25015 小时前
P1113 [USACO02FEB] 杂务
数据结构·c++·算法·动态规划·图论·拓扑排序·洛谷题解