7,855
社区成员
发帖
与我相关
我的任务
分享设备:犀牛派 A1(AidLux)
SoC:Qualcomm QCS6490
NPU/AI 加速:Qualcomm Hexagon DSP(通过 QNN236 后端调用)
目标:让 YOLOv26 模型走 NPU 而非 CPU 推理,并通过浏览器查看最高帧率的实时视频流。
作者: 漂移菌

摄像头: 叙利亚战损版USB摄像头,UVC协议

$ uname -a
Linux aidlux 5.15.x ... aarch64 GNU/Linux
$ cat /proc/cpuinfo | grep "model name" | head
Qualcomm Technologies, Inc QCS6490
结论:该设备不是 Rockchip,无法使用 RKNN。应使用高通自己的 AI SDK:SNPE / QNN。AidLux 系统已预装封装库 AidLite。
import aidlite
print(aidlite.FrameworkType.__members__)
# TYPE_ONNX, TYPE_QNN, TYPE_QNN216, TYPE_QNN223, TYPE_QNN229, TYPE_QNN231, TYPE_QNN236,
# TYPE_SNPE, TYPE_SNPE2, TYPE_SNPE216, TYPE_SNPE223, TYPE_SNPE229, ...
print(aidlite.AccelerateType.__members__)
# TYPE_CPU, TYPE_GPU, TYPE_DSP, TYPE_NPU
AidLite 版本信息(本机实测):
Aidlite library version : Aidlux_Aidlite_C4L_V2.2.8.206_160a6dd_20250820
Aidlite python library version : Aidlux_Aidlite_P4L_V2.2.8.206_160a6dd_20250820
⚠️ 关键坑点:QNN236 的
.ctx.bin模型**只能使用TYPE_DSP**。如果设置TYPE_NPU,初始化会报错:QNN's .bin model can only use DSP因此本项目中 QNN236 后端统一指定
AccelerateType.TYPE_DSP。
| 模型文件 | 路径 | 格式 | 能否在本机 NPU 跑 | 备注 |
|---|---|---|---|---|
yolo26n.onnx | aidcode/models/yolo26n.onnx | ONNX | ❌ 只能 CPU | AidLite ONNX 后端仅支持 CPU,实测约 109 ms/帧 |
yolo26n_for_qnn.onnx | aidcode/models/yolo26n_for_qnn.onnx | ONNX | ❌ 只能 CPU | 已剥离 NMS,输出 [1, 8400, 84],为 PC 端 QNN 转换准备 |
yolo26n.qnn236.ctx.bin | 尚未生成 | QNN236 ctx.bin | ✅ 可以 DSP 加速 | 需要在 PC 端用 QNN SDK 转换后再拷贝到设备 |
yolo26n.pt | aidcode/models/yolo26n.pt | PyTorch | ❌ 不能直接推理 | 训练/导出源文件 |
| 系统示例模型 | /usr/local/share/aidlite/examples/aidlite_qnn236/data/qnn_yolov5_multi/cutoff_yolov5s_640_sigmoid_w8a8.qnn236.ctx.bin | QNN236 | ✅ 已验证 | 用于验证 NPU 通路,约 13 ms/帧 |
在 /home/aidlux/aidcode/npu/ 下创建:
aidcode/
├── models/
│ ├── yolo26n.onnx # 原始模型,带内嵌 NMS,输出 [1,300,6]
│ ├── yolo26n_for_qnn.onnx # 已剥离 NMS,输出 [1,8400,84]
│ ├── yolo26n_simplified.onnx # onnxsim 简化后的原始模型
│ └── yolo26n.qnn236.ctx.bin # 需用户后续在 PC 端转换后放入
├── npu/
│ ├── yolo26_npu.py # 主程序:NPU/CPU 自动切换 + 浏览器 MJPEG 流
│ ├── bench_qnn_demo.py # 使用系统示例模型验证 QNN236+DSP 通路
│ ├── prepare_for_qnn.py # 在设备端剥离 NMS,生成 yolo26n_for_qnn.onnx
│ ├── requirements.txt # 依赖说明
│ └── NPU_SETUP_LOG.md # 本文件
└── outputs/
└── npu/
└── yolo26_npu_preview.jpg
yolo26_npu.py 启动时按以下顺序尝试:
models/yolo26n.qnn236.ctx.bin 存在,则加载 AidLite + QNN236 + TYPE_DSP。models/yolo26n_for_qnn.onnx 存在,则加载 AidLite ONNX CPU,后处理在 CPU 完成。models/yolo26n.onnx,使用 AidLite ONNX CPU。| 后端 | 输入形状 | 输出形状 | 数据类型 | 布局 | 后处理 |
|---|---|---|---|---|---|
| ONNX CPU(原始) | [1, 3, 640, 640] | [1, 300, 6] | float32 | NCHW | 简单阈值 + NMS |
| ONNX CPU(for_qnn) | [1, 3, 640, 640] | [1, 8400, 84] | float32 | NCHW | TopK 解码 + NMS |
| QNN236 DSP | [1, 640, 640, 3] | [1, 8400, 84] | float32 | NHWC | TopK 解码 + NMS |
注:YOLOv26 原始 ONNX 输出是
[1, 300, 6](已内嵌 NMS)。直接转 QNN 时,NMS / TopK 等算子大概率不被支持,因此本项目已把 NMS 剥离,让 NPU 只跑 backbone + head 的卷积部分,后处理在 CPU 完成。
为了最大化帧率,程序拆成 3 个线程:
queue.Queue(maxsize=2),丢弃旧帧,避免推理堆积。latest_frame。multipart/x-mixed-replace 持续推送 latest_frame。http://<犀牛派IP>:9002/http://<犀牛派IP>:9002/streamhttp://<犀牛派IP>:9002/status(返回 FPS、推理耗时、检测数量、后端类型)注意:浏览器前端使用
<img src="/stream">,不要用带时间戳的/frame?t=...,否则路径匹配可能 404。
原始 yolo26n.onnx 内部后处理节点包含:
TopK / GatherElements / Flatten / Mod / Div / Gather / Tile / Cast / Concat
这些算子在 QNN 后端支持有限,直接转换大概率失败。因此我们在设备端用 onnx + onnxsim 把模型截断到 NMS 之前,输出原始检测候选 [1, 8400, 84]。
cd /home/aidlux/aidcode/npu
python3 prepare_for_qnn.py
生成的文件:
models/yolo26n_for_qnn.onnx # 输出 [1, 8400, 84]
models/yolo26n_simplified.onnx
使用 ONNX Runtime 对比:
yolo26n.onnx 输出 [1, 300, 6]yolo26n_for_qnn.onnx 输出 [1, 8400, 84],再按原模型内嵌逻辑做 TopK 后处理结果:
nonempty 行数一致
boxes 最大差异: 0.0
conf 最大差异: 0.0
cls 匹配率: 100%
证明剥离后的模型与原模型完全等价。
运行 npu/bench_qnn_demo.py:
Aidlite library version : Aidlux_Aidlite_C4L_V2.2.8.206_160a6dd_20250820
Aidlite python version : Aidlux_Aidlite_P4L_V2.2.8.206_160a6dd_20250820
✅ QNN236 DSP 模型加载成功
✅ QNN236 DSP 测速完成 (repeats=50)
平均: 14.02 ms | P50: 13.38 ms | P90: 14.22 ms | 等效 FPS: 71.3
结论:NPU/DSP 通路可用,速度约为 CPU ONNX 的 8 倍以上。
运行 npu/yolo26_npu.py(无 QNN 模型时):
平均推理: ~118 ms/帧 | FPS: ~8.5
| 接口 | 状态码 | 结果 |
|---|---|---|
/ | 200 | 正常 |
/status | 200 | JSON 正常 |
/stream | 200 | MJPEG 流正常 |
当前设备上没有 QNN 模型转换工具,需要在一台 x86_64 Linux 开发机上安装 Qualcomm QNN SDK。
export QNN_SDK_ROOT=/opt/qcom/aistack/qnn2.x.x
export PATH=$QNN_SDK_ROOT/bin/x86_64-linux-clang:$PATH
export LD_LIBRARY_PATH=$QNN_SDK_ROOT/lib/x86_64-linux-clang:$LD_LIBRARY_PATH
adb pull /home/aidlux/aidcode/models/yolo26n_for_qnn.onnx ./
# 1. ONNX 转 QNN 中间模型(生成 .cpp + .bin)
qnn-onnx-converter \
--input_network yolo26n_for_qnn.onnx \
--input_dim images 1,3,640,640 \
--output_path yolo26n \
--model_name yolo26n
# 2. 编译成 aarch64 设备端 .so
qnn-model-lib-generator \
-c yolo26n.cpp \
-b yolo26n.bin \
-o yolo26n.so \
-t aarch64-android-clang
# 3. 生成 context binary(.ctx.bin),后端使用 HTP/DSP
qnn-context-binary-generator \
--model_path ./yolo26n.so \
--backend ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnHtp.so \
--binary_file yolo26n.qnn236 \
--output_dir ./out
# 4. 拷贝回犀牛派
adb push ./out/yolo26n.qnn236.ctx.bin /home/aidlux/aidcode/models/
⚠️ 不同 QNN 版本的命令、后端库名可能略有差异。常见后端库名还有
libQnnDsp.so、libQnnHtp.so。如果libQnnHtp.so失败,换成libQnnDsp.so再试。
在 PC 端可用 qnn-net-run 跑一张预处理后的图片,确认输出形状为 [1, 8400, 84]:
qnn-net-run \
--model yolo26n.so \
--backend ${QNN_SDK_ROOT}/lib/x86_64-linux-clang/libQnnHtp.so \
--input_list raw_list.txt \
--output_dir ./output
cd /home/aidlux/aidcode/npu
python3 bench_qnn_demo.py

8.2 运行实时检测流
cd /home/aidlux/aidcode/npu
python3 yolo26_npu.py

然后在同一网络下的浏览器打开:http://<犀牛派IP>:9002


8.3 停止
在终端按 Ctrl+C。
| 问题 | 原因 | 解决方案 |
|---|---|---|
QNN 初始化报错 QNN's .bin model can only use DSP | 设置了 TYPE_NPU 而非 TYPE_DSP | 代码中已固定 AccelerateType.TYPE_DSP |
| 浏览器看不到视频 | 路径写成了 /frame?t=... 或被防火墙拦截 | 使用 /stream,确认端口 9002 可访问 |
| 帧率无法提高 | 单线程串行,推理阻塞采集 | 已使用采集/推理/推流三线程解耦 |
| 检测框位置偏移 | 预处理与模型训练时不一致 | 使用 letterbox + 114 灰边,与 Ultralytics 导出一致 |
| QNN 模型加载失败 | 模型尚未转换或输出 shape 不匹配 | 在 PC 端用 QNN SDK 转换后放入 models/ |
| AidLite 找不到 | Python 环境不对 | AidLite 安装在系统 Python3.10,不要激活其他 venv |
yolo26n.onnx 直接转 QNN 报错 | 内嵌 NMS / TopK 算子不被 QNN 支持 | 使用已剥离 NMS 的 yolo26n_for_qnn.onnx |
TYPE_DSP 调用。yolo26n.onnx 当前只能走 CPU,约 118 ms/帧。npu/ 项目,支持 自动 NPU/CPU 切换、浏览器 MJPEG 实时流、三线程流水线。yolo26n.onnx 剥离 NMS,生成 yolo26n_for_qnn.onnx(输出 [1, 8400, 84]),并验证与原模型数值等价。yolo26n_for_qnn.onnx 转换为 yolo26n.qnn236.ctx.bin,拷贝到 aidcode/models/ 后即可自动启用 NPU 加速。