训练好模型后,对于如何部署模型,我很困惑。后面问了大佬,大佬让我尝试把训练得到的pt和pth文件转换成onnx,最后转为ncnn后,把ncnn部署在vs上。
提供一下大佬推荐的代码:
tx的ncnn有yolov5的部署教程和案例
和另一个大佬推荐的教程(这个我没试过,当时我已经换了另外的方法并且准备答辩了):
【通用目标检测微信小程序(以yolov5作为后端演示)-哔哩哔哩】
接下来附上我的转换过程及报错等:
很多转换代码参考这位大佬的众多文章:https://blog.csdn.net/nihate?type=blog
和他的代码:https://github.com/Tencent
教程:http://t.csdn.cn/o3F0V
配置相应的网络模型,需要把网络模型yaml文件转换成py文件
打开convert_yaml2py.py(该代码用于把网络模型yaml文件转换成py文件:http://t.csdn.cn/SWv6O)
choices = [‘yolov5s’, ‘yolov5l’, ‘yolov5m’, ‘yolov5x’]
修改成:choices = [ ‘yolov5l’]
运行convert_yaml2py.py,得到yolov5l.py文件:
检查opencv版本:
>>> import cv2
>>> print( cv2.__version__ )
根据教程所写,创建My_YOLO函数,代码如教程中所示。
修改convert_onnx中的类型名,改成自己模型的名字:
把自己模型结构的py文件名称替换yolov5s,这里就是上面需要My_YOLO函数的原因:
换成:
修改一部分:
34行的default和 choices里面的模型名都改为自己的模型名,41行也要改模型名:
运行后报错:
Traceback (most recent call last):
File "D:/PycharmProject/yolov5-dnn-cpp-python-main/convert-onnx/convert_onnx.py", line 57, in <module>
if not operator.eq(a.shape, b.shape):
AttributeError: 'collections.OrderedDict' object has no attribute 'shape'
标记一下,然后Debug查看:
通过对比原作者用的pth文件加载出来的数据,其中 的OrderedDict有序字典就是要用的。
原作者的是已经排好的有序字典:
我的还包含有其他数据:
而有序字典是在‘model’中,所以把model提取出来另外赋值:
最终,加载模型这段代码如图:
成功:
其实是没仔细看该代码的使用要求:
在yolov5的源代码(随意一个)主目录中新建py文件,复制代码进去:
import torch
from collections import OrderedDict
import pickle
import os
device = 'cuda' if torch.cuda.is_available() else 'cpu'
if __name__ == '__main__':
choices = ['best'] #修改yolov5s为你自己模型的名字
modelfile = choices[0] + '.pt'
utl_model = torch.load(modelfile, map_location=device)
print(utl_model)
utl_param = utl_model['model'].model
torch.save(utl_param.state_dict(), os.path.splitext(modelfile)[0] + '.pth')
own_state = utl_param.state_dict()
print(len(own_state))
numpy_param = OrderedDict()
for name in own_state:
numpy_param[name] = own_state[name].data.cpu().numpy()
print(len(numpy_param))
with open(os.path.splitext(modelfile)[0] + '_numpy_param.pkl', 'wb') as fw:
pickle.dump(numpy_param, fw)
把要转化的也丢进主目录下,运行:
查看另一个模型:
不用另外提取有序字典,用下面这一句就可:
成功:
ncnn 是一个为手机端极致优化的高性能神经网络前向计算框架。ncnn 从设计之初深刻考虑手机端的部署和使用。无第三方依赖,跨平台,手机端 cpu 的速度快于目前所有已知的开源框架。基于 ncnn,开发者能够将深度学习算法轻松移植到手机端高效执行,开发出人工智能 APP,将 AI 带到你的指尖。ncnn 目前已在腾讯多款应用中使用,如QQ,Qzone,微信,天天P图等。
在windows下编译ncnn前需要先下载编译protobuf-3.4.0,下载后解压,编译命令过程如下:
cd D:/protobuf-3.4.0 #cd <protobuf-root-dir>
mkdir build-2022 #建文件夹
cd build-2022
cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=%cd%/install -Dprotobuf_BUILD_TESTS=OFF -Dprotobuf_MSVC_STATIC_RUNTIME=OFF ../cmake
nmake
nmake install
编译protobuf-3.4.0前要先下载cmake
官网:https://cmake.org/download/
cmake下载:https://cmake.org/files/
安装教程:http://t.csdn.cn/I6VOc
安装后重启
尝试解决(可跳过):
cmake -G "MinGW Makefiles" ../
报错:CMake Error: Error: generator : MinGW Makefiles
安装MinGW并配置环境
后面去stackoverflow上面问了大佬关于“cmake:cl is not a full path and was not found in the PATH. ”的问题,发现是visual studio 编译器的路径没有放:
输入命令:nmake
输入命令:nmake install
编译成功后,后会产生build-2022文件夹以及该文件夹下的若干文件夹及文件:
编译完后再编译ncnn,编译命令过程如下:
git clone https://github.com/Tencent/ncnn.git
cd ncnn
git submodule update --init # 如果这一步一直更新不了的话,需要把cmake编译时候的-DNCNN_VULKAN设置为OFF,不然编译不通过
mkdir build && cd build
cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=%cd%/install -DProtobuf_INCLUDE_DIR=D:/protobuf-3.4.0/build-2022/install/include -DProtobuf_LIBRARIES=D:/protobuf-3.4.0/build-2022/install/lib/libprotobuf.lib -DProtobuf_PROTOC_EXECUTABLE=D:/protobuf-3.4.0/build-2022/install/bin/protoc.exe -DNCNN_VULKAN=OFF ..
nmake
nmake install
(protobuf-root-dir 是刚才编译的protobuf的目录,根据自己的来修改。)
开始编译:git clone https://github.com/Tencent/ncnn.git
失败,进入网站:https://codeload.github.com/Tencent/ncnn/zip/refs/heads/master
下载并解压,进入git cmd,输入命令:
cd D:\ncnn
git submodule update --init
问题:fatal: not a git repository (or any of the parent directories): .git
提示说没有.git这样一个目录,解决办法如下:git init
打开VS2019的X64命令行,进入ncnn根目录:
mkdir build-2022
cd build-2022
cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=%cd%/install -DProtobuf_INCLUDE_DIR=D:/protobuf-3.4.0/build-2022/install/include -DProtobuf_LIBRARIES=D:/protobuf-3.4.0/build-2022/install/lib/libprotobuf.lib -DProtobuf_PROTOC_EXECUTABLE=D:/protobuf-3.4.0/build-2022/install/bin/protoc.exe -DNCNN_VULKAN=OFF ..
nmake
nmake install
在ncnn/tools/onnx/路径下得到onnx2ncnn.cpp文件:
同时在ncnn/build/tools/onnx/目录下得到运行文件onnx2ncnn,如下图,运行这个onnx2ncnn文件就可以将onnx模型转化为ncnn模型了:
下载并安装opencv
官网:https://opencv.org/releases/
安装后放路径:
安装 onnx-simplifier
pip3 install onnx-simplifier
报错:WARNING: You are using pip version 22.0.3; however, version 22.0.4 is available.
You should consider upgrading via the ‘D:\Anaconda\python.exe -m pip install --upgrade pip’ command.
原因:pip版本过低导致安装第三方库失败
python -m pip install --upgrade pip -i https://pypi.douban.com/simple
将模型文件拖入浏览器页面即可显示。将文件拖入浏览器,可看到模型结构,网站:
https://netron.app/
下载了一个简化代码运行不成功,就直接在它的onnxsim文件夹里面新建了一个sim文件,把要简化的onnx模型放入onnxsim文件夹里,直接运行sim文件。加载onnx文件,simplify处理后重新保存,代码如下(我放了个资源包):
import onnx
from tables import leaf
from onnxsim import simplify
onnx_model = onnx.load('leaf.onnx') #output_path:path + model_name + '.onnx'
model_simp, check = simplify(onnx_model)
assert check, "Simplified ONNX model could not be validated"
onnx.save(model_simp, 'leafsim.onnx')
print('finished exporting onnx')
使用onnx2ncnn工具进行转换,进入 ncnn/build/tools/onnx 路径下再输入./onnx2ncnn 命令。 其中 model.onnx 是需要转为ncnn的简化后的 onnx 模型,model.param 和 model.bin 即为转为 ncnn 后输出的两个文件,注意这两个文件的顺序不能写反了!
cd D:\ncnn\build-2022\tools\onnx
onnx2ncnn C:/Users/priesty/Desktop/onnx2ncnn/bestsim.onnx C:/Users/priesty/Desktop/onnx2ncnn/bestsim.param C:/Users/priesty/Desktop/onnx2ncnn/bestsim.bin (命令错误)
提示:Usage: onnx2ncnn [onnxpb] [ncnnparam] [ncnnbin]
用法:onnx2ncnn [onnxpb] [ncnnparam] [ncnnbin]
把要用的onnx文件复制到该目录中,然后:
onnx2ncnn [bestsim.onnx] [bestsim.param] [bestsim.bin] (命令还是错误 )
报错:
open failed [bestsim.onnx]
read_proto_from_binary failed
正确命令:onnx2ncnn bestsim.onnx bestsim.param bestsim.bin
搞定了
onnx2ncnn leafsim.onnx leafsim.param leafsim.bin
其中param存放的是模型结构,可以理解为网络的配置文件,bin存放的是类似卷积这些op的权重文件,可以理解为网络的参数(各种权重)文件。
动态尺寸推理
最后 Reshape 层把输出grid数写死了,根据 ncnn Reshape 参数含义,把写死的数量改为 -1 便可以自适应
替换后用 ncnnoptimize 过一遍模型,ncnnoptimize 是优化整个网络模型,顺便转为 fp16 存储减小模型体积。ncnnoptimize 工具会自动将无用的 MemoryData 删除,并且自动将最终的 blob count 设置为合适的数量,所以前面步骤中不需要自己改 blob count。
进入 ncnn/build/tools 路径下再输入./ncnnoptimize 命令
ncnnoptimize /home/jiao/yolov5/yolov5s-best.param /home/jiao/yolov5/yolov5s-best.bin /home/jiao/yolov5/yolov5s-best-opt.param /home/jiao/yolov5/yolov5s-best-opt.bin 0
我把 bestsim.param和 bestsim.bin放入ncnn/build/tools文件中:
命令如下:ncnnoptimize bestsim.param bestsim.bin bestopt.param bestopt.bin
报错:usage: ncnnoptimize [inparam] [inbin] [outparam] [outbin] [flag] [cutstart] [cutend]
其中,flag指存储类型,0 代表 float32, 65535代表 float16。[inparam] [inbin] 是之前生成的文件,[outparam] [outbin] 是将要生成的文件
新命令:ncnnoptimize bestsim.param bestsim.bin bestopt.param bestopt.bin 0
优化前:
优化后:
另一个模型:
ncnnoptimize leafsim.param leafsim.bin leafopt.param leafopt.bin 0