150|0

55

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

RDK X3测评:3.模型推理 [复制链接]

本帖最后由 waterman 于 2025-1-28 23:53 编辑

本节将基于RDK Python 语言的hobot_dnn模型推理库,完成静态图片推理学习,包括模型加载、数据预处理、模型推理、算法结果后处理等操作。hobot_dnn推理库主要使用的类和接口如下:

  • Model : 算法模型类,执行加载算法模型、推理计算。

  • pyDNNTensor:算法数据输入、输出数据 tensor 类。

  • TensorProperties :模型输入 tensor 的属性类。

  • load:加载算法模型。

模型推理流程

开发板Ubuntu系统预装了Python版本的pyeasy_dnn模型推理模块,通过加载模型并创建Model对象,完成模型推理、数据解析等功能。

模型加载

from hobot_dnn import pyeasy_dnn as dnn

#create model object
models = dnn.load('./model.bin')

图像推理

#do inference with image
outputs = models[0].forward(image)

数据解析

for item in outputs:
    output_array.append(item.buffer)
post_process(output_array)
其中在图像推理部分,我们需要输入待处理的图像,但这个图像的大小我们应该如何查看呢,可以使用Model.inputs进行查看。以yolov5s_672x672_nv12.bin为例,在app/pydev_demo目录下运行如下代码,查看模型的tensor输入信息。
from hobot_dnn import pyeasy_dnn as dnn

def print_properties(pro):
    print("tensor type:", pro.tensor_type)
    print("data type:", pro.dtype)
    print("layout:", pro.layout)
    print("shape:", pro.shape)

models = dnn.load('./models/yolov5s_672x672_nv12.bin')
input = models[0].inputs[0]

print_properties(input.properties)

输出结果如下:

其中NV12指的是图像格式,属于 YUV 颜色空间中的 YUV420SP 格式,每四个 Y 分量共用一组 U 分量和 V 分量,Y 连续存放,U 与 V 交叉存放。数据类型为uint8,数据格式为NCHW,既Batch*Channel*Height*Width,输入的形状为1*3*672*672。

此外,我们还能使用Model.outputs来查看模型的输出数据属性,具体代码如下:

from hobot_dnn import pyeasy_dnn as dnn

def print_properties(pro):
    print("tensor type:", pro.tensor_type)
    print("data type:", pro.dtype)
    print("layout:", pro.layout)
    print("shape:", pro.shape)

models = dnn.load('./models/yolov5s_672x672_nv12.bin')
output = models[0].outputs[0]

print_properties(output.properties)

输出结果如下图所示:

其中与输入有所不同,数据类型为float32,数据格式为NHWC,既Batch*Height*Width*Channel,输出的形状为1*84*84*255。

下面我们就以yolov5s_672x672_nv12模型为例,进行静态图片推理的实现。

静态图片推理

  1. 首先导入相关的库

import numpy as np
import cv2
from hobot_dnn import pyeasy_dnn as dnn
import time
import ctypes
import json 

其中,time用于测量代码执行时间,ctypes提供了Python与C语言动态链接库交互的桥梁,json用于解析JSON格式的数据。

  1. 加载并配置后处理库

libpostprocess = ctypes.CDLL('/usr/lib/libpostprocess.so') 

get_Postprocess_result = libpostprocess.Yolov5PostProcess
get_Postprocess_result.argtypes = [ctypes.POINTER(Yolov5PostProcessInfo_t)]  
get_Postprocess_result.restype = ctypes.c_char_p  

其中libpostprocess.so是官方提供的一个后处理动态库,其中包含了对Yolov5模型输出结果的后处理,需要使用ctypes调用。

  1. 读取模型并打印输入输出张量属性

models = dnn.load('../models/yolov5s_672x672_nv12.bin')
# 打印输入 tensor 的属性
print_properties(models[0].inputs[0].properties)
# 打印输出 tensor 的属性
print(len(models[0].outputs))
for output in models[0].outputs:
    print_properties(output.properties)
  1. 图像读取与预处理

img_file = cv2.imread('./kite.jpg')
h, w = get_hw(models[0].inputs[0].properties)
des_dim = (w, h)
resized_data = cv2.resize(img_file, des_dim, interpolation=cv2.INTER_AREA)
nv12_data = bgr2nv12_opencv(resized_data)

这里使用kite.jpg图片进行推理,但是由于图片与模型的输出可能不同,因此需要调用cv2.resize对图像进行放缩,并且需要将图片格式转换为我们在上面看到的nv12的格式。

  1. 模型推理

t0 = time.time()
outputs = models[0].forward(nv12_data)
t1 = time.time()
  1. 数据后处理

yolov5_postprocess_info = Yolov5PostProcessInfo_t()
yolov5_postprocess_info.height = h
yolov5_postprocess_info.width = w
org_height, org_width = img_file.shape[0:2]
yolov5_postprocess_info.ori_height = org_height
yolov5_postprocess_info.ori_width = org_width
yolov5_postprocess_info.score_threshold = 0.4 
yolov5_postprocess_info.nms_threshold = 0.45
yolov5_postprocess_info.nms_top_k = 20
yolov5_postprocess_info.is_pad_resize = 0

output_tensors = (hbDNNTensor_t * len(models[0].outputs))()
for i in range(len(models[0].outputs)):
    output_tensors[i].properties.tensorLayout = get_TensorLayout(outputs[i].properties.layout)
    if (len(outputs[i].properties.scale_data) == 0):
        output_tensors[i].properties.quantiType = 0
        output_tensors[i].sysMem[0].virAddr = ctypes.cast(outputs[i].buffer.ctypes.data_as(ctypes.POINTER(ctypes.c_float)), ctypes.c_void_p)
    else:
        output_tensors[i].properties.quantiType = 2       
        output_tensors[i].properties.scale.scaleData = outputs[i].properties.scale_data.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
        output_tensors[i].sysMem[0].virAddr = ctypes.cast(outputs[i].buffer.ctypes.data_as(ctypes.POINTER(ctypes.c_int32)), ctypes.c_void_p)
        
    for j in range(len(outputs[i].properties.shape)):
        output_tensors[i].properties.validShape.dimensionSize[j] = outputs[i].properties.shape[j]
    
    libpostprocess.Yolov5doProcess(output_tensors[i], ctypes.pointer(yolov5_postprocess_info), i)

result_str = get_Postprocess_result(ctypes.pointer(yolov5_postprocess_info))  
result_str = result_str.decode('utf-8')  

这里进行YOLOv5模型的后处理信息,并调用外部C库进行后处理操作。首先创建一个Yolov5PostProcessInfo_t实例,该结构体包含后处理所需的各种参数。之后对每个输出张量调用Yolov5doProcess函数进行处理,得到字符串格式的输出。

  1. 结果解析并绘制边界框

data = json.loads(result_str[16:])  

for result in data:  
    bbox = result['bbox']  # 矩形框位置信息  
    score = result['score']  # 得分  
    id = result['id']  # id  
    name = result['name']  # 类别名称  
    
    cv2.rectangle(img_file, (int(bbox[0]), int(bbox[1])), (int(bbox[2]), int(bbox[3])), (0, 255, 0), 2)    
    font = cv2.FONT_HERSHEY_SIMPLEX  
    cv2.putText(img_file, f'{name} {score:.2f}', (int(bbox[0]), int(bbox[1]) - 10), font, 0.5, (0, 255, 0), 1)  
  
cv2.imwrite('output_image.jpg', img_file)

最后对字符串进行解析,获取图像中的目标检测结果并绘制到图片并输出。得到结果如下:

 

点赞 关注

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表