ncnn icon indicating copy to clipboard operation
ncnn copied to clipboard

ncnn2mem内存加载的yolo11模型识别失败

Open OkaAir opened this issue 3 months ago • 10 comments

detail | 详细描述 | 詳細な説明

参考https://github.com/Tencent/ncnn/blob/master/examples/yolo11.cpp 使用ncnn2mem转换param和bin生成的头文件识别失败(yolo11n.ncnn.param yolo11n.ncnn.bin 都是官方示例提供的)

ncnn2mem yolo11n.ncnn.param yolo11n.ncnn.bin \
    ncnn_model/yolo11n_id.h ncnn_model/yolo11n_mem.h

修改的4行如下(注释为源文件示例),对yolo11官方提供的bus.jpg识别数量为0,(使用param和bin识别数量为5)

#include "yolo11n_id.h"
#include "yolo11n_mem.h"
yolo11.load_param(yolo11n_ncnn_param_bin); // yolo11.load_param("yolo11n.ncnn.param");
yolo11.load_model(yolo11n_ncnn_bin); // yolo11.load_model("yolo11n.ncnn.bin");
ex.input(yolo11n_ncnn_param_id::BLOB_in0, in_pad); // ex.input("in0", in_pad);
ex.extract(yolo11n_ncnn_param_id::BLOB_out0, out); // ex.extract("out0", out);

请问各位大佬,是转换的不对还是代码有另外需更改的地方呢

OkaAir avatar Nov 24 '25 08:11 OkaAir

Hi @OkaAir! I'm Dosu and I’m helping the ncnn team.

你的代码修改方式是正确的:用 ncnn2mem 生成的头文件时,应该用 load_param/load_model 传入二进制数组,并用 id.h 里的枚举值替换字符串 blob 名称。这和官方文档、AlexNet 示例一致,不需要额外的代码改动,只要保证头文件数据在推理期间有效即可(zero-copy)参考

但你遇到“内存加载模型推理结果为0,文件加载正常”的情况,结合社区反馈和 ncnn 近期讨论,这通常不是 ncnn2mem 转换本身的问题,而是 GPU/Vulkan 环境下的同步问题,尤其是在设备不支持 VK_KHR_push_descriptor 时,ncnn 的 GPU 内存同步机制可能导致推理结果异常(如 box 坐标全错、置信度正常但无有效检测)详细分析

排查建议:

  1. 先用 CPU(opt.use_vulkan_compute = false)跑一遍,确认 CPU 下内存加载和文件加载结果一致。如果一致,说明 ncnn2mem 转换和代码集成没问题。
  2. 如果只在 GPU 下出错,优先怀疑同步问题。可以尝试在推理前后调用 net.clear(),或只做一次推理(首次推理通常正常,后续异常)。
  3. 若必须用 GPU,可参考社区 workaround:在关键层后手动插入 submit_and_wait() 或 barrier,或临时切回 CPU 跑模型。

总结:你的 ncnn2mem 用法和代码集成方式是对的,问题大概率是 GPU 内存同步导致的推理异常,而不是转换或代码集成错误。可以先用 CPU 验证模型和流程,确认无误后再排查 GPU 环境和同步问题。

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Open in Cursor Join Discord Share on X

dosubot[bot] avatar Nov 24 '25 08:11 dosubot[bot]

是纯CPU环境运行的

yolo11.opt.use_vulkan_compute = false;

OkaAir avatar Nov 24 '25 08:11 OkaAir

纯CPU模式下,ncnn2mem生成的头文件加载模型和直接加载param/bin文件,推理结果应完全一致(代码路径和行为是一样的)参考。你遇到“文件加载正常,内存加载为0”的情况,常见原因有:

  1. 头文件和param/bin文件不匹配(比如param/bin更新后没重新生成头文件)。
  2. 头文件内容损坏或不完整(如ncnn2mem生成异常、手动编辑过)。
  3. 内存数组在推理期间被释放或未对齐(ncnn2mem生成的数组必须整个生命周期都有效)。
  4. ex.input/ex.extract用的blob id和实际模型不一致(比如用了旧的id.h)。

建议排查:确认头文件和param/bin完全一一对应,重新用ncnn2mem生成一遍头文件再测试;确保头文件里的数组在推理期间始终有效;核查ex.input和ex.extract用的blob id和模型输入输出一致。如果还有问题,可以贴出生成的头文件和最小复现代码,便于进一步定位。

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Open in Cursor Join Discord Share on X

dosubot[bot] avatar Nov 24 '25 08:11 dosubot[bot]

yolo11n_id.h.txt 这是yolo11n_id.h文件

然后执行

ncnn2mem yolo11n.ncnn.param yolo11n.ncnn.bin \
    yolo11n_id.h yolo11n_mem.h

额外生成了yolo11n.ncnn.param.bin文件 测试时发现 yolo11.load_param_bin("yolo11n.ncnn.param.bin"); 和 yolo11.load_param("yolo11n.ncnn.param"); 识别效果不一样,load_param_bin没有识别到任何物体,而load_param正确识别了物体

OkaAir avatar Nov 24 '25 08:11 OkaAir

你遇到的现象是 ncnn 设计上的常见“坑”:load_param_bin("yolo11n.ncnn.param.bin") 和 load_param("yolo11n.ncnn.param") 不是等价的,二者加载的文件格式完全不同,不能混用。ncnn2mem 生成的 .param.bin 文件格式和 load_param_bin 期望的标准 binary param 格式并不完全一致,直接用 load_param_bin 加载 ncnn2mem 生成的 .param.bin 文件,推理结果往往异常或全为 0,这是社区已知现象(详见官方 issue 讨论相关案例)。

正确用法如下:

  • 加载文本格式 param 文件(.param):用 load_param("xxx.param")。
  • 加载 ncnn2mem 生成的内存头文件:用 load_param(数组指针)。
  • 加载标准 binary param 文件(用 param2bin 工具生成的 .param.bin):用 load_param_bin("xxx.param.bin")。

ncnn2mem 生成的 .param.bin 文件并不是标准 binary param 格式,不能直接用 load_param_bin 加载,否则推理会失败或输出全 0。你只需要用 load_param 加载文本 param 文件,或者用 load_param(头文件里的数组指针),不要用 load_param_bin 加载 ncnn2mem 生成的 .param.bin 文件即可。

总结:ncnn2mem 生成的 .param.bin 文件不要用 load_param_bin 加载,保持用 load_param 或 load_param_mem(内存数组)即可,推理结果就会和直接加载 .param 文件一致。参考

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Open in Cursor Join Discord Share on X

dosubot[bot] avatar Nov 24 '25 08:11 dosubot[bot]

头文件和param/bin文件不匹配(比如param/bin更新后没重新生成头文件)。 头文件内容损坏或不完整(如ncnn2mem生成异常、手动编辑过)。 内存数组在推理期间被释放或未对齐(ncnn2mem生成的数组必须整个生命周期都有效)。 ex.input/ex.extract用的blob id和实际模型不一致(比如用了旧的id.h)。

排查后没有出现这些问题,都是最新的模型生成的

OkaAir avatar Nov 25 '25 08:11 OkaAir

用的是param文件是不是有 Reshape Tensor.view_6 2 1 141 128 142 6="1w,1h,128" 它的具体实现为 v_106 = v_105.view(1, 128, v_95.size(2), v_95.size(3)) 但我参考官方的文档,Reshape并没有6这个参数,我调试用ncnn2mem导出后是在这一行输出空的 猜测param支持了动态的参数,但ncnn2mem导出的方式还不支持动态参数

jingmouZhong avatar Dec 03 '25 06:12 jingmouZhong

使用param的文件是不是有 Reshape Tensor.view_6 2 1 141 128 142 6="1w,1h,128" 它的具体实现为 v_106 = v_105.view(1, 128, v_95.size(2), v_95.size(3)) 但是我参考官方的文档,Reshape并没有6个这个参数,我用ncnn2mem导出后调试是在这个行空预测的 猜测参数支持了动态的参数,但是ncnn2mem导出的方式不支持动态参数

对,有一行Reshape Tensor.view_6 2 1 141 128 142 6="1w,1h,128"

OkaAir avatar Dec 04 '25 06:12 OkaAir

使用param的文件是不是有 Reshape Tensor.view_6 2 1 141 128 142 6="1w,1h,128" 它的具体实现为 v_106 = v_105.view(1, 128, v_95.size(2), v_95.size(3)) 但是我参考官方的文档,Reshape并没有6个这个参数,我用ncnn2mem导出后调试是在这个行空预测的 猜测参数支持了动态的参数,但是ncnn2mem导出的方式不支持动态参数

对,有一行Reshape Tensor.view_6 2 1 141 128 142 6="1w,1h,128"

感谢报告!

nihui avatar Dec 04 '25 06:12 nihui

https://github.com/Tencent/ncnn/pull/6440

nihui avatar Dec 05 '25 07:12 nihui