### 文章目录
- [@TOC](#文章目录 @[TOC] 1. 版本 2. 纯终端 vs 远程开发 3. CPU+YOLO 4. 开发板环境准备 5.虚拟机操作 6.NPU+YOLO 环境准备)
- [1. 版本](#文章目录 @[TOC] 1. 版本 2. 纯终端 vs 远程开发 3. CPU+YOLO 4. 开发板环境准备 5.虚拟机操作 6.NPU+YOLO 环境准备)
- [2. 纯终端 vs 远程开发](#文章目录 @[TOC] 1. 版本 2. 纯终端 vs 远程开发 3. CPU+YOLO 4. 开发板环境准备 5.虚拟机操作 6.NPU+YOLO 环境准备)
- [3. CPU+YOLO](#文章目录 @[TOC] 1. 版本 2. 纯终端 vs 远程开发 3. CPU+YOLO 4. 开发板环境准备 5.虚拟机操作 6.NPU+YOLO 环境准备)
- [4. 开发板环境准备](#文章目录 @[TOC] 1. 版本 2. 纯终端 vs 远程开发 3. CPU+YOLO 4. 开发板环境准备 5.虚拟机操作 6.NPU+YOLO 环境准备)
- [5.虚拟机操作](#文章目录 @[TOC] 1. 版本 2. 纯终端 vs 远程开发 3. CPU+YOLO 4. 开发板环境准备 5.虚拟机操作 6.NPU+YOLO 环境准备)
- [6.NPU+YOLO 环境准备](#文章目录 @[TOC] 1. 版本 2. 纯终端 vs 远程开发 3. CPU+YOLO 4. 开发板环境准备 5.虚拟机操作 6.NPU+YOLO 环境准备)
1. 版本
一、硬件平台
| 项目 | 内容 |
|---|---|
| 开发板 | 100ASK DShanPI R1(RK3568) |
| CPU | 四核 Cortex-A55 @ 2.0GHz |
| NPU | 1 TOPS INT8 |
| 内存 | 2GB LPDDR4 |
| 存储 | 15GB eMMC |
| 对比型号 | RK3576(6 TOPS,性价比)、RK3588(6 TOPS,旗舰) |
二、系统与内核
| 项目 | 版本/选择 | 说明 |
|---|---|---|
| 发行版 | Armbian 25.11 Minimal(无桌面版) | 内存占用约115MB,远低于带桌面版(300MB+) |
| 底层 | Debian trixie | 稳定、软件包丰富 |
| 内核 | 6.1.115-vendor-rk35xx | Rockchip厂商内核,含NPU驱动 |
| NPU驱动 | rknpu 0.9.8 | 需加载设备树overlay启用 |
| 桌面环境 | 不安装 | 通过SSH + 推流开发,释放内存给模型 |
三、软件环境版本全览
- 开发板端(Armbian)
| 软件 | 版本 | 用途/备注 |
|---|---|---|
| 系统Python | 3.13.5 | 仅用于OpenCV/numpy脚本 |
| 虚拟环境Python | 3.12.7 | RKNN-Toolkit-Lite2所需,通过python-build-standalone安装 |
| OpenCV(系统) | 5.0.0.93 | 用于CPU版YOLO推理 |
| OpenCV(venv) | 4.10.0.84 | 兼容numpy 1.26.4,避免与RKNN冲突 |
| numpy | 1.26.4 | RKNN-Toolkit-Lite2依赖 |
| RKNN-Toolkit-Lite2 | 2.3.2 | 板端NPU推理库 |
| librknnrt.so | 2.0.0b0 | NPU运行时库,需放入/usr/lib |
- PC端(Ubuntu虚拟机)
| 软件 | 版本 | 用途/备注 |
|---|---|---|
| Ubuntu | 推荐22.04 LTS或24.04 LTS | 20.04偏旧,但可用 |
| Python | 3.10(22.04)或3.12(24.04) | 与RKNN-Toolkit2匹配 |
| RKNN-Toolkit2 | 2.3.2 | 模型转换与量化 |
| ONNX | 1.18.0(<1.19.0) | 避免YOLO26转换报错 |
| ONNX opset | 12 | 导出ONNX时指定 |
| PyTorch | 2.4.0+cpu | 仅CPU版,190MB,满足RKNN依赖 |
| YOLOv8n ONNX | 来自官方或OpenCV镜像 | 12MB,用于CPU和NPU部署 |
四、版本兼容性核心规则
- RKNN-Toolkit2 与 Ubuntu/Python 对应关系
| RKNN-Toolkit2 | Ubuntu (x64) | 推荐Python |
|---|---|---|
| v2.3.x | 24.04 LTS | 3.12 |
| 22.04 LTS | 3.10 / 3.11 | |
| 20.04 LTS | 3.8 / 3.9 | |
| 18.04 LTS | 3.6 / 3.7 |
- YOLO版本与工具链
| YOLO版本 | 推荐ONNX版本 | RKNN-Toolkit2最低版本 | 特点 |
|---|---|---|---|
| YOLOv8n | <1.19.0(如1.18.0) | ≥2.0.0 | 成熟,资料最多 |
| YOLO26n | <1.19.0 | ≥2.3.0 | 无NMS,边缘优化 |
- 板端与PC端版本匹配
- RKNN-Toolkit2(PC) 与 RKNN-Toolkit-Lite2(板) 大版本需一致(如均为2.3.2)
- librknnrt.so 版本尽量与工具链匹配,避免推理报错
五、部署流程回顾与关键坑
阶段一:CPU推理(理解全流程)
- 用
cv2.dnn.readNetFromONNX加载YOLOv8n - 预处理:
blobFromImage除255、缩放640、BGR转RGB - 推理输出
(1,84,8400) - 后处理:置信度过滤、NMS、画框
- 速度:1~3 FPS
阶段二:NPU部署(加速)
- PC端:ONNX → RKNN(INT8量化,需校准集)
- 板端:
RKNNLite加载.rknn,调用NPU推理 - 关键坑1 :RKNN内部已归一化,预处理不能除255(用1.0)
- 关键坑2 :INT8量化需用场景匹配的校准集,否则类别分数全0
- 关键坑3:FP16虽不量化但速度慢(RK3568对INT8优化更好)
- 实测速度:FP16约380ms/帧,INT8(好校准集)可到150~200ms/帧
六、选型思考:RK3568 / RK3576 / RK3588
| 型号 | NPU | 多路视频能力 | 价格 | 适合场景 |
|---|---|---|---|---|
| RK3568 | 1 TOPS | 有限,适合2路以内 | 已有 | 学习、轻量控制 |
| RK3576 | 6 TOPS | 4路1080P@25fps | ~899元 | 性价比之选,中高端AIoT |
| RK3588 | 6 TOPS | 16路以上,带宽翻倍 | ~1500元+ | 多路高并发、旗舰视觉 |
决策逻辑:
- 预算紧、学习为主 → 先用RK3568深入掌握部署全流程
- 需4路以内AI检测、追求性价比 → RK3576
- 多路高并发、一步到位 → RK3588
七、职业方向思考
- 岗位统称:AI嵌入式开发工程师、端侧AI部署工程师、边缘AI工程师
- 核心技能:模型量化、NPU部署、C++/Python、Linux驱动、性能优化
- 嵌入式背景优势:懂硬件、系统、内存管理,能解决兼容性与性能瓶颈
- 面试表述:突出"在资源受限平台上完成模型部署与优化"的实战经验
- 学习建议:从Python入手,逐步深入C++推理、多核调度、跟踪算法
八、常用命令与资源
- NPU检查 :
ls /dev/rknpu*、dmesg | grep -i rknpu - 模型转换 :
python3 convert.py yolov8n.onnx rk3568 i8 - 板端推理 :使用
RKNNLite,注意输入不除255 - 校准集生成 :
ffmpeg -i video.mp4 -vf "fps=2" -frames:v 100 calib_%03d.jpg
版本兼容问题确实是部署中最容易让人头疼的一环,很多时间都花在了环境配置上。我帮你把 RKNN 工具链、Python、Ubuntu 以及 YOLO 模型之间的对应关系梳理了一下,希望能帮你理清头绪。
📊 核心兼容性速查表
下面这张表是官方推荐的版本对应关系,可以作为你搭建环境时的核心参考:
| RKNN-Toolkit2 版本 | Ubuntu 版本 (x64) | 推荐 Python 版本 |
|---|---|---|
| v2.3.x (最新) | Ubuntu 24.04 LTS | 3.12 |
| Ubuntu 22.04 LTS | 3.10 或 3.11 | |
| Ubuntu 20.04 LTS | 3.8 或 3.9 | |
| Ubuntu 18.04 LTS | 3.6 或 3.7 |
注意:对于开发板(ARM64),RKNN-Toolkit-Lite2 的 Python 版本要求与你的 Armbian 系统(Debian 12)匹配,通常也是 Python 3.10 - 3.12。
🎯 针对你的情况:如何选择?
结合你之前用 Ubuntu 20.04 + Python 3.8 遇到的情况,建议如下:
- 首选方案(最稳妥) :使用 Ubuntu 22.04 LTS + Python 3.10。这是目前社区资料最丰富、最稳定的组合,也是瑞芯微官方 Demo 常用的环境,可以避开很多新版本的坑。
- 次选方案(追求最新) :使用 Ubuntu 24.04 LTS + Python 3.12。这是官方目前推荐的最新组合,能获得最新的工具链支持。
- 关于 Ubuntu 20.04 + Python 3.8 :这个组合仍然可用,但已经偏旧。如果你之前的环境能跑通,可以继续用;如果重新搭建,建议升级到 22.04。
🤖 YOLO 版本与工具链的兼容性
你提到的 YOLOv8n 和 YOLO26n,在部署时有不同的要求:
- YOLOv8n :非常成熟。官方
rknn_model_zoo有完整的示例,对 RKNN-Toolkit2 的版本要求比较宽松,v2.0.0 及以上的版本都可以。 - YOLO26n :部署时需要注意 ONNX 版本 。有 PR 明确指出,ONNX 版本必须低于 1.19.0 ,否则会出现
AttributeError: module 'onnx' has no attribute 'mapping'的错误。此外,需要 RKNN-Toolkit2 ≥ 2.3.0 以获得更好的支持。
🔗 关键依赖:ONNX 与 ONNX opset 版本
这是从 PyTorch 导出 ONNX 时最容易忽略的环节。
-
ONNX 版本 :建议在环境中明确安装
onnx<1.19.0(例如1.18.0),以避免上述的兼容性错误。 -
ONNX opset :导出时建议指定
opset=11或opset=12。有些转换脚本为了兼容性,甚至会自动限制最高 opset 为 19 。你可以在导出命令中明确指定:bash# 导出时指定 opset 版本 yolo export model=yolov8n.pt format=onnx opset=12
⚙️ 环境搭建与版本管理建议
为了避免未来再次陷入"版本地狱",推荐使用 Miniforge (Conda) 来管理不同的项目环境。你可以为 YOLOv8 和 YOLO26 分别创建独立的虚拟环境,互不干扰。
例如,创建一个专门用于 YOLOv8 部署的环境:
bash
# 创建一个名为 yolo8_deploy 的环境,指定 Python 3.10
conda create -n yolo8_deploy python=3.10 -y
# 激活环境
conda activate yolo8_deploy
# 在此环境中安装指定版本的 ONNX 和 RKNN-Toolkit2
pip install onnx==1.18.0
pip install rknn_toolkit2==2.3.2
🔧 常见问题排查
- RKNN-Toolkit2 安装失败 :首先检查 Python 版本是否与 Ubuntu 版本匹配(如上表所示)。其次,确保是在正确的虚拟环境中执行安装命令。
- 模型转换时报错 :如果遇到与
onnx相关的 AttributeError,优先检查 ONNX 版本是否过高 ,尝试降级到1.18.0或更低版本。 - 开发板端推理报错 :确保开发板上的
librknnrt.so版本与 PC 端 RKNN-Toolkit2 的版本保持一致或兼容。版本不匹配是导致推理失败的一个常见原因。
2. 纯终端 vs 远程开发
| 对比项 | MobaXterm(纯 SSH 终端) | Trae / VS Code Remote-SSH |
|---|---|---|
| 架构 | 本地只负责显示字符、发送按键 | 本地是前端界面,开发板运行后端服务 |
| 开发板进程 | 仅 sshd + 你执行的命令 |
sshd + Trae/VS Code Server + 语言服务器 + 插件 |
| 内存占用 | 几 MB ~ 十几 MB | 100MB ~ 500MB+(大型项目可超 1GB) |
| CPU 占用 | 极低(仅传输文本) | 中高(文件索引、语法分析、AI 请求) |
| 典型功能 | 命令行操作、文件传输 | 智能补全、跳转定义、调试、AI 辅助 |
| 适用场景 | 编译、运行、监控、系统操作 | 写代码、重构、复杂项目开发 |
结论:MobaXterm 是"远程打字机",Remote-SSH 是"远程电脑"。打字机不耗电,远程电脑要耗电。
二、Remote-SSH 资源消耗详解
Remote-SSH 会在开发板上安装一个服务端,主要消耗来自:
- Trae/VS Code Server 基础进程:100~150MB
- 语言服务器(如 Pylance、clangd):200~400MB
- 扩展插件(Git、Linter、AI 助手):100~200MB
- 项目索引:100~300MB(视项目大小)
对于 2GB 内存的 RK3568,长时间运行 Remote 会严重挤占 YOLO 等 AI 任务的资源,甚至导致 OOM。
三、Remote-SSH 优化配置(没成功)
- 强制插件在本地运行(最关键)
在Trae的远程窗口中,按 Ctrl+Shift+P,输入 Preferences: Open Remote Settings (JSON) 并回车
在远程窗口 的settings.json中添加:
json
{
"extensions.experimental.affinity": {
"*": 0
}
}
"*": 0表示所有插件仅在本地电脑运行,不占用开发板资源。0=仅本地,1=仅远程,2=自动(默认,最耗资源)。
- 排除文件监听,防止内存暴涨
同样在远程 settings.json 中添加:
json
{
"files.watcherExclude": {
"**/node_modules/**": true,
"**/dist/**": true,
"**/build/**": true,
"**/.git/**": true
}
}
四、更轻量的替代方案(工业级推荐)
如果优化后 2GB 开发板依然吃力,可切换以下方案,资源占用极低:
| 方案 | 原理 | 开发板占用 | 适用场景 |
|---|---|---|---|
| sshfs + 本地编辑器 | 将开发板目录挂载到本地,本地编辑,编译运行仍在开发板 | 极低(仅文件系统) | 喜欢本地 IDE 编辑,接受命令行编译 |
| rsync + gdbserver | 本地交叉编译,rsync 同步二进制,gdbserver 远程调试 | 极低(gdbserver 仅 5-15MB) | 嵌入式行业标准工作流 |
| rtty | 超轻量 Web 终端,客户端仅 692KB | 极低 | 远程终端维护、简单编辑 |
推荐 :rsync + gdbserver 是嵌入式开发的最佳实践,构建与目标硬件分离,极致节省资源。
五、针对 RK3568(2GB)的实用建议
- 分时复用工具 :
- 写代码/看代码 → 用 Trae Remote(优化后)
- 编译/跑 YOLO/监控资源 → 用 MobaXterm(纯终端)
- 用完即断:不需要 Remote 时,立即断开连接,释放开发板内存。
- 监控资源 :在 MobaXterm 中
htop或free -h,观察 Trae Server 实际占用。 - 只装必要扩展:远程端仅保留 Python / C++ 核心支持,禁用主题、GitLens、AI 助手等。
- 终极方案:若长期受内存困扰,考虑升级到 4GB/8GB 开发板(如 RK3576/RK3588)。
-
核心区别:远程开发 vs. 本地挂载
远程开发 (Remote Development):在开发板上安装一个完整的服务端(VS Code Server),所有代码分析、补全、索引都在板子上运行。功能强大,但资源占用极高。
-
本地挂载 (Local Mount):通过 SFTP 等协议将开发板的目录"挂载"为本地文件夹。代码编辑、AI 补全等都在你的电脑上运行,开发板几乎不消耗资源。
-
插件对比
-
Open Remote - SSH (jeanp413)
原理:远程开发。微软官方 Remote-SSH 的开源替代品,功能几乎一致,专为 VSCodium 等非官方 VSCode 设计。
开发板占用:极高,和官方 Remote-SSH 一样,需要安装完整服务端。
- Remote SSH (Microsoft)
原理:远程开发。微软官方插件,功能最全,体验最好。
开发板占用:极高。这是资源消耗的"元凶",2GB 内存的板子会非常吃力。
- SSH FS (Kelvin)
原理:本地挂载。通过 FUSE 技术,将远程目录挂载为本地工作区,编辑体验接近本地。
开发板占用:几乎为零。它不需要在板子上安装任何服务,资源占用极低。
SSH FS 是目前最符合你要求的扩展,它将"本地挂载"和"远程终端"两大功能整合在了一起。
文件挂载与实时同步:它通过 SFTP 协议将开发板的目录直接挂载为 VS Code 的本地工作区文件夹。你在编辑器中的任何保存操作都会实时同步到开发板,无需手动上传下载。
集成远程终端:扩展内置了远程终端功能。你可以通过侧边栏按钮或命令面板,一键在开发板的指定目录中打开一个终端,直接运行 gcc、make 等命令。
极低资源占用:它的工作原理是纯客户端的,不会在开发板上安装任何后台服务,因此对开发板的内存和 CPU 消耗几乎为零。
其他实用功能:支持配置编辑、连接复用、SSH 跳板等,使用体验很流畅。
安装与关键配置:在 VS Code 扩展商店搜索 SSH FS (作者 Kelvin Schoofs) 安装即可。为了确保文件保存后直接写入远程,建议在 VS Code 设置中将 sshfs.saveMode 改为 direct
3. CPU+YOLO
一、环境准备
- 开发板系统信息
- 发行版:Armbian 25.11 Minimal(无桌面)
- 内核:6.1.115-vendor-rk35xx
- Python:系统自带 3.13
- 内存:2GB
- 安装依赖(系统 Python 3.13)
bash
# 安装 pip(若未安装)
sudo apt update
sudo apt install -y python3-pip
# 安装 numpy 2.x(Python 3.13 不支持 numpy 1.26.4,会编译失败)
pip3 install "numpy<2.3" --break-system-packages
# 安装 OpenCV headless(无 GUI,省内存)
pip3 install opencv-python-headless==4.10.0.84 --break-system-packages
# 验证
python3 -c "import cv2, numpy; print('OpenCV:', cv2.__version__, 'NumPy:', numpy.__version__)"
预期输出:
OpenCV: 4.10.0 NumPy: 2.2.6
⚠️ 踩坑记录:
- 直接装
numpy==1.26.4会失败,因为 Python 3.13 没有对应的预编译 whl,pip 会尝试源码编译,缺Python.h报错。 - 系统 Python 3.13 用 numpy 2.x 完全够用;后续 NPU 推理会在独立的 Python 3.12 venv 中安装 numpy 1.26.4,互不影响。
二、下载 YOLOv8n ONNX 模型
bash
cd ~/yolo
wget --user-agent="Mozilla/5.0" -O yolov8n.onnx https://dl.opencv.org/models/yolov8/yolov8n.onnx
ls -lh yolov8n.onnx # 应约 12~13MB
注意:OpenCV 镜像可能返回 403,但文件有时已缓存成功。若失败,可从其他源下载(如 GitHub Release 或从 PC 传输)。
三、CPU 推理代码(带详细注释)
创建 cpu_infer.py:
python
import cv2 # 导入 OpenCV 库,用于图像处理和深度学习模型推理
import numpy as np # 导入 NumPy 库,用于数组运算和数值计算
import time # 导入时间模块,用于测量推理耗时
# 1. 加载模型
print("加载 ONNX 模型...") # 打印提示信息,告诉用户正在加载模型
net = cv2.dnn.readNetFromONNX('yolov8n.onnx') # 读取 ONNX 格式的 YOLOv8n 模型,返回一个网络对象
print("模型加载成功") # 打印成功信息
# 2. 读取图片
img = cv2.imread('testd.jpg') # 读取当前目录下的 testd.jpg 图片,返回 NumPy 数组
if img is None: # 判断图片是否读取成功(失败返回 None)
print("❌ 找不到 testd.jpg") # 如果失败,打印错误信息
exit(1) # 退出程序,返回码 1 表示异常退出
h, w = img.shape[:2] # 获取图片的高度和宽度(shape 返回 (高, 宽, 通道))
print(f"图片尺寸: {w}x{h}") # 打印图片的宽和高
# 3. 预处理(CPU 版要除 255)
# 使用 blobFromImage 对图像进行预处理:缩放、归一化、BGR 转 RGB、调整维度
# 参数:图像, 缩放因子 1/255.0(将像素值从 0~255 归一化到 0~1), 目标尺寸 (640,640),
# 均值 (0,0,0) 不做减均值, swapRB=True 将 BGR 转为 RGB, crop=False 不裁剪
blob = cv2.dnn.blobFromImage(img, 1/255.0, (640, 640), (0,0,0), swapRB=True, crop=False)
net.setInput(blob) # 将预处理后的图像输入到神经网络
# 4. 推理
start = time.time() # 记录推理开始时间
outputs = net.forward() # 执行前向传播,得到模型输出
print(f"推理耗时: {(time.time()-start)*1000:.1f} ms") # 计算并打印推理耗时(毫秒)
# 5. 后处理
outputs = outputs[0].T # 输出形状为 (1,84,8400),取第一个元素并转置得到 (8400,84),每行一个预测框
# 定义 COCO 数据集的 80 个类别名称,模型输出的类别索引对应这些名称
class_names = ['person','bicycle','car','motorcycle','airplane','bus','train','truck','boat','traffic light','fire hydrant','stop sign','parking meter','bench','bird','cat','dog','horse','sheep','cow','elephant','bear','zebra','giraffe','backpack','umbrella','handbag','tie','suitcase','frisbee','skis','snowboard','sports ball','kite','baseball bat','baseball glove','skateboard','surfboard','tennis racket','bottle','wine glass','cup','fork','knife','spoon','bowl','banana','apple','sandwich','orange','broccoli','carrot','hot dog','pizza','donut','cake','chair','couch','potted plant','bed','dining table','toilet','tv','laptop','mouse','remote','keyboard','cell phone','microwave','oven','toaster','sink','refrigerator','book','clock','vase','scissors','teddy bear','hair drier','toothbrush']
boxes, confs, ids = [], [], [] # 初始化三个空列表,分别存放边界框坐标、置信度和类别索引
for row in outputs: # 遍历每一个预测框(共 8400 个)
scores = row[4:] # 取第 4 个元素之后的所有值,即 80 个类别的概率
cid = int(np.argmax(scores)) # 找到概率最大的类别索引
conf = float(scores[cid]) # 取该最大概率值作为置信度
if conf > 0.25: # 如果置信度大于 0.25,则认为检测有效
xc, yc, bw, bh = row[0], row[1], row[2], row[3] # 提取中心坐标 x,y 和宽高 w,h
xc, yc = xc/640*w, yc/640*h # 将中心坐标从 640x640 缩放回原图尺寸
bw, bh = bw/640*w, bh/640*h # 将宽高从 640x640 缩放回原图尺寸
# 计算左上角和右下角坐标,并转为整数
boxes.append([int(xc-bw/2), int(yc-bh/2), int(xc+bw/2), int(yc+bh/2)])
confs.append(conf) # 保存置信度
ids.append(cid) # 保存类别索引
# 使用非极大值抑制(NMS)去除重叠的检测框
# 参数:所有框, 置信度, 置信度阈值 0.25, NMS 阈值 0.4
indices = cv2.dnn.NMSBoxes(boxes, confs, 0.25, 0.4)
print(f"检测到 {len(indices)} 个目标") # 打印最终检测到的目标数量
# 6. 画框
if len(indices) > 0: # 如果检测到了目标
for i in np.array(indices).flatten(): # 将 indices 转为扁平数组并遍历每个保留框的索引
x1, y1, x2, y2 = boxes[i] # 获取对应框的左上角和右下角坐标
cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) # 在原图上画绿色矩形框,线宽 2
# 在框的左上角上方写类别名称和置信度,颜色绿色,字体大小 0.6,线宽 2
cv2.putText(img, f'{class_names[ids[i]]} {confs[i]:.2f}', (x1, y1-5),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
cv2.imwrite('cpu_result.jpg', img) # 将画好框的图像保存为 cpu_result.jpg
print("已保存 cpu_result.jpg") # 打印保存成功信息
四、运行与结果
bash
cd ~/yolo
python3 cpu_infer.py
实测输出:
加载 ONNX 模型...
模型加载成功
图片尺寸: 1024x768
推理耗时: 1740.4 ms
检测到 6 个目标
已保存 cpu_result.jpg
结果图片 :cpu_result.jpg 中6头牛全部被绿色框标出,置信度 0.89~0.93,类别 cow。

五、关键知识点与对比
| 项目 | CPU 版(ONNX + OpenCV DNN) | NPU 版(RKNN) |
|---|---|---|
| 模型格式 | .onnx |
.rknn(INT8量化) |
| 预处理归一化 | 必须除以 255 (代码中 1/255.0) |
不能除以 255(RKNN 内部已处理) |
| 推理速度 | 约 300~500 ms/帧(2~3 FPS) | 目标 50~150 ms/帧(10~20 FPS) |
| 内存占用 | 中等(模型+OpenCV) | 低(量化后模型更小) |
| 适用 Python | 系统 Python 3.13 | 独立 Python 3.12 venv |
| 校准集 | 不需要 | 需要(建议用场景匹配的牛图) |
⚠️ 最易踩坑 :从 CPU 迁移到 NPU 时,预处理必须把 1/255.0 改成 1.0,否则输入被双重归一化,检测结果全为 0。
4. 开发板环境准备
步骤 1:确认切换到 NPU 的目标
背景 :CPU 视频推理实测 1400 ms/帧,295 帧需要约 7 分钟,太慢。
决定:把 YOLOv8n 从 ONNX 转成 RKNN 格式,用 RK3568 的 NPU 推理。
涉及概念:
- ONNX:CPU 能跑的通用模型格式,不能调用 NPU
- RKNN:瑞芯微专用模型格式,能调用 NPU
- RKNN-Toolkit2:把 ONNX 转 RKNN 的工具,只能在 x86_64 上跑
- RKNN-Toolkit-Lite2 :在开发板上加载
.rknn推理的库
步骤 2:检查开发板 NPU 驱动状态
在开发板上执行:
bash
# 检查内核中是否包含 rknpu 驱动
grep rknpu /usr/lib/modules/$(uname -r)/modules.builtin
输出:
kernel/drivers/rknpu/rknpu.ko
解释:内核已编译 rknpu 驱动模块。
bash
# 检查设备树中 NPU 节点状态
cat /sys/firmware/devicetree/base/npu@fde40000/status
输出:
okay
解释:设备树中 NPU 节点是使能状态。
bash
# 检查 NPU 初始化日志
dmesg | grep -i rknpu
输出(关键错误):
RKNPU fde40000.npu: can't request region for resource [mem 0xfde40000-0xfde4ffff]
RKNPU fde40000.npu: error -ENXIO: IRQ npu_irq not found
解释:驱动无法申请内存区域、找不到中断号。
bash
# 检查 NPU 设备节点
ls -l /dev/rknpu*
输出:
ls: cannot access '/dev/rknpu*': No such file or directory
解释 :设备节点未创建,NPU 实际不可用。需要在开发板上加载设备树 overlay(未解决)。
c
* 查看 DRM 渲染节点
ls -l /dev/dri/
输出
crw-rw---- 1 root video 226, 0 card0
crw-rw---- 1 root render 226, 128 renderD128 ← 显示控制器
crw-rw---- 1 root render 226, 129 renderD129 ← NPU
crw-rw---- 1 root render 226, 130 renderD130 ← GPU
dmesg | grep -i rknpu | head -10
输出
OF: reserved mem: initialized node rknpu
RKNPU fde40000.npu: RKNPU: rknpu iommu is disabled, using non-iommu mode ← 核心!
RKNPU fde40000.npu: assigned reserved memory node rknpu
RKNPU fde40000.npu: RKNPU: initialize reserved memory for rknpu device!
[drm] Initialized rknpu 0.9.8 20240828 for fde40000.npu on minor 1
- 这个NPU加载问题详见
【Linux】RK3568-NPU加载失败问题(九)
5.虚拟机操作
环境:Ubuntu 24.04 LTS / Python 3.12
目标:把
yolov8n.onnx转换成 RK3568 NPU 可用的yolov8n.rknn
步骤 1:确认系统环境
命令:
bash
# 查看系统版本
lsb_release -a
# 查看 Python 版本
python3 --version
# 查看 pip 是否可用
pip3 --version
输出:
- Ubuntu 24.04.5 LTS(Noble)
- Python 3.12.3
- pip3 未安装
说明:
- Ubuntu 24.04 默认 Python 3.12,符合 RKNN-Toolkit2 官方推荐
- pip 需要后续手动安装
步骤 2:安装系统基础工具
命令:
bash
# 更新软件包索引(拉取最新包列表)
sudo apt update
# 安装编译工具 + Python 开发环境
sudo apt install -y build-essential git wget curl python3-pip python3-venv python3-dev
工具作用:
| 工具 | 作用 |
|---|---|
build-essential |
gcc、g++、make,编译 C/C++ 程序 |
git |
克隆仓库(如 rknn-toolkit2) |
wget / curl |
下载文件 |
python3-pip |
Python 包管理器 |
python3-venv |
创建虚拟环境 |
python3-dev |
Python 头文件(编译扩展用) |
输出:新安装 59 个包,共 72.3 MB。
步骤 3:创建 Python 虚拟环境
命令:
bash
# 用系统 Python 3.12 创建虚拟环境(放在 home 目录下)
python3 -m venv ~/rknn_env
# 激活虚拟环境
source ~/rknn_env/bin/activate
# 确认 python 指向虚拟环境
which python
# 输出:/home/user/rknn_env/bin/python
# 确认 Python 版本
python --version
# 输出:Python 3.12.3
说明:
- 虚拟环境隔离系统 Python,避免污染
- 后续所有
pip install都装在这个环境里
涉及文件:
~/rknn_env/:Python 3.12 虚拟环境目录~/rknn_env/bin/python:虚拟环境的解释器
步骤 4:配置 pip 源(踩坑)
第一次尝试清华源:
bash
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
测试失败:
bash
pip install numpy==1.26.4
# 输出:Failed to establish a new connection: [Errno 101] 网络不可达
诊断网络:
bash
# ping 通
ping -c 3 mirrors.tuna.tsinghua.edu.cn
# 但 HTTPS 443 端口被封
curl -v https://pypi.tuna.tsinghua.edu.cn/simple/
# 输出:connect to 101.6.15.130 port 443 failed: 连接被拒绝
# 官方 PyPI 能通
curl -v https://pypi.org/simple/
# 输出:Connected to pypi.org port 443
切换到官方源:
bash
pip config set global.index-url https://pypi.org/simple/
说明:
- 清华源 443 端口被封(虚拟机网络环境限制)
- 官方源速度慢(100 kB/s)但能通
涉及文件:
~/.config/pip/pip.conf:pip 配置文件
步骤 5:安装 RKNN-Toolkit2 依赖
命令:
bash
pip install numpy==1.26.4 onnx==1.18.0 onnxruntime==1.19.2 protobuf==4.25.4 \
psutil ruamel.yaml scipy tqdm opencv-python-headless==4.10.0.84 fast-histogram
每个包的作用:
| 包 | 版本 | 作用 |
|---|---|---|
| numpy | 1.26.4 | RKNN-Toolkit2 严格要求(2.x 会报错) |
| onnx | 1.18.0 | 读取 ONNX 模型,必须 <1.19.0 |
| onnxruntime | 1.19.2 | ONNX 推理后端 |
| protobuf | 4.25.4 | ONNX 依赖的序列化库 |
| psutil | 最新 | 系统监控(RKNN 内部使用) |
| ruamel.yaml | 最新 | 解析 YAML 配置 |
| scipy | 1.17.1 | 科学计算(量化时用) |
| tqdm | 最新 | 进度条 |
| opencv-python-headless | 4.10.0.84 | 图像处理(headless 版无 GUI,省资源) |
| fast-histogram | 最新 | 快速直方图统计(量化用) |
输出:约 10 分钟下载完(速度 100 kB/s)。
步骤 6:下载 PyTorch CPU 版
为什么需要 PyTorch :RKNN-Toolkit2 内部会 import torch。
测试阿里云镜像:
bash
# curl 探测文件存在
curl -I https://mirrors.aliyun.com/pytorch-wheels/cpu/torch-2.4.0%2Bcpu-cp312-cp312-linux_x86_64.whl
# 返回 HTTP/2 200
# 但 wget 直连被拒(防盗链)
wget -c https://mirror.aliyun.com/pytorch-wheels/cpu/torch-2.4.0%2Bcpu-cp312-cp312-linux_x86_64.whl
# 输出:连接被拒绝
改用上海交大镜像:
bash
# 下载(支持断点续传)
wget -c https://mirror.sjtu.edu.cn/pytorch-wheels/cpu/torch-2.4.0%2Bcpu-cp312-cp312-linux_x86_64.whl
输出:
185.95M 7.51MB/s 用时 28s
说明:
- GPU 版 797MB(含 CUDA),虚拟机无显卡用不上
- CPU 版 186MB,够用
- 上海交大镜像速度 7.5 MB/s,非常快
涉及文件:
~/yolo/torch-2.4.0+cpu-cp312-cp312-linux_x86_64.whl:PyTorch CPU 安装包(186MB)
步骤 7:安装 PyTorch
命令:
bash
# 切换到文件所在目录
cd ~/yolo
# 本地安装(不重新下载)
pip install ./torch-2.4.0+cpu-cp312-cp312-linux_x86_64.whl
输出:
Successfully installed MarkupSafe-3.0.3 filelock-4.0.4 fsspec-2026.9.0
jinja2-3.1.6 networkx-3.7 setuptools-84.0.0 torch-2.4.0+cpu
验证:
bash
python -c "import torch; print('PyTorch:', torch.__version__)"
# 输出:PyTorch: 2.4.0+cpu
⚠️ 注意 :此时 setuptools 被自动升级到 84.0.0,埋下后续 pkg_resources 缺失的坑。
步骤 8:下载 RKNN-Toolkit2 的 whl
命令:
bash
# 用 ghproxy.net 代理下载(迅雷也能下)
wget -c https://ghproxy.net/https://github.com/airockchip/rknn-toolkit2/raw/master/rknn-toolkit2/packages/x86_64/rknn_toolkit2-2.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
输出:
37.03M 85.5 KB/s 用时 7m 23s
说明:
- 从 GitHub raw 下载,用 ghproxy.net 代理加速
- 选择
cp312版本(对应 Python 3.12) x86_64架构(虚拟机是 x86_64)
涉及文件:
~/yolo/rknn_toolkit2-2.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:RKNN-Toolkit2 安装包(38MB)
步骤 9:安装 RKNN-Toolkit2
命令:
bash
# 激活虚拟环境
source ~/rknn_env/bin/activate
# 安装(--no-deps 跳过已装依赖)
pip install --no-deps ./rknn_toolkit2-2.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
输出:
Successfully installed rknn-toolkit2-2.3.2
验证:
bash
python -c "from rknn.api import RKNN; print('RKNN-Toolkit2 就绪!')"
# 输出:RKNN-Toolkit2 就绪!
说明:
--no-deps:只装 RKNN-Toolkit2 本身,依赖已手动装好- 不加可能重新下载/升级依赖,浪费时间
步骤 10:克隆 rknn_model_zoo 仓库
先试 GitHub(失败):
bash
git clone --depth 1 https://ghfast.top/https://github.com/airockchip/rknn_model_zoo.git
# 卡住不动
改用 Gitee 镜像(成功):
bash
git clone --depth 1 https://gitee.com/seaflyren/rknn_model_zoo.git
输出:
205.80 MiB | 9.60 MiB/s 完成
说明:
- Gitee 是国内代码托管平台,速度极快(9.6 MB/s)
- 仓库包含转换脚本、校准集、示例代码
涉及文件:
~/yolo/rknn_model_zoo/:仓库根目录(205MB)
目录结构:
~/yolo/rknn_model_zoo/
├── examples/
│ └── yolov8/
│ └── python/
│ ├── convert.py ← 转换脚本
│ └── yolov8.py ← 推理示例
└── datasets/
└── COCO/
├── coco_subset_20.txt ← 校准集列表
└── subset/ ← 校准图片
步骤 11:修复 pkg_resources 缺失
执行转换时报错:
bash
python convert.py ~/yolo/yolov8n.onnx rk3568
# ModuleNotFoundError: No module named 'pkg_resources'
原因:
- PyTorch 安装时自动升级 setuptools 到 84.0.0
- 新版 setuptools(80+)移除了
pkg_resources模块 - RKNN-Toolkit2 内部代码依赖
pkg_resources
解决:降级 setuptools:
bash
pip install "setuptools<80"
输出:
Uninstalling setuptools-84.0.0
Successfully installed setuptools-79.0.1
验证:
bash
python -c "import pkg_resources; print('pkg_resources 就绪')"
# 输出:pkg_resources 就绪
步骤 12:执行 ONNX → RKNN 转换
命令:
bash
# 进入转换脚本目录
cd ~/yolo/rknn_model_zoo/examples/yolov8/python
# 确认虚拟环境激活
source ~/rknn_env/bin/activate
# 执行转换
python convert.py ~/yolo/yolov8n.onnx rk3568
参数说明:
~/yolo/yolov8n.onnx:输入 ONNX 模型路径rk3568:目标 NPU 平台- 默认
dtype=i8(INT8 量化) - 默认校准集
../../../datasets/COCO/coco_subset_20.txt
输出(关键行):
I rknn-toolkit2 version: 2.3.2
--> Config model
done
--> Loading model
I Loading : 100%|██████████| 127/127
done
--> Building model
I OpFusing 0: 100%|██████████|
I Quantizating : 100%|██████████| 176/176
done
--> Export rknn model
done
可忽略的警告:
found outlier value:某些权重有离群值,量化正常现象Unkown op target: 0:少数算子回退 CPU,影响不大input dtype changed to int8:RKNN 内部把输入 dtype 改成 int8
输出文件:
~/yolo/rknn_model_zoo/examples/yolov8/model/yolov8.rknn
步骤 13:验证转换结果
命令:
bash
ls -lh ~/yolo/rknn_model_zoo/examples/yolov8/model/yolov8.rknn
输出:
-rw-rw-r-- 1 user user 4.2M ... yolov8.rknn
对比:
| 文件 | 大小 | 说明 |
|---|---|---|
yolov8n.onnx |
12MB | 原始模型(FP32) |
yolov8n.rknn |
约 4MB | NPU 模型(INT8 量化后) |
结论 :模型压缩到 1/3,已生成可供 RK3568 NPU 使用的 .rknn 文件。
📋 全部涉及文件清单
| 文件 | 位置 | 作用 |
|---|---|---|
~/rknn_env/ |
虚拟机 home | Python 3.12 虚拟环境 |
~/.config/pip/pip.conf |
虚拟机 home | pip 配置文件(index-url) |
~/yolo/yolov8n.onnx |
虚拟机 | 输入模型(12MB,FP32) |
~/yolo/torch-2.4.0+cpu-*.whl |
虚拟机 | PyTorch CPU 安装包(186MB) |
~/yolo/rknn_toolkit2-2.3.2-cp312-*.whl |
虚拟机 | RKNN-Toolkit2 安装包(38MB) |
~/yolo/rknn_model_zoo/ |
虚拟机 | 转换脚本+校准集仓库(205MB) |
~/yolo/rknn_model_zoo/examples/yolov8/python/convert.py |
虚拟机 | 转换脚本 |
~/yolo/rknn_model_zoo/datasets/COCO/coco_subset_20.txt |
虚拟机 | 校准集列表 |
~/yolo/rknn_model_zoo/examples/yolov8/model/yolov8.rknn |
虚拟机 | 输出模型(4.2MB,INT8) |
📌 关键经验
| 问题 | 解决方案 |
|---|---|
| 清华源 443 被封 | 改用官方 pypi.org |
| PyTorch 下载慢 | 用上海交大镜像(7.5 MB/s) |
| GitHub 克隆慢 | 用 Gitee 镜像(9.6 MB/s) |
| pkg_resources 缺失 | 降级 setuptools<80 |
| 依赖版本冲突 | 严格锁定 numpy=1.26.4、onnx=1.18.0 |
✅ 到此为止的成果
虚拟机最终产出:
~/yolo/rknn_model_zoo/examples/yolov8/model/yolov8.rknn
6.NPU+YOLO 环境准备
- 接第4章,开发板环境准备
目前是CPU+YOLO已经完成
虚拟机准备的rknn已经就绪
准备开发板使用NPU的环境
因为系统 Python 是 3.13,而 RKNNLite 最高只支持 3.12,所以我们必须重新搭建 Python 3.12 环境
- 搭建 Python 3.12 环境
下载镜像:由于网络限制,最终使用迅雷下载中科大镜像
中科大镜像:
https://mirrors.ustc.edu.cn/github-release/astral-sh/python-build-standalone/20241016/cpython-3.12.7%2B20241016-aarch64-unknown-linux-gnu-install_only.tar.gz
迅雷下载
bash
cd ~/yolo
# 1. 删掉之前可能没下载完的 py312.tar.gz,避免混淆
rm -f py312.tar.gz
# 2. 解压迅雷下载的完整压缩包(名字很长,可以用 Tab 键补全)
tar -xzf cpython-3.12.7+20241016-aarch64-unknown-linux-gnu-install_only.tar.gz
# 3. 验证解压成功
./python/bin/python3.12 --version
# 预期输出:Python 3.12.7
# 4. 创建并激活虚拟环境
./python/bin/python3.12 -m venv ~/rknn_env_312
source ~/rknn_env_312/bin/activate
# 5. 确认已进入虚拟环境(提示符前面应该有 (rknn_env_312))
which python
# 预期输出:/home/user/rknn_env_312/bin/python
- 安装 RKNNLite 和 Python 依赖库
在激活的虚拟环境中((rknn_env_312)),执行以下安装命令
bash
pip config set global.index-url https://pypi.org/simple/
说明:
清华源 443 端口被封(虚拟机网络环境限制)
官方源速度慢(100 kB/s)但能通
- 安装依赖(numpy 必须锁定 1.26.4)
pip install numpy==1.26.4 - 安装 RKNNLite
pip install rknn-toolkit-lite2


bash
python -c "from rknnlite.api import RKNNLite; print('✅ RKNNLite 就绪!')"
只要看到 ✅ RKNNLite 就绪!,说明 Python 环境已经全部打通

- 检查 NPU 底层库
环境好了,还要确认底层调用库在不在:
bash
ls -l /usr/lib/librknnrt.so
如果文件存在:直接进入下一步。
如果提示找不到:说明你重刷系统后,把这个库弄丢了。需要下载:
bash
cd ~/yolo
wget https://ghproxy.net/https://github.com/airockchip/rknn-toolkit2/raw/master/rknpu2/runtime/Linux/librknn_api/aarch64/librknnrt.so
sudo cp librknnrt.so /usr/lib/
sudo ldconfig
bash
(rknn_env_312) user@dshanpi-r1:~/yolo$ ls
cpu_infer.py librknnrt.so yolov8n.onnx
cpu_result.jpg python yolov8.rknn
cpython-3.12.7+20241016-aarch64-unknown-linux-gnu-install_only.tar.gz testd.jpg
(rknn_env_312) user@dshanpi-r1:~/yolo$ sudo cp librknnrt.so /usr/lib/
[sudo] user 的密码:
(rknn_env_312) user@dshanpi-r1:~/yolo$
(rknn_env_312) user@dshanpi-r1:~/yolo$ sudo ldconfig
(rknn_env_312) user@dshanpi-r1:~/yolo$ groups
user tty disk dialout sudo audio video plugdev games users netdev docker render input systemd-journal
(rknn_env_312) user@dshanpi-r1:~/yolo$
(rknn_env_312) user@dshanpi-r1:~/yolo$ ls -l /usr/lib/librknnrt.so
-rw-r--r-- 1 root root 8189368 11月 7日 23:49 /usr/lib/librknnrt.so
- 环境检查
bash
1. 检查 NPU 硬件节点
bash
ls -l /dev/dri/renderD129
期望:显示 crw-rw---- ... root render ... renderD129
2. 检查用户组权限
bash
groups
期望:输出里必须包含 render 和 video。如果没有,执行 sudo usermod -a -G video,render $USER,然后 exit 重新 SSH 登录。
3. 检查底层库
bash
ls -l /usr/lib/librknnrt.so
期望:显示该文件存在,大小约 7.8MB。
4. 检查模型文件
bash
ls -l ~/yolo/yolov8.rknn
期望:显示该文件存在,约 4.2MB。
5. 检查 Python 虚拟环境及核心库(⚠️ 最重要)
bash
cd ~/yolo
source ~/rknn_env_312/bin/activate
python -c "import numpy; print('numpy:', numpy.__version__)"
python -c "from rknnlite.api import RKNNLite; print('✅ RKNNLite 就绪!')"
期望:打印出 numpy: 1.26.4 以及 ✅ RKNNLite 就绪!
bash
(rknn_env_312) user@dshanpi-r1:~/yolo$ ls -l /dev/dri/renderD129
crw-rw---- 1 root render 226, 129 11月 6日 23:49 /dev/dri/renderD129
(rknn_env_312) user@dshanpi-r1:~/yolo$ groups
user tty disk dialout sudo audio video plugdev games users netdev docker render input systemd-journal
(rknn_env_312) user@dshanpi-r1:~/yolo$ ls -l /usr/lib/librknnrt.so
-rw-r--r-- 1 root root 8189368 11月 7日 23:49 /usr/lib/librknnrt.so
(rknn_env_312) user@dshanpi-r1:~/yolo$ ls -l ~/yolo/yolov8.rknn
-rw-rw-r-- 1 user user 4367248 11月 7日 21:48 /home/user/yolo/yolov8.rknn
(rknn_env_312) user@dshanpi-r1:~/yolo$ source ~/rknn_env_312/bin/activate
(rknn_env_312) user@dshanpi-r1:~/yolo$ python -c "import numpy; print('numpy:', numpy.__version__)"
numpy: 1.26.4
(rknn_env_312) user@dshanpi-r1:~/yolo$ python -c "from rknnlite.api import RKNNLite; print('✅ RKNNLite 就绪!')"
bash: !': event not found
(rknn_env_312) user@dshanpi-r1:~/yolo$
(rknn_env_312) user@dshanpi-r1:~/yolo$ python -c "from rknnlite.api import RKNNLite; print('✅ RKNNLite 就绪!')"
bash: !': event not found
(rknn_env_312) user@dshanpi-r1:~/yolo$
(rknn_env_312) user@dshanpi-r1:~/yolo$ python -c "from rknnlite.api import RKNNLite; print('✅ RKNNLite 就绪!')"
✅ RKNNLite 就绪!