目录
YOLOv8的RKNN模型
程序的部署
流量统计
本文首发于电子发烧友论坛:【新提醒】【HZHY-AI300G智能盒试用连载体验】+ 智能工业互联网网关 - 北京合众恒跃科技有限公司 - 电子技术论坛 - 广受欢迎的专业电子论坛! (elecfans.com)
环境准备好之后,接下来利用RK3588的NPU进行道路视频中的车辆识别,根据识别到的车辆的数量估计道路的流量情况,实现智慧交通中的流量监控功能。
YOLOv8的RKNN模型
我们使用YOLOv8框架进行目标的检测。YOLOv8(You Only Look Once version 8)是一个深度学习框架,用于实现实时对象检测。YOLOv8 继承了前代模型的优点,并在此基础上进行了多项改进,包括更复杂的网络架构、更优化的训练流程和更强大的特征提取能力。
厂商在其Github仓库中提供了大量已经优化和测试验证过的模型,其中就包括YOLOv8:
https://github.com/airockchip/rknn_model_zoo/blob/main/examples/yolov8/README.md。
厂商提供的模型是一个优化后的模型,与官方原始模型不同。以yolov8n.onnx为例来展示它们之间的差异。
1、它们输出信息的对比如下。左边是官方原始模型的输出,右边是优化后的模型输出。如图所示,原始模型的输出被分为三个部分。例如,在输出集合([1,64,80,80],[1,80,80,80],[1,1,80,80])中,[1,64,80,80]是边界框的坐标,[1,80,80,80]是对应于80个类别的边界框置信度,而[1,1,80,80]是80个类别置信度的总和。
请注意,这里的解释是基于常见目标检测模型(如YOLO系列)的输出格式,具体细节(如维度含义)可能因模型版本或实现而异。但一般来说,上述解释提供了关于YOLO类模型输出结构的通用理解。
2、以输出集合([1,64,80,80],[1,80,80,80],[1,1,80,80])为例,瑞芯微在模型中移除了两个卷积节点之后的子图,保留了这两个卷积的输出([1,64,80,80],[1,80,80,80]),并增加了一个reducesum+clip分支来计算80个类别置信度的总和([1,1,80,80])。
这里的“reducesum”操作通常用于对某个维度上的元素进行求和,而“clip”操作用于限制求和结果的取值范围,以避免数值溢出或保持数值在特定范围内。
这里提供的YOLOv8模型的训练方法和官方的完全相同,只是在导出的时候做了一些修改,有关导出 RKNPU 适配模型说明请见:https://github.com/airockchip/ultralytics_yolov8/blob/main/RKOPT_README.zh-CN.md。
程序的部署
YOLOv8程序在RK3588上的部署,我们参考了风筝2100的博文RK3588 npu python运行 YOLOv8 和 YOLOv8-seg 的教程_rk3588支持yolov9版 android-CSDN博客,在此表示感谢。
和RKNN_model_zoo 中的examples 提供的YOLOv8 的相关 demo对比,该程序有两点改进:
1)借助rknn-multi-threaded(https://github.com/leafqycc/rknn-multi-threaded)使用多线程推理提高NPU的占用率,参考:多线程异步提高RK3588的NPU占用率,进而提高yolov5s帧率_rk3588 多线程_rknn多线程-CSDN博客
2)优化了Python 后处理部分去除PyTorch 依赖,将后处理耗时从几百毫秒降低到了几十毫秒。
在 main.py 文件中,可以修改模型、线程数,还可以修改成实时推理摄像头。
# 推理视频文件cap = cv2.VideoCapture('./720p60hz.mp4')# 推理实时摄像头
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH,640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT,480)
程序启动后会显示RNKK的相关信息:
python3 main.pyI RKNN: [19:25:32.433] RKNN Runtime Information, librknnrt version: 2.0.0b0 (35a6907d79@2024-03-24T10:31:14)I RKNN: [19:25:32.433] RKNN Driver Information, version: 0.9.3I RKNN: [19:25:32.434] RKNN Model Information, version: 6, toolkit version: 1.6.0+81f21f4d(compiler version: 1.6.0 (585b3edcf@2023-12-11T07:42:56)), target: RKNPU v2, target platform: rk3588, framework name: ONNX, framework layout: NCHW, model inference type: static_shape./rknnModel/yolov8s.rknn doneI RKNN: [19:25:32.644] RKNN Runtime Information, librknnrt version: 2.0.0b0 (35a6907d79@2024-03-24T10:31:14)I RKNN: [19:25:32.644] RKNN Driver Information, version: 0.9.3I RKNN: [19:25:32.644] RKNN Model Information, version: 6, toolkit version: 1.6.0+81f21f4d(compiler version: 1.6.0 (585b3edcf@2023-12-11T07:42:56)), target: RKNPU v2, target platform: rk3588, framework name: ONNX, framework layout: NCHW, model inference type: static_shape./rknnModel/yolov8s.rknn doneI RKNN: [19:25:32.770] RKNN Runtime Information, librknnrt version: 2.0.0b0 (35a6907d79@2024-03-24T10:31:14)I RKNN: [19:25:32.770] RKNN Driver Information, version: 0.9.3I RKNN: [19:25:32.771] RKNN Model Information, version: 6, toolkit version: 1.6.0+81f21f4d(compiler version: 1.6.0 (585b3edcf@2023-12-11T07:42:56)), target: RKNPU v2, target platform: rk3588, framework name: ONNX, framework layout: NCHW, model inference type: static_shape./rknnModel/yolov8s.rknn done
流量统计
我们在每帧推理结束后,统计其中"car"、"motorbike "、 "bus"和"truck"对象的数量,作为流量统计的依据。
def myFunc(rknn_lite, IMG):IMG2 = cv2.cvtColor(IMG, cv2.COLOR_BGR2RGB)# 等比例缩放IMG2, ratio, padding = letterbox(IMG2)# 强制放缩# IMG2 = cv2.resize(IMG, (IMG_SIZE, IMG_SIZE))IMG2 = np.expand_dims(IMG2, 0)outputs = rknn_lite.inference(inputs=[IMG2],data_format=['nhwc'])#print("oups1",len(outputs))#print("oups2",outputs[0].shape)boxes, classes, scores = yolov8_post_process(outputs)global car_numglobal truck_numglobal motorbike_numglobal bus_numcar_num = 0truck_num = 0motorbike_num = 0bus_num = 0if classes is not None:for box, score, cl in zip(boxes, scores, classes):if CLASSES[cl] == 'car':car_num = car_num + 1elif CLASSES[cl] == 'motorbike':motorbike_num = motorbike_num + 1elif CLASSES[cl] == 'bus':bus_num = bus_num + 1elif CLASSES[cl] == 'truck':truck_num = truck_num + 1if boxes is not None:draw(IMG, boxes, scores, classes, ratio, padding)return IMG
我的程序已经可以在开发板上实时运行,并显示车辆检测结果。