VS2019/cmake/ninja
的windows配置,本文并未详细说明故事要从PaddleSeg开始说起
PaddleSeg的链接:https://github.com/PaddlePaddle/PaddleSeg
PaddleSeg 通过指定 config 文件来训练,这是 train.py
的部分其他参数含义:
参数名 | 用途 | 是否必选项 | 默认值 |
---|---|---|---|
iters | 训练迭代次数 | 否 | 配置文件中指定值 |
batch_size | 单卡batch size | 否 | 配置文件中指定值 |
learning_rate | 初始学习率 | 否 | 配置文件中指定值 |
config | 配置文件 | 是 | - |
save_dir | 模型和visualdl日志文件的保存根路径 | 否 | output |
num_workers | 用于异步读取数据的进程数量, 大于等于1时开启子进程读取数据 | 否 | 0 |
use_vdl | 是否开启visualdl记录训练数据 | 否 | 否 |
save_interval | 模型保存的间隔步数 | 否 | 1000 |
do_eval | 是否在保存模型时启动评估, 启动时将会根据mIoU保存最佳模型至best_model | 否 | 否 |
log_iters | 打印日志的间隔步数 | 否 | 10 |
resume_model | 恢复训练模型路径,如:output/iter_1000 | 否 | None |
keep_checkpoint_max | 最新模型保存个数 | 否 | 5 |
训练时,临时修改config文件,可以通过 (文档找不到了,我记得之前有这个来着)-o
参数来指定
在训练之后,得到模型参数文件 model.pdparams
,可以用export.py
来将动态图模型导出为静态图模型
关于PaddleSeg导出脚本 export.py
的使用分析:
https://blog.csdn.net/HaoZiHuang/article/details/125761854
这里插一句:
什么是动态图和静态图?
在深度学习模型构建上,飞桨框架支持动态图编程和静态图编程两种方式,其代码编写和执行方式均存在差异。动态图编程: 采用 Python 的编程风格,解析式地执行每一行网络代码,并同时返回计算结果。在 模型开发 章节中,介绍的都是动态图编程方式。
静态图编程: 采用先编译后执行的方式。需先在代码中预定义完整的神经网络结构,飞桨框架会将神经网络描述为 Program 的数据结构,并对 Program 进行编译优化,再调用执行器获得计算结果。
动态图编程体验更佳、更易调试,但是因为采用 Python 实时执行的方式,开销较大,在性能方面与 C++ 有一定差距;静态图调试难度大,但是将前端 Python 编写的神经网络预定义为 Program描述,转到 C++ 端重新解析执行,脱离了 Python 依赖,往往执行性能更佳,并且预先拥有完整网络结构也更利于全局优化。
以上摘自Paddle官方文档:
https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/jit/index_cn.html
PaddleSeg export.py 使用文档
https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.6/docs/model_export_cn.md
直接这样导出文档,没啥大问题:
# 设置1张可用的卡
export CUDA_VISIBLE_DEVICES=0
# windows下请执行以下命令
# set CUDA_VISIBLE_DEVICES=0
python export.py \
--config configs/bisenet/bisenet_cityscapes_1024x1024_160k.yml \
--model_path bisenet/model.pdparams \
--save_dir output
--input_shape 1 3 512 1024
参数名 | 用途 | 是否必选项 | 默认值 |
---|---|---|---|
config | 配置文件 | 是 | - |
model_path | 预训练权重的路径 | 否 | 配置文件中指定的预训练权重路径 |
save_dir | 保存预测模型的路径 | 否 | output |
input_shape | 设置导出模型的输入shape,比如传入--input_shape 1 3 1024 1024 。如果不设置input_shape,默认导出模型的输入shape是[-1, 3, -1, -1] | 否( 如果预测shape固定,建议指定input_shape参数 ) | None |
with_softmax | 在网络末端添加softmax算子。由于PaddleSeg组网默认返回logits,如果想要部署模型获取概率值,可以置为True | 否 | False |
without_argmax | 是否不在网络末端添加argmax算子。由于PaddleSeg组网默认返回logits,为部署模型可以直接获取预测结果,我们默认在网络末端添加argmax算子 | 否 | False |
这里需要主要的时候,without_argmax
是否需要添加,以及 with_softmax
还有input_shape
是否需要指定,这里留下一个伏笔,指定一个固定的输入有时很有必要
导出之后的文件树:
./output
├── deploy.yaml # 部署相关的配置文件,主要说明数据预处理的方式
├── model.pdmodel # 预测模型的拓扑结构文件
├── model.pdiparams # 预测模型的权重文件
└── model.pdiparams.info # 参数额外信息,一般无需关注
需要说明的是,在Paddle的其他套件或者版本
model.pdmodel
可能会被命名为 __model__
model.pdiparams
可能会被命名为 __param__
导出静态图模型,就可以直接用 paddle inference 推理了
上图是我总结的Paddle Inference 中的关键API, 其实接下来可以看到,几乎所有轻量化框架都遵循这里流程:
具体的实验demo, 可以参考PaddleInference的官方demo
https://paddle-inference.readthedocs.io/en/master/guides/quick_start/python_demo.html
我之前写过:
win10 PaddleLite 编译以及代码跑通复盘:https://blog.csdn.net/HaoZiHuang/article/details/126040571
跑 PaddleLite 一是环境怎么搭建,二是模型怎么转换,三是代码跑通,可直接看上文
到此,我在Paddle 部分的尝试就叙述完毕
使用工具paddle2onnx, 可以将静态图转化为onnx模型:
https://github.com/PaddlePaddle/Paddle2ONNX
paddle2onnx --model_dir saved_inference_model \
--model_filename model.pdmodel \
--params_filename model.pdiparams \
--save_file model.onnx \
--enable_dev_version True
参数 | 参数说明 |
---|---|
–model_dir | 配置包含 Paddle 模型的目录路径 |
–model_filename | [可选] 配置位于 --model_dir 下存储网络结构的文件名 |
–params_filename | [可选] 配置位于 --model_dir 下存储模型参数的文件名称 |
–save_file | 指定转换后的模型保存目录路径 |
–opset_version | [可选] 配置转换为 ONNX 的 OpSet 版本,目前支持 7~16 等多个版本,默认为 9 |
–enable_dev_version | [可选] 是否使用新版本 Paddle2ONNX(推荐使用),默认为 True |
–enable_onnx_checker | [可选] 配置是否检查导出为 ONNX 模型的正确性, 建议打开此开关, 默认为 False |
–enable_auto_update_opset | [可选] 是否开启 opset version 自动升级功能,当低版本 opset 无法转换时,自动选择更高版本的 opset进行转换, 默认为 True |
–input_shape_dict | [可选] 配置输入的 shape, 默认为空; 此参数即将移除,如需要固定Paddle模型输入Shape,请使用此工具处理 |
–deploy_backend | [可选] 量化模型部署的推理引擎,支持 onnxruntime、tensorrt 或 others,当选择 others 时,所有的量化信息存储于 max_range.txt 文件中,默认为 onnxruntime |
–version | [可选] 查看 paddle2onnx 版本 |
注意 –input_shape_dict
参数即将移除
这个转化工具需要注意的不多,可能是某些算子不支持,比如 adaptivepooling 不支持:
解决方式,可以自定义一个来替换:
对于接触部署不多的同学,我觉得这张图这段话很有用,摘自mmdeploy官方文档:
深度学习模型的结构通常比较庞大,需要大量的算力才能满足实时运行的需求。模型的运行效率需要优化。 因为这些难题的存在,模型部署不能靠简单的环境配置与安装完成。经过工业界和学术界数年的探索,模型部署有了一条流行的流水线:
为了让模型最终能够部署到某一环境上,开发者们可以使用任意一种深度学习框架来定义网络结构,并通过训练确定网络中的参数。之后,模型的结构和参数会被转换成一种只描述网络结构的中间表示,一些针对网络结构的优化会在中间表示上进行。最后,用面向硬件的高性能编程框架(如 CUDA,OpenCL)编写,能高效执行深度学习网络中算子的推理引擎会把中间表示转换成特定的文件格式,并在对应硬件平台上高效运行模型。
这一条流水线解决了模型部署中的两大问题:使用对接深度学习框架和推理引擎的中间表示,开发者不必担心如何在新环境中运行各个复杂的框架;通过中间表示的网络结构优化和推理引擎对运算的底层优化,模型的运算效率大幅提升。
onnx模型只是一个通用的中间表示
ONNX (Open Neural Network Exchange)是 Facebook 和微软在2017年共同发布的,用于标准描述计算图的一种格式。目前,在数家机构的共同维护下,ONNX 已经对接了多种深度学习框架和多种推理引擎。因此,ONNX 被当成了深度学习框架到推理引擎的桥梁,就像编译器的中间语言一样。由于各框架兼容性不一,我们通常只用 ONNX 表示更容易部署的静态图。
我们可以将 tf/torch/paddle
的模型导出为onnx,使用Netron (开源的模型可视化工具) 来查看模型网络结构:
https://netron.app/
因为我们很少直接用 onnx api 直接创建模型,而是通过AI框架(Paddle/Torch/TF等)直接导出 onnx 模型,所以关于 onnx API 无需叙述,可参阅 onnx github:
https://github.com/onnx/onnx
可以用这二者对onnx模型做简化:
https://github.com/daquexian/onnx-simplifier
https://github.com/onnx/optimizer
但是实验表明,速度反而变慢了…
我们只需要关心 onnx模型怎么在跑起来,也就是 onnxruntime
的环境配置
若要安装适用于 Python 的 onnxruntime ,请使用以下命令之一:
pip install onnxruntime # CPU build
pip install onnxruntime-gpu # GPU build
若要在 Python 脚本中调用 onnxruntime,请使用:
import onnxruntime
session = onnxruntime.InferenceSession("path to model")
模型附带的文档通常会指示有关使用模型的输入和输出。 还可使用可视化工具查看模型。 onnxruntime 还可以查询模型元数据、输入和输出:
session.get_modelmeta()
first_input_name = session.get_inputs()[0].name
first_output_name = session.get_outputs()[0].name
若要推理模型,请使用 run
,并传入要返回的输出列表(如果需要所有输出,则保留为空)和输入值的映射。 结果是输出列表。
results = session.run(["output1", "output2"], {
"input1": indata1, "input2": indata2})
results = session.run([], {"input1": indata1, "input2": indata2})
有关完整的 Python API 参考,请参阅 onnxruntime 参考文档。
https://onnxruntime.ai/docs/api/python/api_summary.html
可以使用
>>> import onnxruntime
>>> onnxruntime.get_available_providers()
["CPUExecutionProvider", "CUDAExecutionProvider", "TensorrtExecutionProvider"]
来查看本机支持的推理provider
若本机有CUDA环境,则会有 "CUDAExecutionProvider"
若本机有TensorRT环境,则会有 "TensorrtExecutionProvider"
我之前写了
windows MNN 的使用流程(Python版): https://blog.csdn.net/HaoZiHuang/article/details/126146550
mnn 之后的版本会提供 pymnn, 可以用 Python API 调用 opencl, vulkan 后端的编译的mnn.lib
参考github issue:
https://github.com/alibaba/MNN/issues/2010
使用Python版本建议直接pip安装,使用C++版本建议自行根据文档进行编译
还是那三个问题:
Python环境直接pip就好,转换模型pip之后会提供命令行工具mnnconvert
, 可以用该工具进行转换:
MNNConvert -f ONNX --modelFile output.onnx --MNNModel output.mnn --bizCode biz
其半精度操作也很简单,直接加上 --fp16
即可
接下来就是怎么推理:
https://blog.csdn.net/HaoZiHuang/article/details/126146550
文中提供了验证demo,可以直接down下来测试
然后就是原文也提供了convert 和 推理引擎的编译过程,供参考
TensorRT是重头戏,我花费了最长的时间,首先是环境的部署:
windows 版本:
https://blog.csdn.net/HaoZiHuang/article/details/125795230
linux 版本:
https://blog.csdn.net/HaoZiHuang/article/details/126046171
关于模型的转换,我尝试了 onnx 模型转换为 trt/engine 模型
.trt / .engine 文件之后后缀不同,内容完全一样
按照官方文档的Python API 通过 onnx parser 来转换,我尝试了,不太行
我是用 trtexec 来进行转换的
同时有些需要注意的地方:
等等,都可参考下文:
https://blog.csdn.net/HaoZiHuang/article/details/125859167
建议直接查看方法二
此文引出了各种东西,同时 TensorRT 也有官方中文版,不过我看了一下,就是直接扔到谷歌翻译里的感觉,我甚至扔到谷歌翻译试了一下,确实是谷歌翻译翻译的hhh
中文版:
https://developer.nvidia.com/zh-cn/blog/author/ken-he/
英文版:
https://docs.nvidia.com/deeplearning/tensorrt/developer-guide/index.html#overview