Skills Plugins MCP Prompt Model 博客 我的中心

qnn-debug

MNN QNN(高通 HTP/NPU)后端的问题定位、修复与算子适配。覆盖运行时报错(1002/6000/1003/6004)、模型转换/算子校验失败、推理结果异常、精度不达标、以及性能问题;并指导为 QNN 新增/适配算子。核心方法:用 MNN2QNNModel --dump_intermediate_outputs 一次性导出 QNN 全部中间张量,与 CPU(fwd=0) 基线逐张量对比,直接定位首个出错算子(旧的 testMNNFromOnnx.py 截断二分已降为回退手段);区分“真 bug/量化/HTP fp16 精度”;新增算子先查 SDK 算子文档(MasterOpDef/HtpOpDefSupplement)再实现。

DeepseekModel Curated skill Quality Excellent · 90 v1.0.0

Get

https://deepseekmodel.com/api/download.php?id=alibaba-mnn-skills-qnn-debug-skill-md&format=skill
Download .skill Standard format with system_prompt and model_config, ready for any agent framework
The actual content of the system_prompt field in the .skill file.
name qnn-debug description MNN QNN(高通 HTP/NPU)后端的问题定位、修复与算子适配。覆盖运行时报错(1002/6000/1003/6004)、模型转换/算子校验失败、推理结果异常、精度不达标、以及性能问题;并指导为 QNN 新增/适配算子。核心方法:用 MNN2QNNModel --dump_intermediate_outputs 一次性导出 QNN 全部中间张量,与 CPU(fwd=0) 基线逐张量对比,直接定位首个出错算子(旧的 testMNNFromOnnx.py 截断二分已降为回退手段);区分“真 bug/量化/HTP fp16 精度”;新增算子先查 SDK 算子文档(MasterOpDef/HtpOpDefSupplement)再实现。 MNN QNN 后端 定位 / 修复 / 适配 SKILL 触发条件 :用户报告 QNN / NPU(高通 HTP)后端任何问题,或要求适配算子。常见表述:"QNN 结果不对/NPU 精度差"、"QNN 报错 1002/6000/1003/6004"、"graphFinalize/graphExecute 失败"、"模型转换失败 / validateOpConfig failed"、"LLM 在 NPU 上输出乱码"、"QNN 性能差"、"给 QNN 加/支持 XXX 算子"、"某算子 QNN 不支持回落 CPU"。 概述 QNN 后端有 两条执行路径 ,排查前先分清在跑哪条(详见 reference.md · 两条执行路径 ): 在线 finalize 路径 :加载普通 .mnn (视觉/CNN),运行时逐算子构图 → graphFinalize → 整图执行。入口多为 ModuleBasic 。报错码常见 1002(finalize)/6000(execute) 。 离线预编译路径 :LLM 经 llmexport.py → generate_llm_qnn.py 生成预编译 QNN 二进制, llm_demo 加载运行。报错码常见 1003/6004(运行时 IO 与图定义不一致) 、转换期 validateOpConfig failed 。 本 SKILL 覆盖三类工作,可组合: A. 数值/精度 & 报错定位 (主线): 建立可信基线 → dump 全部中间张量比对定位首个出错点(回退:截断二分)→ 读误差模式并数值验证 → 区分真 bug / 量化 / HTP fp16 精度 → 打桩定位到代码 。 B. 新增/适配算子 : 先查 SDK 算子文档(MasterOpDef/HtpOpDefSupplement/SupportedOps) → 照现有算子模板实现并注册 → 二分探测验证 。见 新增 / 适配 QNN 算子 。 C. 性能定位 :开 QNN Profile → 找过多 quant/dequant、数据搬运、CPU fallback → 优化。见 性能定位与优化 。 问题分诊(先按症状选路径) 症状 / 错误 路径 去哪一节 error 1002 graphFinalize 失败 / could not create op 在线 步骤 3.5 + 新增/适配算子 error 6000 graphExecute 失败 / 输入全零、结果恒为 bias 在线 先试 shapeMutable=false (见关键约束) + 步骤 3.5 结果不对 / 精度差 / 与 CPU 不一致 在线 步骤 0→4 :dump 中间张量比对(回退:截断二分) error 1003/6004 运行时报错(离线/LLM) 离线 运行时报错 1003/6004 validateOpConfig failed / 转换失败(离线/LLM) 离线 新增/适配算子 (同查 OpDef) + reference 案例 8 LLM 输出乱码 / 数值异常(能跑不报错) 离线 reference 案例 9 · 量化精度 性能不达预期 两者 性能定位与优化 要新增/适配某算子 两者 新增/适配算子 A/B 常交织:定位到"某 OpType 没实现/实现有 bug"就转 B,补完再用 A 验证。 核心原则 先建立可信基线 :任何对比都先确认 CPU fp32 与 ONNX 一致( TEST_SUCCESS / diff ≈ 1e-4)。参考 txt 与 input.txt 必须是 同一次 生成的,否则会误判(见坑 1)。 一次性 dump 全部中间张量 (首选,替代反复截断):用 MNN2QNNModel <sdk> <soc> <arch> <model.mnn> <out> --dump_intermediate_outputs 生成 debug 版模型,它把 每个 QNN native 激活提升为 APP_READ 图输出;在真机上跑一遍即把全部中间张量连同 manifest_*.tsv 落盘,再与 CPU 基线 逐张量 比对,一次定位首个出错算子——不必每探一个点就重转一次模型。截断二分( testMNNFromOnnx.py <model> <tensor> )保留为 回退手段 (dump 跑不起来、或想快速二分少数点时用)。见 步骤 1 。 看误差模式,别只看 diff 数值 :每通道常数、全常数、转置、NaN 各有明确含义(见 reference.md )。用 Python 对照 bias/权重等 数值验证 你的假设,而不是猜。 三方对比区分“bug”还是“精度” :QNN-fp16、 CPU-fp16 (fp16 地板,fp32 累加)、CPU-fp32(可信基线)一起对比( qnn_probe.sh 一次给全)。真 bug 会在某算子处 QNN 突跳而 CPU-fp16 不跳 ;fp16 精度问题是 平滑累积 、经 Pool/GAP 会 下降 。需要时再拿 OpenCL-fp16 交叉验证。 能定位就停 :定位到首个出错算子 + 数值证据即可下结论;改代码前先 git blame 看该处是否近期改动。 闭环沉淀 :每次非平凡定位/修复/适配完成后,若有可复用经验, 主动 按 复盘:回写 reference 追加案例——让本 skill 越用越强。 关键约束 严禁访问 schema/private/ 和 source/internal/ 。 结果异常先试一招 :若模型输入形状固定,先用 shapeMutable=false ( Session_Input_Inside )跑一遍。QNN 在线路径在 Session_Input_User ( shapeMutable=true ,多数入口默认)下有 输入不被拷入、首个算子吃全零 的已知问题; shapeMutable=false 零代码规避。详见 reference.md 案例 1 。 两套构建目录别搞混 : build/ (macOS 主机构建, MNN_QNN=OFF )只提供 MNNConvert 等主机工具;真机 libMNN.so 来自 project/android/build_64 ( MNN_QNN=ON ,NDK arm64)。 改后端代码后要在 build_64 里 make MNN 并 push 它产出的 libMNN.so ,push 错目录的库是最常见的“修了没效果”原因。 前置依赖(环境准备) 依赖 用途 检测 adb + 真机 设备已连接, /data/local/tmp/MNN/ 下已就绪 ModuleBasic.out 、 libMNN.so 、 libQnnHtp*.so 、 libc++_shared.so 等 adb devices ; adb shell ls /data/local/tmp/MNN/ 主机 MNNConvert ONNX→MNN 转换(截断后重转) ls build/MNNConvert (或 which mnnconvert ) python 环境 testMNNFromOnnx.py 依赖 onnx onnxruntime numpy python3 -c "import onnx,onnxruntime,numpy" Android QNN 构建 改后端代码后重编 libMNN.so grep MNN_QNN: project/android/build_64/CMakeCache.txt 应为 ON 设备上运行都要 export LD_LIBRARY_PATH=. (在 /data/local/tmp/MNN/ 下)。 必背:ModuleBasic 命令与后端编号 ./ModuleBasic.out <model.mnn> <dir> <runMask> <forwardType> <loops> <threads> <precision> forwardType :CPU= 0 ,OpenCL= 3 , QNN= 5 (QNN 注册为 MNN_FORWARD_NN ,见 QNNBackend.cpp 的 QNN_FORWARD_TYPE ) precision :Normal= 0 ,High= 1 ,Low= 2 ;QNN 里 mUseFP16 = (precision != High) dir 内需有 input.txt 、 input.json 和 <outputName>.txt 参考;比对阈值为 1% ( absMaxV*0.01 < diffmax 判失败) 用户给的复现命令示例: ./ModuleBasic.out onnx/test.mnn onnx 0 5 1 4 2 (QNN, fp16)。 必背:MNN2QNNModel + 中间张量 dump(定位主力,见步骤 1) MNN2QNNModel <qnnSDKPath> <socId> <hexagonArch> <src.mnn> <outDir> [totalShapeNum] [shape...] [--dump_intermediate_outputs] 常见 SoC:8Gen2→ socId 43 / arch 73 ,8Gen3→ 57 / 75 ,8Elite→ 69 / 79 。 加 --dump_intermediate_outputs 生成 debug 版 离线模型( outDir/<name>.mnn + .bin ):它把 QNN 图里每个 native 张量提升为 APP_READ 输出; 该标志已烘焙进模型 ,运行时无需再传任何 flag,跑一遍即自动 dump。 对普通 CNN 同样适用 :MNN2QNNModel 接受任意 .mnn ,所以在线路径的模型也能用这条离线 dump 通道拿到全部中间张量(在线 ModuleBasic 本身不透传 dump flag)。 输出落盘:默认写到模型旁的 qnn_intermediate_outputs/ ;设环境变量 MNN_QNN_DUMP_DIR 改目录。每次执行产出一个 manifest_NNNNNN.tsv + 每张量一个 raw 文件。详见 reference.md · QNN 中间张量 dump 。 在线路径若要在自己的 runner 里开 dump: backendConfig.flags = MNN_QNN_DUMP_INTERMEDIATE_OUTPUTS ( 1<<16 ,见 MNNForwardType.h )。 ModuleBasic.out 未透传该 flag,故在线模型走上面的 MNN2QNNModel 通道最省事。 离线 / LLM 路径的准备(仅 LLM/NPU 预编译模型需要) source $QAIRT /bin/envsetup.sh # 设 QNN_SDK_ROOT 等 # 1) 导出 NPU 版 MNN(量化):关键 --generate_for_npu --quant_bit 4 --act_bit=16 --sym --smooth --hqq python3 transformers/llm/export/llmexport.py --path <model> -- export mnn --dst_path <out> --generate_for_npu ... # 2) MNN → QNN 预编译离线图(报错→转"转换期校验失败") python3 transformers/llm/export/npu/generate_llm_qnn.py --model <mnn> --soc_id=57 --dsp_arch=v75 # 3) 设备运行 adb shell "cd /data/local/tmp && LD_LIBRARY_PATH=. ./llm_demo <model>/config_qnn.json prompt.txt" 除 libMNN.so 外,离线路径还需 push QNN SDK 运行库: libQnnHtp.so / libQnnSystem.so / libQnnHtpV<arch>Stub.so / libQnnHtpV<arch>Skel.so (来自 $QNN_SDK_ROOT/lib/{aarch64-android,hexagon-v<arch>/unsigned} )。 定位流程 步骤 0 · 建立可信基线 cd build # 主机构建目录,有 MNNConvert python3 ../tools/script/testMNNFromOnnx.py ../models/<model>.onnx # 全模型:生成 onnx/ 参考 + convert_cache.mnn,并做 CPU 自检 末尾应打印 TEST_SUCCESS 。把 convert_cache.mnn → onnx/test.mnn ,连同 input*.txt/input.json/<out>.txt push 到设备,跑 CPU fwd=0 prec=1 确认 diff≈1e-4。 至此确认模型/转换无误,问题在 QNN。 ⚠️ 源 onnx 必须放在 onnx/ 目录之外 (如 cp build/onnx/test.onnx build/src_model.onnx )——否则 testMNNFromOnnx.py 把它拷成 onnx/test.onnx 时报 SameFileError。多输入模型会生成 input0.txt/input1.txt/… ,push 时用 onnx/input*.txt 覆盖。 步骤 1 · 一次性 dump 全部中间张量并比对(首选) 一趟 dump 拿到 QNN 全部中间激活,再与 CPU 基线逐张量比,直接找出 第一个 出错算子——取代"每探一个点就重转一次"的截断循环。 生成 debug 模型并跑一遍 (CNN / LLM 通用): MNN2QNNModel $QNN_SDK_ROOT 57 75 onnx/test.mnn dbg --dump_intermediate_outputs # soc/arch 按真机改 adb push dbg/test.mnn dbg/test.bin /data/local/tmp/MNN/ # 连同 input.txt/input.json/.bin adb shell "cd /data/local/tmp/MNN && LD_LIBRARY_PATH=. MNN_QNN_DUMP_DIR=dump ./ModuleBasic.out test.mnn . 0 5 1 4 2" adb pull /data/local/tmp/MNN/dump ./dump # manifest_*.tsv + 每张量一个 raw 读 manifest 逐张量对比 CPU : manifest_NNNNNN.tsv 每行给出 name / file / data_type / dimensions / quant_encoding / scale / offset 。raw 文件是 QNN 布局(NHWC)+ QNN dtype ,比对前要按 manifest 的 quant(反量化 f = (q - offset) * scale )与布局还原,再和 CPU-fp32 基线( testMNNFromOnnx.py 全模型跑出的中间张量,或 MNNDump2Json 的张量表)对齐。张量名形如 t42 ,可回查 MNN 张量表定位到具体 op。 找突跳点 :按图执行顺序扫每个张量的 diff,第一个" 输入好、输出坏 "且 QNN 远大于 CPU-fp16 地板的即首个出错算子;随后转 步骤 2/3 读误差模式、区分 bug/精度。 细节(manifest 字段、布局/量化还原、局限)见 reference.md · QNN 中间张量 dump 。 回退:截断 + 二分(dump 跑不起来 / 只想快速二分少数点时) 先看图节点顺序: python3 -c "import onnx;m=onnx.load('src_model.onnx');[print(i,n.op_type,list(n.output)) for i,n in enumerate(m.graph.node)]" ;或 MNNDump2Json 看 MNN 侧执行顺序(MNN 名与 ONNX 名可能不同)。 用 scripts/qnn_probe.sh <tensor> [<tensor> ...] 对中间张量截断→转换→push→ 一次并排跑 QNN-fp16 / CPU-fp32 / CPU-fp16 ,对节点序号二分找"输入好、输出坏"的第一个算子。 脚本已 自动注入 shapeMutable=false (否则 QNN 输入不进去,见关键约束)。 陷阱 见 坑 2/坑 3 :换模型前 rm -f .tempcache (QNN 图缓存,脚本已带);单独取 QNN 输出要单独跑 fwd=5 再 cat output/0_0.txt (同一条命令里跑 CPU 会覆盖它)。 步骤 2 · 读误差模式 + 数值验证 把 QNN 输出与参考 reshape 后用 numpy 比对,对照 误差模式速查 。例如“每通道 std=0 的常数”几乎一定是 conv 收到全零输入 → 输出==bias ,可与 ONNX 里该 conv 的 bias 逐通道核对确认。 步骤 3 · 区分“真 bug”还是“HTP fp16 精度” 最简单:直接看 qnn_probe.sh 已经并排给出的 CPU-fp16 列——它是"行为良好的 fp16 地板"(CPU/OpenCL 的 fp16 都用 fp32 累加器)。某点 QNN-fp16 ≫ CPU-fp16 且突跳 = 真 bug; 同步平滑增长 = fp16 累积。 需要 OpenCL 做交叉验证时,再用 scripts/cmp_probe.sh (设备需 libMNN_CL.so )一次输出 QNN 与 OpenCL 的 diff。判据: 现象 结论 某算子处 QNN 误差 突跳 、OpenCL 不跳 该算子 真 bug ,深挖它 QNN 与 OpenCL 平滑同步 增长,经 GlobalAveragePool/Pool 后误差 下降 随机精度噪声,非离散 bug QNN 比 OpenCL 同精度大 ~2.5×/层 并随深度放大 HTP fp16 累加 (OpenCL fp16 用 fp32 累加器) QNN High 与 Low 结果几乎相同 HTP 忽略 fp32 请求 ,底层纯 fp16(见 reference) 步骤 3.5 · graphFinalize / graphExecute 失败时:启用 QNN 错误日志 如果 QNN 报 error code 1002(graphFinalize 失败)或 6000(graphExecute 失败),需要启用 QNN 内部日志来获取详细错误信息: 启用 log callback :在 QNNBackend.cpp 中找到 QnnLog_create 或 log level 设置处,将级别改为 QNN_LOG_LEVEL_ERROR (1)或更详细的级别(2=WARN, 3=INFO, 4=DEBUG)。 重编并测试 : cd project/android/build_64 && make MNN -j8 && adb push libMNN.so /data/local/tmp/MNN/ 查看日志 :运行测试时 grep QNN_LOG ,关注: could not create op → 某算子约束不满足,查 MasterOpDef.html Wrong number of Inputs → 输入数量不对 Op creation failure, total_inputs=N → 检查各 Input 的类型(F16Crouton=fp16, PlainFloat=fp32) 查 SDK 算子文档确认约束 :SDK 根取自编译配置—— SDK=$(grep -i QNN_SDK_ROOT project/android/build_64/CMakeCache.txt | head -1 | cut -d= -f2) (或 $QNN_SDK_ROOT ),再进 $SDK/docs/QNN/ (老版)或 $SDK/docs/QAIRT-Docs/QNN/ (2.48) 下的 OpDef/ 。同目录 HtpOpDefSupplement.html 是 HTP 专属约束权威来源, SupportedOps.html 是各后端支持列表。搜算子名确认输入数量、类型、维度约束。 详见 reference.md · QNN 错误日志 和 QNN 算子约束查询 。 步骤 4 · 打桩定位到代码 / 给结论
Keywords that activate this skill. Click one to copy it.

This skill does not provide trigger words.

The downloaded .skill package contains the following fields.
Field Description
formatFormat tag (skill/v1)
skill_idUnique skill ID
nameSkill name
versionVersion
descriptionDescription
categoryCategories (array)
trigger_wordsTrigger words
tagsTags
sourceSource
source_urlSource URL (this page)
exported_atExported at (set per download)
system_promptSystem prompt body
model_configModel config: provider / model / temperature / max_tokens / top_p
examplesExamples
install_guideImport guide for Coze / Dify / Claude / custom frameworks
The same skill can be exported in different platform formats.
.skill Standard format with system_prompt and model_config, ready for any agent framework Download
.skillpro Enhanced format with scripts, tools, dependencies and hooks Download
.json Plain JSON export with system_prompt and model parameters only Download
Coze Markdown with frontmatter, for Coze platform import Download
Dify Dify DSL, import directly after creating an app Download

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

提交后我们会发送一封确认邮件,点击邮件里的链接才会开始收信。

完全免费,取消任意时间。我们不会发送垃圾邮件。