7,968
社区成员
发帖
与我相关
我的任务
分享实测日期:2026 年 11 月 5 日
在这块 X1 上,YOLOv5 的 CPU 样例可以完成检测,但同一 TFLite 样例选择 DSP 后,第一次在模型加载阶段就失败了。后来我保留原有模型与 SDK,用 strace 找到 ADB 身份的设备访问拒绝,再以已有 aidlux 普通账号执行相同 DSP 分支,完成了 10 次 invoke 和结果图。
最后一路报告的 invoke 均值约为 1.56 ms。这个数字来自真实板端日志;它的范围是样例调用,不代表端到端帧率,也没有替代逐节点硬件 profiling。本文同时记录怎样跑通、怎样复现,以及哪些 NPU 结论仍缺少证据。
本机用户空间是 Ubuntu 22.04.2,架构为 aarch64,Python 为 3.10.12。运行时 AidLite C/Python 版本均打印 V2.5.0.284_5521ce6_20260810。样例、模型和 bus.jpg 均来自板端已有目录,没有另外下载模型或安装框架。
| 资产 | 路径,相对于 /usr/local/share/aidlite/examples/ |
|---|---|
| ONNX 样例 | aidlite_onnx/python/onnx_yolov5_multi.py |
| ONNX 模型 | aidlite_onnx/data/onnx_yolov5_multi/cutoff_yolov5s_640_sigmoid.onnx |
| TFLite 样例 | aidlite_tflite/python/tflite_yolov5_multi.py |
| TFLite 模型 | aidlite_tflite/data/tflite_yolov5_multi/cutoff_yolov5s_640_int8.tflite |
两个模型的 SHA-256 分别为:
ONNX 14490b4ea10caaca2ed4158263bda6bfad6e3736ee76b943cee66973f306141b
TFLite 3f1eb9278f59f059e1ac84195f40ea98f292f2463c032b58e3100fa6a6b00dfb
文件名中的 INT8 不能代替张量记录。这个 TFLite 样例实际使用 UINT8 输入 [1,640,640,3] 和三个 UINT8 检测头;ONNX 样例则是 float32、NCHW 输入 [1,3,640,640]。不同格式、布局与预处理会影响比较范围。
厂商也提供 X1 的 YOLOv5 NPU 教程,其中展示了较早的 AidLite 2.3.x、QNN 2.31 模型与 qnn236 插件组合。本机是 2.5.0.284,不能把教程环境当成本机兼容性证明。本次没有照搬其升级命令。官方部署教程
每次模型启动都使用独立工作区;原脚本复制后不修改,数据链接到原目录,避免覆盖厂商文件。每次事先限定最多启动一次,配置 10 次 invoke、120 秒上限,失败后先保存证据。
| 记录 | 身份与配置 | 实际结果 |
|---|---|---|
| Q0-SAMPLE-01 | ADB uid=2000,ONNX CPU | 加载、10 次 invoke、结果图完成 |
| Q0-SAMPLE-02 | ADB uid=2000,TFLite DSP | HTP delegate 图应用失败,0 次 invoke |
| Q0-SAMPLE-03 | 同一 ADB 身份,同模型 TFLite CPU | 10 次 invoke、结果图,XNNPACK CPU delegate 创建日志 |
| Q0-DIAG-04 | ADB 身份,strace 跟踪同一 DSP 样例 | 再现加载失败,捕获 RPC 节点访问拒绝 |
| Q0-SAMPLE-05 | aidlux uid=1007,含 system 组,同一 DSP 配置 | 加载、10 次 invoke、结果图完成 |

图 1:根据本次五次运行记录绘制的原创诊断图。箭头表示排查顺序;第五次完成的是 DSP 配置路径,逐节点硬件归属仍待核实。
这些记录共同构成一次诊断过程,不是五次性能资格实验。样例参数 1 选择 CPU,TFLite 参数 3 选择 TYPE_DSP;配置还指定 TYPE_TFLITE 和 TYPE_LOCAL。模型运行入口是:
# X1 临时工作区的 python 目录;以下是不同记录的入口,不要整段连续执行。
python3 -B ./onnx_yolov5_multi.py 1
python3 -B ./tflite_yolov5_multi.py 1
python3 -B ./tflite_yolov5_multi.py 3
目录准备、身份与哈希核对、单路径运行及停止方式见已开源的复现步骤。本文命令用于解释历史记录,不表示新增实验已经执行。
ONNX CPU 配置样例报告模型加载完成,10 个 invoke 的进入与返回记录相符,迭代编号 0–9 齐全,并生成了 3 人、1 辆公交车的检测图。日志实际加载了 AidLite ONNX 插件,但没有底层 execution provider profiling,因此这里称为“CPU 配置路径完成”。
stderr 还有一条有用的告警:输入的 memoryview 不连续,绑定层改为连续 bytes 拷贝。程序随后完成推理。这说明当前输入路径包含额外拷贝,不能写成零拷贝实现。
遇到 TFLite DSP 失败后,我又保持同一脚本、模型、图片、冻结库和 ADB 身份,只把参数 3 改为 1。CPU 对照完成 10 次 invoke,stderr 明确记录:
INFO: Created TensorFlow Lite XNNPACK delegate for CPU.
它证明同一 TFLite 资产的 CPU 调用链能够执行,不能替代 HTP 图兼容验证。这是独立 CPU 实验,也不是前一次失败进程的自动 fallback。
最初 TFLite DSP 请求实际加载了 Backend,建立了 Interpreter,随后报错:
Tflite modify graph with htp delegate failed.
StatusCode[110031]
The backend load model failed.
interpreter load model failed !
stderr 提到 delegate 应用失败后恢复原 execution plan,但样例在加载阶段结束,没有进入推理循环、没有结果图。不能把“恢复 execution plan”解释成已经在 CPU 完成推理。
更容易误判的是:这个失败进程的退出码仍然为 0。原脚本的 main() 返回 False,没有相应转换成非零退出码。因此我的完成判据同时检查模型加载、实际 invoke、输出及转移哈希。
当时已看到 ADB 用户缺少 RPC 节点权限,但静态 mode 只是线索。日志中的 op[114] 警告、首次没有缓存、shell 中 ADSP_LIBRARY_PATH 为空,都不足以单独解释 110031;TFLite 库内本来就有 DSP 默认路径字符串。
下一次独立批准的运行只增加受控 strace,过滤文件与 ioctl 调用。原样例与 SDK 不改,120 秒和日志量守卫均未触发,取得 43 个任务 trace;模型仍在相同阶段失败。
trace 显示 QNN TFLite delegate、libQnnHtp.so 和 V73 stub 文件都成功打开。动态库搜索中一些候选目录返回 ENOENT,后面已有成功路径,不能只凭第一条失败就判定缺库。
真正连续失败的是 FastRPC 设备访问:
| 路径 | 结果 | 次数 |
|---|---|---|
/dev/adsprpc-smd-secure | EACCES,权限拒绝 | 4 |
/dev/cdsprpc-smd | ENOENT,路径不存在 | 4 |
/dev/adsprpc-smd | EACCES,权限拒绝 | 4 |
这 12 次 open 出现在 delegate 错误之前,捕获的任务没有成功打开上述 RPC 路径。权限线索由此推进为 uid=2000 这条调用路径中的实际阻塞。tracing 会影响时序,且本次仍无实际 invoke,所以这次运行不提供性能数据。
进一步核对发现,设备节点属于 system,而 ADB uid=2000 不在该组;板端已有 aidlux 普通账号在 system(1000) 组。我在本机终端认证进入这个账号后,启动相同样例,实际运行记录确认:
uid=1007(aidlux) gid=1004(aidlux)
groups=1004(aidlux),27(sudo),1000(system)
本次没有使用账号的 sudo 能力,也没有运行 root 推理或 chmod。模型、图片、样例和相关库共 11 项冻结资产,与此前 CPU、DSP 对照逐项同哈希,原样例参数仍为 3。
这次日志进入了原先没有到达的阶段:
Allocate tensors Success.
detect model load success!
current [0] invoke cost time :2.2780895233154297 ms
current [9] invoke cost time :1.4774799346923828 ms
中间的 1–8 次记录也齐全,最终产生 3 人、1 辆公交车的结果图。图片已回传并按板端哈希核对,SHA-256 为 a083aeb86329e9018d7bf0dfc201b74608ed100d8ce008c2e8b0e9ae4ad5f0e0。
本次真实结果图已在本地归档并目视核对。公开稿不附厂商样例图片,改为给出原日志摘录和结果文件哈希。检测框与场景相符,但没有独立参考张量或标注集精度验收。CPU 与 DSP 的结果 JPEG 字节不同,也不能据此判断张量差异或宣称数值完全一致。
程序还生成了 QNN binary 缓存。可读主文件已回传;两个原生库生成的辅助文件为 aidlux 所有、0600,ADB 无权读取,已记录大小和权限。没有为了回收它们修改权限,缓存重载也没有测试。
| 路径 | 实际 invoke | 均值 | 最小–最大 | 首次 |
|---|---|---|---|---|
| ONNX CPU 配置 | 10 | 149.03 ms | 145.13–159.64 ms | 159.64 ms |
| TFLite CPU 配置,ADB 身份 | 10 | 78.70 ms | 74.30–115.69 ms | 115.69 ms |
| TFLite DSP 配置,aidlux 身份 | 10 | 1.56 ms | 1.47–2.28 ms | 2.28 ms |

图 2:从三份原始 stdout 重算的 30 条计时;圆点包括首次调用,虚线表示本次运行均值。三个子图分别使用不同的纵轴范围,不能用图形高度作比例比较。失败和 trace 运行没有实际 invoke,因此未画作 0 ms。原始数值另附 CSV。
全部数据来自原样例在 invoke() 前后使用 time.time() 的差值,源码已乘 1000;没有另做预热,全部 10 次都保留。加载失败和 strace 运行没有可列入的推理延迟。
这张表用于说明每条路径实际观察到了什么。ONNX 与 TFLite 的模型格式、接口和预处理不同;两次 TFLite 成功运行的账号、环境与时间也不同,没有配对、温度或调度控制。不能直接换算芯片加速倍数。1.56 ms 未覆盖模型加载、预处理或后处理,也未覆盖样例中分别计时的 set_input_tensor 和 get_output_tensor;不能倒数得到端到端帧率或机器人实时能力。
可以确认的结果是:在这份镜像和冻结资产下,已有 aidlux 普通账号的 TYPE_DSP 配置路径完成加载、10 次 invoke 与结果图。 日志包含 HTP 相关检查,本次未见先前 delegate 错误或 CPU XNNPACK/fallback 标记,并生成了 QNN 缓存。
这些证据支持 HTP 配置路径的样例完成,但没有逐节点委托覆盖率、硬件 profiler,或本次成功 RPC 调用的 trace。未见 fallback 日志和低延迟都不能单独证明零 CPU 工作,所以本文不写“全图所有算子均由 NPU 执行”。
先前 RPC 拒绝与普通账号成功共同支持执行身份的重要性;账号切换还改变 HOME、组和环境,未隔离成单个权限位的因果实验。这个结果也没有把 110031 解释成跨模型通用错误,更没有建立 ACT 数值行为、持续负载或跨厂商 Runtime 迁移。
公开项目仓库已经提供环境清单、冻结模型与运行库哈希、有界监督脚本和主机侧核验器。需要自行准备合法取得的相同厂商样例与依赖;仓库不分发模型或 SDK,也不包含设备授权标识。
在 ThinkBook 或其他普通电脑上,可以先做不访问板卡的资料校验:
git clone https://github.com/fwr6926996-commits/rhino-pi-x1-q0.git
cd rhino-pi-x1-q0
git checkout 711f847f309723208fe69a98b28e185af346e423
python3 scripts/verify_public_assets.py
这一步核对 21 个公开文件哈希和 30 条既有计时样本;它没有重新运行推理。板端运行需按复现说明核对自己的环境和授权,不直接复用已经执行过的历史 run_id。
本文配套资料包括 30 条计时 CSV、结构化运行摘要与白名单日志摘录。完整原始日志与 trace 保留本地;摘录保留原行内容并省略无关行,没有把整理后的文本制作成终端截图。
前篇的系统、USB 接入和硬件观察可参阅平台体验文章。