纸翼 · 加载中
2438 words
12 minutes
RK3588 端侧 AI 部署(六):MobileNet、YOLO 与 RKLLM 实战
所属合集 RK3588 端侧 AI 部署 第 6 / 6 篇
  1. 1 RK3588 端侧 AI 部署(一):平台、NPU 与 RKNN 工具链
  2. 2 RK3588 端侧 AI 部署(二):主机与板端环境搭建
  3. 3 RK3588 端侧 AI 部署(三):ONNX 转 RKNN 与推理验证
  4. 4 RK3588 端侧 AI 部署(四):量化、评估与模型优化
  5. 5 RK3588 端侧 AI 部署(五):Lite2、C API 与零拷贝工程化
  6. 6 RK3588 端侧 AI 部署(六):MobileNet、YOLO 与 RKLLM 实战 正在阅读

RK3588 端侧 AI 部署(六):MobileNet、YOLO 与 RKLLM 实战#

最后一篇把前面的知识组合成项目路线:先用 MobileNet 验证基础 C API,再完成一个自定义 YOLO 安全帽检测项目,最后认识 RKLLM 大模型部署。

上一篇:Lite2、C API 与零拷贝工程化

一、为什么先做 MobileNet#

MobileNet 分类模型通常只有一个图像输入和一个分类输出,能把问题限制在:

读取 RKNN
→ 查询 Tensor
→ BGR/RGB、resize 和 layout
→ NPU 推理
→ 反量化/Softmax/Top-K

先通过官方 MobileNet Model Zoo 示例 验证环境和通用 C API,再进入 YOLO。分类模型都没跑对时,直接调多尺度检测后处理只会增加变量。

MobileNet 的验收标准:

  • Python、Lite2 和 C++ 的 Top-5 基本一致;
  • 输入 shape、RGB/BGR 和均值/标准差已明确;
  • C++ 能正确释放输出和 Context;
  • 已分别统计预处理、推理和后处理时间。

二、YOLO 部署比分类多了什么#

YOLO 的 RKNN 调用本身没有本质变化,难点集中在输出契约和后处理:

  • 多尺度输出;
  • 回归分支和分类分支;
  • INT8 输出反量化;
  • 置信度筛选;
  • 网格/stride 解码;
  • letterbox 坐标还原;
  • 按类别执行 NMS;
  • 类别数量和标签映射。

不同 YOLO 版本甚至同一版本的不同导出参数,输出数量、顺序和 shape 都可能不同。C++ 后处理必须针对实际 ONNX/RKNN 查询结果编写。

三、项目:安全帽检测从数据到板端#

第 1 步:定义业务指标#

安全帽项目不能只写“mAP 越高越好”。建议提前定义:

  • helmetno_helmet 两类;
  • no_helmet 漏检的容忍度;
  • 摄像头分辨率和距离范围;
  • 目标最小像素尺寸;
  • 期望 FPS 和最大告警延迟;
  • 白天/夜间、室内/室外和遮挡场景。

业务上未戴安全帽的漏检代价通常高于普通误报,因此要单独看该类别 Recall 和真实漏检案例。

第 2 步:采集和划分数据#

视频抽帧示例:

import cv2
from pathlib import Path
video = cv2.VideoCapture("source.mp4")
output = Path("frames")
output.mkdir(exist_ok=True)
index = 0
saved = 0
interval = 15
while True:
ok, frame = video.read()
if not ok:
break
if index % interval == 0:
cv2.imwrite(str(output / f"{saved:06d}.jpg"), frame)
saved += 1
index += 1
video.release()
print("saved:", saved)

连续视频相邻帧非常相似。训练集和验证集应按视频、机位或时间段划分,不能把同一段连续帧随机打散到两边,否则验证指标会虚高。

YOLO 数据结构:

helmet_dataset/
├─ images/
│ ├─ train/
│ └─ val/
└─ labels/
├─ train/
└─ val/

单个标签行:

class_id x_center y_center width height

坐标归一化到 0~1class_id 必须与 YAML 中的类别顺序一致。

helmet.yaml

path: /absolute/path/to/helmet_dataset
train: images/train
val: images/val
names:
0: helmet
1: no_helmet

第 3 步:建立训练环境#

Terminal window
conda create -n helmet-yolo python=3.10 -y
conda activate helmet-yolo
pip install ultralytics
nvidia-smi
python - <<'PY'
import torch
print("torch:", torch.__version__)
print("cuda available:", torch.cuda.is_available())
print("cuda version:", torch.version.cuda)
PY

PyTorch、CUDA 和驱动组合应参考当前 PyTorch/Ultralytics 官方安装说明,不要固定照抄课程中的旧版本。

第 4 步:训练和验证#

命令行示例:

Terminal window
yolo detect train \
model=yolo26n.pt \
data=helmet.yaml \
epochs=300 \
imgsz=640 \
batch=-1 \
workers=4 \
patience=50 \
device=0

Python 示例:

from ultralytics import YOLO
if __name__ == "__main__":
model = YOLO("yolo26n.pt")
model.train(
data="helmet.yaml",
epochs=300,
imgsz=640,
batch=-1,
workers=4,
patience=50,
device=0,
)

Windows 多进程训练要保留 if __name__ == "__main__":

训练结束优先使用 best.pt,并检查:

  • train/val loss;
  • 每类别 Precision、Recall、mAP;
  • 混淆矩阵;
  • PR 和 F1 曲线;
  • 验证集真实框与预测框;
  • 漏检、误检和小目标案例。

Ultralytics 当前训练参数和用法参考官方 Train 文档

四、把 YOLO 模型导出到 RKNN#

这里有两条路线。

路线 A:Ultralytics 直接导出 RKNN#

截至本文写作时,Ultralytics 已提供 RKNN 集成,要求在 x86 Linux 上导出,当前主要支持检测模型:

from ultralytics import YOLO
model = YOLO("runs/detect/train/weights/best.pt")
# RK3588 浮点构建
model.export(format="rknn", name="rk3588")
# INT8 构建,data 用于量化校准
model.export(
format="rknn",
name="rk3588",
quantize=8,
data="helmet.yaml",
)

官方说明见 Ultralytics RKNN 集成文档。导出后可用 Ultralytics 在 RK3588 上执行预测和验证,但正式 C++ 项目仍要确认输出 Tensor 契约。

路线 B:ONNX → Toolkit2 → 自定义 C++#

如果需要复用 Model Zoo 的 C++ 后处理、修改检测头输出或做深度定制:

best.pt
→ 导出 ONNX
→ onnx.checker + Netron + ONNX Runtime
→ Toolkit2 转 RKNN
→ Python 模拟器/连板验证
→ C++ 后处理

课程中的 YOLO26 示例通过修改检测头导出多路回归/分类特征。源码路径会随 Ultralytics 版本变化,不能机械按旧行号修改。无论怎样导出,必须固定并记录:

  • 输出数量和顺序;
  • 每个输出 shape;
  • 三个 stride/尺度;
  • 类别数;
  • DFL/回归解码方式;
  • 是否已经包含 NMS。

五、C++ 检测后处理的关键顺序#

读取各输出 Tensor
→ 按 scale/zero point 反量化
→ 解码每个尺度的候选框
→ 计算 objectness/类别分数
→ 置信度过滤
→ 合并所有尺度
→ 按类别 NMS
→ 去除 letterbox padding
→ 映射回原图坐标

Letterbox 参数必须随每帧保存:

scale = min(input_w / original_w, input_h / original_h)
pad_x = (input_w - original_w × scale) / 2
pad_y = (input_h - original_h × scale) / 2

还原坐标时先减 padding,再除以 scale,并裁剪到原图边界。

逐级调试方法#

  1. 固定一张测试图;
  2. 保存 PyTorch 输出和最终框;
  3. 保存 ONNX 对应输出;
  4. 保存 RKNN Python 输出;
  5. 保存 C++ 反量化后的部分 Tensor;
  6. 对比同一位置、同一类别和同一尺度;
  7. 最后才加入视频和多线程。

如果单图都不一致,不要通过反复调置信度阈值掩盖问题。

六、用官方 YOLO 示例建立参考#

RKNN Model Zoo 提供 YOLOv5、YOLOv8 等示例。以 YOLOv5 为例:

Terminal window
cd rknn_model_zoo/examples/yolov5/model
./download_model.sh
cd ../python
python convert.py ../model/yolov5s_relu.onnx rk3588
cd ../../..
export GCC_COMPILER=<AARCH64_TOOLCHAIN_PREFIX>
./build-linux.sh -t rk3588 -a aarch64 -d yolov5

示例模型可能专门删除了不利于量化的子图,并把它移到 C++ 后处理。因此官方示例的后处理不能无条件套到任意原始 YOLO ONNX。

七、YOLO 性能优化顺序#

1. INT8#

先用代表性校准集转换,再跑完整验证集。不要只比较某一张图片。

2. Letterbox 和 RGA#

Letterbox首先保证几何正确。确认 OpenCV 版本结果正确后,再用 RGA 替换 resize/颜色转换,并逐像素/逐框比较结果。

3. 多 Context 线程池#

解码 → 有界队列 → 3 个左右独立 Context worker
→ 结果重排 → 后处理/显示

线程数增加到一定程度会被 DDR、CPU 前后处理或 NPU 饱和限制。报告总吞吐时同时报告单帧 P95 延迟和队列深度。

4. 零拷贝#

通用 API 正确后,再把 RGA/DMA-BUF 输出绑定给 RKNN Tensor Memory,减少 CPU 拷贝。必须处理 stride 和 Cache 一致性。

5. 硬件友好的模型结构#

课程演示了将 SiLU 改为 ReLU 后重新训练。修改激活函数会改变模型,不能沿用原权重后直接宣称加速成功。正确流程是重新训练、导出、量化,并同时比较精度和性能。

八、视频流项目的完整指标#

最终报告至少包含:

类别指标
模型版本、输入尺寸、FP16/INT8、模型大小
精度每类 Precision/Recall、mAP、困难样本
性能纯推理、端到端 P50/P95、持续 FPS
资源CPU/NPU 利用率、峰值 RSS、温度、功耗
流水线解码/预处理/推理/后处理/编码耗时
稳定性运行时长、丢帧、队列峰值、错误恢复

“100 FPS”如果不说明线程数、是否包含前后处理、是否丢帧和输入尺寸,几乎没有复现价值。

九、RKLLM:在 RK3588 上部署 Qwen/DeepSeek#

RKLLM 与 RKNN 的整体思路相似:

Hugging Face 模型
→ RKLLM-Toolkit 转换和 W4A16/W8A8 等量化
→ .rkllm
→ RKLLM Runtime
→ RK3588 NPU

当前官方入口是 airockchip/rknn-llm。截至 2026-07-21,该仓库发布版本已到 v1.3.0,并列出 Python 3.9~3.12 支持;实际模型、量化类型和 API 仍以当前 README/Release 为准。

1. 先评估内存#

总内存不只包括模型文件:

量化权重
+ KV Cache(随上下文增长)
+ Runtime
+ Tokenizer/embedding
+ 系统和其他应用

8 GiB 板卡应从较小模型和较短上下文开始,先确认能稳定加载,再逐步增加。能放入存储不等于能在内存中运行。

2. 优先跑官方预转换模型#

第一次建议按仓库 Quickstart 下载预转换模型和 Demo,先验证 Runtime/驱动。官方多模态示例的基本步骤是:

Terminal window
adb push ./demo_Linux_aarch64 /data/
adb push ./model.rkllm /data/demo_Linux_aarch64/
adb push ./vision_model.rknn /data/demo_Linux_aarch64/
adb shell
cd /data/demo_Linux_aarch64
export LD_LIBRARY_PATH=./lib

具体命令参数包含图片、视觉 RKNN、语言 RKLLM、最大生成长度、上下文长度、NPU 核数和平台。参数在新版本中可能变化,运行前直接查看该 release 的 README 和 Demo usage。

3. 大模型性能要测什么#

  • 首 Token 延迟;
  • 生成速度 Token/s;
  • 最大 RSS 和 KV Cache;
  • 不同上下文长度的变化;
  • CPU/NPU 利用率;
  • 输出质量和量化影响;
  • 连续多轮对话的稳定性。

官方仓库建议使用频率脚本,并可设置:

Terminal window
export RKLLM_LOG_LEVEL=1

再配合仓库的 CPU/NPU 监控脚本记录性能和内存。

十、完整学习路线验收#

完成六篇后,我应该能独立完成:

确认硬件和版本
→ 搭建 Toolkit2/Runtime 环境
→ 检查并转换 ONNX
→ 对齐预处理和输出契约
→ 评估 INT8 精度、性能和内存
→ 用 Lite2/C API 在 RK3588 运行
→ 用零拷贝和多 Context 优化
→ 完成分类、检测或小型 LLM 项目

真正完成项目的标准,不是终端打印 success,而是有一套可复现的代码、版本、模型、指标和问题定位方法。

系列起点:RK3588 端侧 AI 部署(一):平台、NPU 与 RKNN 工具链

RK3588 端侧 AI 部署(六):MobileNet、YOLO 与 RKLLM 实战
https://blog.huangzy.xyz/posts/rk3588-端侧-ai-部署六/
Author
纸翼
Published at
2026-07-21
License
CC BY-NC-SA 4.0

Some information may be outdated