新闻详情

新闻详情

首页 / 资讯中心 / 详情

在RK3588上跑YOLOv5:从模型转换到NPU推理的部署实录

发布时间:2026/10/1 14:30:27来源:尧图网络
在RK3588上跑YOLOv5:从模型转换到NPU推理的部署实录
1. 为什么要在 RK3588 上折腾 YOLOv5 部署RK3588 这颗片子这两年出镜率很高8 核 CPU4×A76 4×A55、Mali-G610 GPU外加一颗标称 6 TOPS 的 NPU做边缘侧目标检测算是性价比不错的选择。YOLOv5 又是目标检测里落地最广的模型之一权重好找、结构清晰、社区资料多。把这两者凑到一起就是很多自研板卡项目绕不开的一步在 RK3588 上跑 YOLOv5实现本地化的目标检测推理。但真上手你会发现从 PyTorch 权重到板端 NPU 出检测框中间隔着好几道坎。PC 上torch.load一把梭的模型板子上根本不认直接拿 ONNX 丢给 NPU要么算子不支持要么精度掉得离谱量化参数没配对检测框全飘。我见过不少朋友卡在rknn_init报错或者输出张量对不上号最后只能退回 CPU 推理帧率惨不忍睹。这篇就按实际部署链路走一遍PyTorch 权重导出 ONNX、用 RKNN-Toolkit2 转成.rknn、量化校准、板端 NPU 推理验证单张图片和视频流两种输入都覆盖。目标很明确——你在自己的 RK3588 板卡上照着命令和配置能复现出检测框。适合做嵌入式 AI 落地、智能监控、机器人视觉的开发者也适合刚拿到板子想跑通第一个检测 demo 的人。需要说明的是模型转换和推理验证这类工作经常要在 PC 和板子之间来回切环境有时候还想顺手让大模型帮忙看看报错日志、改改后处理代码。我自己的习惯是本地终端配好一个稳定的模型调用入口遇到 RKNN 报错或者输出解析不对时直接把日志贴过去问省得翻半天文档。后面会提到怎么把这块接进工作流先聚焦部署本身。2. 部署前的环境准备与 TaoToken 接入配置2.1 PC 侧和板端的环境分工整个链路分两台机器一台 x86 PCUbuntu 20.04/22.04 都行负责模型导出和 RKNN 转换一块 RK3588 板卡负责推理。PC 侧需要 Python 3.8、PyTorch、ONNX以及 Rockchip 的 RKNN-Toolkit2板端需要 rknpu2 运行时和对应的 librknnrt.so。PC 侧装依赖conda create -n rknn python3.8 -y conda activate rknn pip install torch1.13.1 torchvision0.14.1 onnx1.14.0 onnxruntime1.16.0 pip install rknn-toolkit21.6.0RKNN-Toolkit2 的版本要和板端 rknpu2 驱动版本对齐1.6.0 对应 rknpu2 1.6.0版本错位是最常见的rknn_init失败原因之一。板端确认运行时cat /proc/rknpu/version # 输出类似RKNPU driver version: 0.9.6如果/proc/rknpu/version不存在说明 NPU 驱动没加载需要先刷对应固件。2.2 把模型调用入口配进工作流部署过程中真正耗时的往往不是写代码而是排查报错。比如 ONNX 导出后某个算子 RKNN 不支持、量化后 mAP 掉点、板端输出张量 shape 和预期对不上。这些场景下有个顺手的模型对话入口会快很多。我一般用 TaoToken 做这件事它的 API 兼容 OpenAI 格式PC 侧直接配环境变量就能调。先拿 Key打开 https://taotoken.net/api-keys 登录后创建一个 API Key复制出来。然后配置到终端export TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/api如果你用 Python 脚本调可以这样写一个最小验证import os from openai import OpenAI client OpenAI( api_keyos.environ[TAOTOKEN_API_KEY], base_urlos.environ[TAOTOKEN_BASE_URL], ) resp client.chat.completions.create( modelclaude-sonnet-4-20250514, messages[ {role: user, content: RKNN 转换时提示 Unsupport op: Resize怎么处理} ], ) print(resp.choices[0].message.content)模型 ID 按你实际要用的填TaoToken 支持多个主流模型具体列表在模型对话页能看到https://taotoken.net/models 。这样在转换脚本报错时把日志贴进去问比纯搜文档效率高。注意这只是辅助排查部署本身还是靠 RKNN 工具链。2.3 板端 rknpu2 运行时安装板端拉取 rknpu2 仓库编译安装运行时库git clone https://github.com/rockchip-linux/rknpu2.git cd rknpu2/runtime/RK3588/Linux/librknn_api sudo cp aarch64/librknnrt.so /usr/lib/ sudo ldconfigPython 侧还需要rknn_toolkit_lite2用于板端加载.rknn模型pip install rknn_toolkit_lite2-1.6.0-cp38-cp38-linux_aarch64.whl这个 whl 在 rknpu2 仓库的runtime/RK3588/Linux/librknn_api附近能找到版本务必和 PC 侧 Toolkit2 一致。3. YOLOv5 导出 ONNX 与 RKNN 转换可复制配置3.1 PyTorch 权重导出 ONNX假设你已经有一个训练好的best.pt或者直接用官方yolov5s.pt。先克隆 YOLOv5 源码建议用 v7.0 分支导出脚本稳定git clone -b v7.0 https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txt导出 ONNX注意--opset用 12RKNN 对 opset 12 支持最好python export.py \ --weights best.pt \ --img-size 640 640 \ --batch-size 1 \ --opset 12 \ --include onnx导出后会得到best.onnx。用 onnxruntime 快速验证一下输出import onnxruntime as ort import numpy as np sess ort.InferenceSession(best.onnx) inp np.random.randn(1, 3, 640, 640).astype(np.float32) outs sess.run(None, {sess.get_inputs()[0].name: inp}) for o in outs: print(o.shape) # 预期类似 (1, 25200, 85)如果输出 shape 是(1, 25200, 85)说明导出正常。25200 是三个尺度特征图拼接后的 anchor 数85 4 框 1 置信度 80 类。3.2 RKNN 转换配置与量化新建convert_rknn.py这是核心转换脚本from rknn.api import RKNN rknn RKNN(verboseTrue) # 配置均值方差、目标平台、量化算法 rknn.config( mean_values[[0, 0, 0]], std_values[[255, 255, 255]], target_platformrk3588, quantized_dtypeasymmetric_quantized-8, quantized_algorithmnormal, optimization_level3, ) # 加载 ONNX ret rknn.load_onnx(modelbest.onnx) assert ret 0, load_onnx failed # 构建指定量化校准数据集 ret rknn.build(do_quantizationTrue, datasetdataset.txt) assert ret 0, build failed # 导出 rknn ret rknn.export_rknn(best.rknn) assert ret 0, export failed rknn.release()dataset.txt是量化校准图片列表每行一个图片路径建议放 100~200 张有代表性的图./calib/0001.jpg ./calib/0002.jpg ./calib/0003.jpg量化参数说明用表格对照更清楚参数取值作用mean_values[[0,0,0]]输入均值YOLOv5 预处理是 /255所以均值填 0std_values[[255,255,255]]输入标准差对应 /255 归一化quantized_dtypeasymmetric_quantized-88bit 非对称量化精度和速度平衡quantized_algorithmnormal普通量化mmse 更准但慢optimization_level3最高优化等级会做算子融合注意mean/std 一定要和训练时的预处理对齐。YOLOv5 默认是img / 255所以这里 std 填 255、mean 填 0。填错会导致检测框全乱。转换成功后终端会打印各层量化信息重点看有没有Unsupport op警告。如果出现通常是某个算子 RKNN 不支持需要改 ONNX 图或者换 opset。3.3 板端加载与推理脚本板端新建infer_image.pyimport cv2 import numpy as np from rknnlite.api import RKNNLite CLASSES [person, car, dog] # 换成你自己的类别 def letterbox(img, new_shape640): shape img.shape[:2] r min(new_shape / shape[0], new_shape / shape[1]) new_unpad (int(round(shape[1] * r)), int(round(shape[0] * r))) dw, dh new_shape - new_unpad[0], new_shape - new_unpad[1] dw, dh dw // 2, dh // 2 img cv2.resize(img, new_unpad) img cv2.copyMakeBorder(img, dh, dh, dw, dw, cv2.BORDER_CONSTANT, value(114, 114, 114)) return img, r, (dw, dh) rknn RKNNLite() ret rknn.load_rknn(best.rknn) assert ret 0 ret rknn.init_runtime(core_maskRKNNLite.NPU_CORE_0) assert ret 0 img0 cv2.imread(test.jpg) img, ratio, (dw, dh) letterbox(img0) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img np.expand_dims(img, 0) outputs rknn.inference(inputs[img]) pred outputs[0][0] # (25200, 85) conf_thres 0.25 boxes [] for row in pred: obj_conf row[4] if obj_conf conf_thres: continue cls_scores row[5:] cls_id int(np.argmax(cls_scores)) score obj_conf * cls_scores[cls_id] if score conf_thres: continue cx, cy, w, h row[:4] x1 (cx - w / 2 - dw) / ratio y1 (cy - h / 2 - dh) / ratio x2 (cx w / 2 - dw) / ratio y2 (cy h / 2 - dh) / ratio boxes.append([x1, y1, x2, y2, score, cls_id]) for b in boxes: x1, y1, x2, y2, score, cls_id b cv2.rectangle(img0, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2) cv2.putText(img0, f{CLASSES[cls_id]}:{score:.2f}, (int(x1), int(y1) - 8), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imwrite(result.jpg, img0) rknn.release()这里没有加 NMS实际项目里要补上。简单版 NMSdef nms(boxes, iou_thres0.45): boxes sorted(boxes, keylambda x: x[4], reverseTrue) keep [] while boxes: best boxes.pop(0) keep.append(best) boxes [b for b in boxes if iou(best, b) iou_thres] return keep def iou(a, b): xx1 max(a[0], b[0]); yy1 max(a[1], b[1]) xx2 min(a[2], b[2]); yy2 min(a[3], b[3]) inter max(0, xx2 - xx1) * max(0, yy2 - yy1) area_a (a[2] - a[0]) * (a[3] - a[1]) area_b (b[2] - b[0]) * (b[3] - b[1]) return inter / (area_a area_b - inter 1e-6)4. 单图与视频流推理验证及成功结果4.1 单张图片验证板端执行python infer_image.py成功的话会生成result.jpg打开能看到检测框和类别标签。终端还会打印推理耗时RK3588 单核 NPU 跑 yolov5s 640×640大概在 25~40ms 一张具体看量化质量和板子散热。如果输出框位置明显偏移八成是 letterbox 的 padding 还原算错了重点检查dw/dh和ratio的除法顺序。4.2 视频流推理把上面的逻辑改成读摄像头或视频文件加个帧循环cap cv2.VideoCapture(0) # 或 test.mp4 while True: ret, frame cap.read() if not ret: break img, ratio, (dw, dh) letterbox(frame) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img np.expand_dims(img, 0) outputs rknn.inference(inputs[img]) # ... 解析 NMS 画框同上 cv2.imshow(rknn, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()实测 1080p 视频流NPU 推理 后处理 画框整体能跑到 20 FPS 以上。如果帧率掉得厉害先确认core_mask有没有开多核rknn.init_runtime(core_maskRKNNLite.NPU_CORE_0_1_2)RK3588 有 3 个 NPU 核心多核并行能明显提帧率但要注意模型是否支持多核调度。4.3 成功结果的判断标准跑通后你应该看到单图输出检测框位置和原图目标对齐类别标签正确置信度合理一般 0.5 以上视频流连续帧检测稳定没有大面积闪烁或框漂移。如果量化后精度掉太多可以换quantized_algorithmmmse重新转换或者增加校准集数量。5. 部署常见报错排查5.1 rknn_init 失败 / librknnrt 版本不匹配报错长这样E RKNN: rknn_init, load model failed! E RKNN: Invalid RKNN model version原因基本是 PC 侧 Toolkit2 版本和板端 rknpu2 运行时版本不一致。解决PC 侧pip show rknn-toolkit2看版本板端cat /proc/rknpu/version看驱动版本两者要对齐。比如 Toolkit2 1.6.0 配 rknpu2 1.6.0。版本对不上就重装对应 whl。5.2 Unsupport op 导致 build 失败E build: Unsupport op: ResizeRKNN 对某些 ONNX 算子支持有限。处理办法导出 ONNX 时换 opset或者用 onnx-simplifier 简化图pip install onnx-simplifier python -m onnxsim best.onnx best_sim.onnx简化后再转 RKNN很多 Resize/Slice 的兼容问题会消失。5.3 输出张量 shape 对不上 / reading choices 报错如果你用 OpenAI 兼容接口辅助排查偶尔会遇到reading choices这类解析报错通常是返回体不是标准结构。检查 base_url 是否写成了https://taotoken.net/api不要带多余路径以及 model ID 是否拼错。模型 ID 在 https://taotoken.net/models 能查到准确写法。5.4 检测框全飘 / 置信度异常量化后框飘优先查三件事mean/std 是否和训练预处理一致letterbox 的 padding 还原是否正确校准集是否覆盖了实际场景。我踩过的坑是校准集全用白天图结果夜间场景量化后几乎检测不到补了夜间样本才恢复。5.5 板端 import rknnlite 失败ModuleNotFoundError: No module named rknnlite说明rknn_toolkit_lite2没装或装错架构。确认装的是 aarch64 版本且 Python 版本匹配cp38 对应 Python 3.8。装完python -c from rknnlite.api import RKNNLite验证一下。6. 把部署流程沉淀成可复用工作流整套链路跑通后建议把转换脚本和推理脚本都参数化模型路径、类别、阈值、校准集路径都抽成配置换模型时不用改代码。RKNN 转换这块量化校准集的质量直接决定板端精度别图省事随便找几张图。另外部署过程中遇到算子不支持、精度掉点、后处理对不上号这些问题与其硬啃文档不如把报错日志和 ONNX 结构贴给模型问能省不少时间。我常用 TaoToken 的模型对话入口做这件事API 兼容 OpenAI 格式PC 侧配好TAOTOKEN_API_KEY和TAOTOKEN_BASE_URL就能直接调具体模型列表在 https://taotoken.net/models 看。如果是长期做嵌入式 AI 部署、经常要跑转换和排障可以考虑 Coding Plan把模型调用额度固定下来省得每次临时配https://taotoken.net/coding-plan 。最后一步板端跑通后记得测一下长时间运行的稳定性NPU 连续推理几小时看会不会掉帧或内存泄漏。这一步过了才算真正能在自研板卡上落地。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Spring Boot 集成 Jasypt:配置文件加密从入门到落地 2026/10/1 15:17:42

Spring Boot 集成 Jasypt:配置文件加密从入门到落地

1. 为什么你的配置文件里全是明文口令,还没人觉得有问题 我前几年接手过一个老项目,第一件事就是把 application-prod.yml 拉下来看,好家伙,MySQL 密码、Redis 密码、短信平台密钥、OSS 的 AccessKey,整整齐齐全是明…

阅读更多 →
Agent判断器选型与部署:Laya轻量推理与Jev复杂决策实战 2026/10/1 15:17:42

Agent判断器选型与部署:Laya轻量推理与Jev复杂决策实战

1. 为什么 Agent 需要一个“判断器”——以及 Laya、Jev 是怎么出现在视野里的这几个月我一直在折腾 Agent 类项目,从最基础的 tool calling 到多步任务编排都试了一圈。一个很深的感受是:Agent 框架本身已经不算稀罕物了,真正难的是让 Agent…

阅读更多 →
Redis核心实战:从安装部署到缓存穿透与分布式锁治理 2026/10/1 15:17:42

Redis核心实战:从安装部署到缓存穿透与分布式锁治理

1. 为什么是 Redis:先搞清楚缓存到底解决了什么问题 我见过太多人一上来就敲 redis-server ,把服务跑起来了,然后照着网上的教程 set key value ,再 get key ,最后对着终端发呆——然后呢?然后就没有…

阅读更多 →
OpenClaw智能体部署与Skill集成实战:8分钟跑通全流程 2026/10/1 15:17:42

OpenClaw智能体部署与Skill集成实战:8分钟跑通全流程

1. 部署之前,先把 OpenClaw 与 Clawdbot 的关系捋清楚1.1 一顿操作猛如虎,装完发现装错包先说结论:OpenClaw 和 Clawdbot 是同一个项目的两个“马甲”,只是不同发行阶段叫法不一样。早期版本在 GitHub 和 npm 上直接用clawdbot作为…

阅读更多 →
SpringBoot高并发异步编排:CompletableFuture与线程池实战指南 2026/10/1 15:17:42

SpringBoot高并发异步编排:CompletableFuture与线程池实战指南

做后端这几年,被高并发折磨得最厉害的往往不是数据库,而是那种“一个接口要串行调好几个服务”的场景。一个典型的 SpringBoot 项目里,订单详情要查订单、查库存、查优惠券、查用户,每个服务稳定 50ms,串起来就是 200m…

阅读更多 →
我花 3 天实测 Hermes Agent:这波热度值不值得跟?(附新手选型结论) 2026/10/1 15:17:36

我花 3 天实测 Hermes Agent:这波热度值不值得跟?(附新手选型结论)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉