核心结论
问题定位明确了:hb_verifier 和 hrt_model_exec 都通过,说明模型本身没问题,问题出在 Python pyeasy_dnn 的使用方式上。
关键差异:hrt_model_exec 使用了 --hybrid_dequantize_process=true 参数,但 Python 代码没有正确处理反量化和输入 offset。
问题原因
从你的 hb_verifier 日志看,模型是量化模型(quantized),但 Python 代码直接用 forward(x) 推理,存在两个关键问题:
- 缺少 input_offset 设置:featuremap 输入需要设置 offset=0
- 输出未反量化:bin 模型输出是 int8 定点数,需要反量化才能得到 float32 结果
解决方案
方案 1:使用 hb_session.run 接口(推荐)
import os
import numpy as np
from hobot_dnn import pyeasy_dnn as dnn
MODEL_PATH = "./stgcn_x5.bin"
INPUT_PATH = "/home/sunrise/Desktop/data/-_pn5NxJmok.bin"
DUMP_DIR = "./dump_manual"
INPUT_SHAPE = (1, 3, 32, 18)
def main():
os.makedirs(DUMP_DIR, exist_ok=True)
# 加载模型
models = dnn.load(MODEL_PATH)
model = models[0]
# 获取输入输出节点名称
input_names = [inp.name for inp in model.inputs]
output_names = [out.name for out in model.outputs]
print("input names:", input_names)
print("output names:", output_names)
# 加载输入数据
x = np.fromfile(INPUT_PATH, dtype=np.float32).reshape(INPUT_SHAPE)
x = np.ascontiguousarray(x, dtype=np.float32)
# 构造 feed_dict,使用节点名称
feed_dict = {input_names[0]: x}
# 关键:设置 input_offset=0(featuremap 模型)
# 使用 hb_session.run 接口
outputs = model.hb_session.run(
output_names,
feed_dict,
input_offset=0 # featuremap 必须设为 0
)
# 输出结果
for i, (name, out) in enumerate(zip(output_names, outputs)):
arr = np.array(out.buffer).reshape(out.shape)
print(f"output[{i}] {name} shape:", arr.shape, "dtype:", arr.dtype)
# 保存结果
txt_path = os.path.join(DUMP_DIR, f"python_output_{i}.txt")
np.savetxt(txt_path, arr.reshape(-1, 1), fmt="%.5f")
print("done")
if __name__ == "__main__":
main()
方案 2:检查是否需要手动反量化
如果方案 1 仍然不对,可能需要手动处理反量化:
# 在获取输出后,检查输出的 dtype 和 scale/zero_point
for i, out in enumerate(outputs):
arr = np.array(out.buffer)
print(f"output[{i}] dtype:", arr.dtype)
print(f"output[{i}] shape:", out.shape)
# 如果输出是 int8/uint8,需要反量化
if arr.dtype in [np.int8, np.uint8]:
# 获取量化参数(从模型属性或配置文件)
scale = out.properties.get('scale', 1.0)
zero_point = out.properties.get('zero_point', 0)
arr = (arr.astype(np.float32) - zero_point) * scale
# 保存
np.savetxt(os.path.join(DUMP_DIR, f"output_{i}.txt"),
arr.reshape(-1, 1), fmt="%.5f")
方案 3:使用 dnn.DNN 类并设置正确参数
from hobot_dnn import pyeasy_dnn as dnn
# 加载时设置配置
config = {
'input_offset': 0, # featuremap 模型
'output_dtype': 'float32', # 强制输出 float32
}
models = dnn.load(MODEL_PATH, config=config)
model = models[0]
# 推理
outputs = model.forward(x, input_offset=0)
关键排查点
1. 对比输入数据是否完全一致
# 在 Python 代码中添加
x = np.fromfile(INPUT_PATH, dtype=np.float32).reshape(INPUT_SHAPE)
np.savetxt("./python_input_check.txt", x.reshape(-1, 1), fmt="%.5f")
# 然后和 hrt_model_exec 生成的 dump 对比
# diff python_input_check.txt ./dump_manual/model_infer_input_0_input.txt
2. 检查输出 dtype
在 Python 代码中打印输出 dtype:
for i, out in enumerate(outputs):
arr = np.array(out.buffer)
print(f"output[{i}] dtype: {arr.dtype}") # 应该是 float32
print(f"output[{i}] shape: {out.shape}")
print(f"output[{i}] first 5 values: {arr.flatten()[:5]}")
如果 dtype 是 int8 或 uint8,说明输出没有反量化。
3. 检查节点名称匹配
# 打印所有输入输出节点名称
for inp in model.inputs:
print(f"input name: {inp.name}, shape: {inp.properties.shape}")
for out in model.outputs:
print(f"output name: {out.name}, shape: {out.properties.shape}")
确保 feed_dict 使用的名称和模型一致。
参考社区资源
搜索一下社区关于 pyeasy_dnn 的使用案例:
核心结论
问题已定位:pyeasy_dnn 对 featuremap 类型模型存在已知兼容性问题。
从你的测试结果看:
hb_verifier通过 → 模型量化/编译正确
hrt_model_exec通过 → C++ 接口推理正确
pyeasy_dnn异常 → Python 接口对 featuremap 模型支持不完善
这是社区已知的老问题,参考案例:板端 bin 文件推理输出和原模型输出差异过大
解决方案
方案 1:使用 C/C++ 编写推理代码(推荐)
这是官方推荐的 production-ready 方案。参考官方文档:Runtime 程序编写详解
核心代码框架:
#include "hobot/hb_media/hb_media.h"
#include "hobot/hb_dnn/hb_dnn.h"
#include <iostream>
#include <vector>
int main() {
// 1. 加载模型
hbDNNModel_t model;
hbDNNLoadModel(&model, "stgcn_x5.bin");
// 2. 创建推理实例
hbDNNHandle_t handle;
hbDNNCreateHandle(&handle, &model);
// 3. 准备输入数据 (featuremap 类型)
hbDNNInputTensor_t input;
input.dtype = HB_DNN_FLOAT32; // 关键:featuremap 用 float32
input.layout = HB_DNN_LAYOUT_NCHW;
input.shape = {1, 3, 32, 18};
input.data = malloc(1 * 3 * 32 * 18 * sizeof(float));
// 读取你的 bin 输入文件
FILE* f = fopen("/home/sunrise/Desktop/data/-_pn5NxJmok.bin", "rb");
fread(input.data, sizeof(float), 1*3*32*18, f);
fclose(f);
// 4. 推理
hbDNNTensor_t output;
hbDNNInferFeatureMap(handle, &input, &output); // 关键:用 hbDNNInferFeatureMap
// 5. 获取结果
float* result = (float*)output.data;
// 处理输出...
// 6. 释放资源
hbDNNReleaseHandle(handle);
hbDNNUnloadModel(&model);
return 0;
}
编译命令:
aarch64-linux-gnu-g++ -o infer infer.cpp \
-I${OE_PACKAGE_PATH}/include \
-L${OE_PACKAGE_PATH}/lib \
-lhbdnn -lhbmisc \
-Wl,-rpath,${OE_PACKAGE_PATH}/lib
方案 2:使用 HB_ONNXRuntime 推理 quantized.onnx(临时方案)
如果必须用 Python,可以绕过.bin 模型,直接推理量化后的 ONNX 文件:
from horizon_tc_ui import HB_ONNXRuntime
import numpy as np
# 加载 quantized.onnx(不是.bin)
sess = HB_ONNXRuntime(model_file="stgcn_x5_quantized.onnx")
# 准备输入
input_data = np.fromfile("/home/sunrise/Desktop/data/-_pn5NxJmok.bin", dtype=np.float32)
input_data = input_data.reshape(1, 3, 32, 18)
# 推理 - 关键:featuremap 模型用 run_feature,input_offset=0
output_names = sess.get_output_names()
outputs = sess.run_feature(output_names, {"input": input_data}, input_offset=0)
print(outputs[0])
注意:
- 此方案性能不如.bin 模型(无法充分利用 BPU 硬件加速)
- 仅适合调试/验证,不适合 production
方案 3:等待新 Python 接口发布
根据社区官方回复,新的 Python 接口已在开发中,将完整支持 featuremap 模型。可以关注社区公告。
验证步骤
-
先用方案 2 验证(最快):
python3 -c " from horizon_tc_ui import HB_ONNXRuntime import numpy as np sess = HB_ONNXRuntime(model_file='stgcn_x5_quantized.onnx') data = np.fromfile('/home/sunrise/Desktop/data/-_pn5NxJmok.bin', dtype=np.float32).reshape(1,3,32,18) out = sess.run_feature(sess.get_output_names(), {'input': data}, input_offset=0) print('top5:', np.argsort(out[0].flatten())[-5:][::-1]) print('logits:', out[0].flatten()[np.argsort(out[0].flatten())[-5:][::-1]]) "如果结果和
hrt_model_exec一致,确认是pyeasy_dnn的问题。 -
部署时切换到 C++ 方案(方案 1)
为什么 hb_verifier 通过但 pyeasy_dnn 失败?
hb_verifier 内部使用的是 C++ 推理接口(hbDNNInferFeatureMap),而 pyeasy_dnn 是 Python 封装层,对 featuremap 类型的输入/输出处理存在 bug(主要是数据 layout 和反量化逻辑)。
建议的下一步
- 立即用方案 2 验证,确认结果是否正常
- 如果正常:开发阶段继续用
HB_ONNXRuntime + quantized.onnx,部署时切换 C++ - 如果需要 C++ 帮助:可以提供你的具体应用场景,我帮你完善 C++ 代码框架
相关资源
- Runtime 程序编写详解
- 板端 bin 文件推理输出和原模型输出差异过大 - 相同问题案例
- 模型精度验证及调优建议 - 官方排查流程