记录基于NCNN的YOLO4网络转换并推理成功的过程。
NCNN模型结构:
NCNN吃专有的网络格式,所以在使用NCNN对通用网络进行转换之前,必须将其转换为NCNN支持的网路格式。NCNN的模型有两个组成部分,分别是 {name}.param和{name}.bin,他们的作用如图所示:
NCNN Model中,.param是对网络结构的文本描述,用文本工具即可打开,文件内容较小,而*.bin文件保存的是网络权重和偏置数据,要大很多。
以NCNN官方的模型库为例(地址在https://github.com/nihui/ncnn-assets.git)
可以很明显的总结出以上结论,以其中某个*.param为例,用vim打开
可以看到其网络结构。
YOLOV4网络转换:
下载后的darknet目录中包含有yolov4的网络模型,不过它是用darknet识别的格式描述的。
同时我们还要下载yolov4.weights文件。
wget -c https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.weights
之后进入到darknet/cfg目录下,找到yolov4.cfg,他就是我们要转换的yolov4网络的darknet描述。
按照前面推荐的博客要求,编译完NCNN之后,在build/tools/darknet目录下,会生成模型转换工具darknet2ncnn:
转换命令格式为:
darknet2ncnn yolov4.cfg yolov4.weights [output.param] [output.bin] [merge]
默认情况下,我们输入前两个参数即可。
接下来开始转换模型,输入命令:
./darknet2ncnn /home/czl/WorkSpace/dark/darknet/cfg/yolov4.cfg /home/czl/WorkSpace/dark/darknet/cfg/yolov4.weights
默认情况下NCNN yolov4程序使用的是yolov4-tiny.cfg小模型文件,所以我们需要对小模型的权重和模型结构进行转化,就是yolov4-tiny.cfg和yolov4-tiny.weights.
如果没有后续参数,在当前目录下生成的默认名为ncnn.param和ncnn.bin的文件即是转换后的结果文件,可以被NCNN推理引擎识别。
用生成的模型推理:
测试模型,在build/examples目录下,生成的yolov4测试程序,可以用来对模型进行测试,首先将上一步生成的ncnn.bin,ncnn.param重命名为yolov4默认的文件名yolov4-tiny-opt.bin和yolov4-tiny-opt.param
之所以指定这个名字是因为代码中写死了。
之后找一张照片,执行./yolov4 ./person0.jpeg,进行推理,下面是输出结果:
可以看到,我们转换的模型是正确的,推理得到了正确的结果。
需要注意的是,NCNN图形化输出结果需要OPENCV的支持,请确保环境安装了opencv.
YOLOV4小模型转换:
上面转转换的是YOLOV4的大模型,现在转换yolov4-tiny.cfg小模型,小模型权重从这里下载:
https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v4_pre/yolov4-tiny.weights
之后执行推理:
darknet2ncnn编译
NCNN项目下darknet2ncnn.cpp是个程序,它对环境没有特别依赖,可以直接用g++编译器编译运行。
之后就可以进行常规的模型转换操作了。
参照目录中的readme.md文件的使用说明:
值得注意的是merge_output参数,YOLOV3-tiny网络有两个YOLO层输出,merge_output参数表示是否需要将两个YOLO层输出合并为1个,以下截图代表两种情况下的差异,可以看到右边的多出一层YOLO层的输出。
XX_$$$命名符合"层号_行号"的规范.
并且发现,YOLO层是没有编号的,也就是并不像其它层一样,名字前有一个数字序号表明他在原.cfg文件中的顺序。
其它转换:
onnx2ncnn转换工具可以将onnx格式的模型转换为NCNN模型,由于ONNX模型的结构是数据和模型结构在一个文件中,所以输入参数只有一个,而输出则是NCNN模型的两个文件。
执行命令:./onnx2ncnn mnist.onnx
生成的ncnn.bin和ncnn.param是NCNN模型文件。
编译生成的工具有哪些?看如下列表: