赞
踩
ncnn的.param和.bin文件的读取,参考这个基本上可以触类旁通
大概找了找全网使用ncnn框架导出权重模型的博客(可以参考的只有2篇,一篇过时了,没法儿使用;另一篇的函数重载似乎提及了也没什么用处,因为另一篇提到的函数重载事实上在ncnn中已经代码体现了,但是未能深入逐层输出,而且我运行了发现出了bug),翻了ncnn的github,有大量技术发烧友都在追求ncnn工具导出后的FP16、INT8模型的权重、偏置参数读取,然而苦于ncnn框架规模实在太大,C++技术高度密集,权重输出确实不太容易。
我在本文中利用线上开源的onnx转ncnn FP16的网站将nanodet-plus.onnx模型转变为.param和.bin,并在此基础上对ncnn进行修改和编译,验证框架使用我修改后的批量目标检测的nanodet.cpp,该部分代码不提供,我只提供结果。另外,不对ncnn进行深入分析,本文只提供如何输出权重值的思路和代码实现。再次重申:
本文只提供:
1、ncnn中我用于输出权重值的修改后若干文件(您可以替换之后重现我的结果);
2、nanodet-plus在ncnn框架下使用ncnn格式的模型作为批量图片的目标检测的一个输入(图片是另一个输入)的结果(您可以使用nanodet-plus官方原装的单张图片的目标检测作为测试框架,道理一样,不用纠结,我懒得改了);
3、提供权重输出的思路(相信会对你有帮助);
本文不提供:
1、批量图片的目标检测代码;
2、不提供算法优化;
3、不提供整个模型输出的方案;
这边可以直接参考nihui的ncnn github官网来解读,不过要是不想看英文,想直接快速上手,直接看下面。
图片来源:https://blog.csdn.net/qq_25105061/article/details/131457787
layer:描述网络一共有多少层,例如:ReLU、Conv 都叫一个layer;
blob:表示数据节点,例如一个Conv就有一个输入blob和输出blob;
bottom_count:当前层接收输入blob的层个数;
top_count:将当前层的输出作为输入blob的层个数;
bottom_name:当前层输入数据的生产层名字;
blob_name: 消费当前的输出结果的层名字;
差不多够用!继续往下!
根据文件引用关系:net.cpp的line1293、line1736分别指向load_param和load_model的最接近Layer类的模型和参数加载函数,随后lin1293的load_param指向line1449的pd.load_param(dr),该函数需要到paramdict.cpp中寻找,找到int Net::load_param()从而配合line1293该函数的其余内容完整输出.param文件。随后看load_model,到net.cpp的line1763,找到layer->load_model,该函数需要到layer.cpp和layer.h中寻找定义和声明,layer就是基类,因此我们随便找一个基于Layer基类的派生类Convolution,寻找convolution.cpp,查找其内的load_param和load_model,我们只关注load_model,因为load_param过于直观了,load_model需要回到modelbin.cpp中查找Mat ModelBin::load(int w, int h, int type) const,我们根据“Mat mret = m.reshape(w, h);”查找mat.cpp中的reshape函数,并设置使用指针来输出权重值。
图示cout代码输出.param中的layer_cout和blob_cout。
图示cout代码用于确认逐层layer参数载入,且可以确认参数载入来自于Layer类,由于Layer已经是基类,因此我们随便选择Layer派生类比如Convolution。
这部分是load_param的内容。
这部分是load_model的内容。
我们可以看到weight_data和bias_data都通过mb类实例下的load函数得到,我们可以确认mb实例是对ModelBin的例化。接下来我们看ModelBin类定义。
有效的部分是该load函数,我对此处进行了修改,原内容直接返回m.reshape(w, h),我多增加一步以确定是否经过该步。接下来我们确认确实是reshape函数起作用,因此我们需要查找Mat类定义。
其中起作用的包含两部分:
此处红色框内我对权重值进行了打印!
最后的部分输出结果:
其实前面两部分基本上对输出权重做了流程化的介绍,接下来就是把ncnn中已经更改的文件、终端输出的内容和实现步骤讲讲,该拿出来的拿出来,该讲明白的讲明白。
从添加更改文件后的命令如下:
1、重新编译并安装ncnn:
mkdir build
cd build
cmake ..
make -j32
make install
2、增加路径:export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
3、在编译运行nanodet-ncnn工程之前:
export ncnn_DIR=/root/autodl-tmp/ncnn/build/install/lib/cmake/ncnn
4、清除./nanodet/demo_ncnn/build的内容:rm -rf *
5、加入.param和.bin:cp -r ../nanodet.param ../nanodet/model ./
6、编译工程:
cmake ..
make
7、运行工程(以批量检测为例):
./nanodet_demo 1 /root/autodl-tmp/nanodet/demo_ncnn/pic/(这个参考nanodet官方)
我应该已经上传到csdn了。
简单对ncnn的权重参数进行了输出,够累,只能说对AI编译器的理解又进了一步!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。