Paddle2onnx
模型转换
动态图ONNX模型导出和静态图ONNX模型导出;
动态图
大致的原理就是动转静,然后再将静态图模型转换为ONNX模型,所以转换的代码上与动转静很相似;
import os
import time
import paddle
# 从模型代码中导入模型
from u2net import U2NETP
# 实例化模型
model = U2NETP()
# 加载预训练模型参数
model.set_dict(paddle.load([path to the pretrained model]))
# 将模型设置为评估状态
model.eval()
# 定义输入数据
input_spec = paddle.static.InputSpec(shape=[None, 3, 320, 320], dtype='float32', name='image')
# ONNX模型导出 (paddle version > 2.0.0)
paddle.onnx.export(model, [path to the save onnx model], input_spec=[input_spec], opset_version=[opset version])
例如通过paddle提供的动态图转静态图的工具,具体如下
python PaddleSeg/export.py
--config PaddleSeg/configs/bisenet/bisenet_cityscapes_1024x1024_160k.yml
--model_path model.pdparams
--save_dir bisenet
save_dir即output输出文件
├── deploy.yaml # 部署相关的配置文件,主要说明数据预处理的方式
├── model.pdmodel # 预测模型的拓扑结构文件
├── model.pdiparams # 预测模型的权重文件
└── model.pdiparams.info # 参数额外信息,一般无需关注
静态图
- 除了动态图模型可以导出为ONNX模型
- 静态图的推理模型当然也可以转换为ONNX模型
- 通过命令行调用如下命令即可完成转换
$ paddle2onnx \
--model_dir [model dir] \
--model_filename [model filename] \
--params_filename [params filename] \
--save_file [save file] \
--opset_version [opset version]
Parameters | Description |
---|---|
model_dir | The directory path of the paddlepaddle model saved by paddle.fluid.io.save_inference_model |
model_filename | [Optional] The model file name under the directory designated by--model_dir |
params_filename | [Optonal] the parameter file name under the directory designated by--model_dir |
opset_version | [Optional] To configure the ONNX Opset version. Opset 9-11 are stably supported. Default value is 9. |
模型可视化
通过netron导入可视化模型结构:
Pytorch2onnx
torch.onnx.export(model, args, f, export_params=True, verbose=False, input_names=None,
output_names=None,do_constant_folding=True,dynamic_axes=None,opset_version=9)
Function Parameters:
1. model:torch.nn.model
要导出的模型
2. args:tuple or tensor
模型的输入参数。注意tuple的最后参数为dict要小心,详见pytorch文档。
输入参数只需满足shape正确,为什么要输入参数呢?因为后面torch.jit.trace要用到,先按下不表。
3. f:file object or string
转换输出的模型的位置,如'yolov4.onnx'
4. export_params:bool,default=True
true表示导出trained model,否则untrained model。默认即可
5. verbose:bool,default=False
true表示打印调试信息
6. input_names:list of string,default=None
指定输入节点名称
7. output_names:list of string,default=None
指定输出节点名称
8. do_constant_folding:bool,default=True
是否使用常量折叠,默认即可
9. dynamic_axes:dict<string, dict<int, string>> or dict<string, list(int)>,default=None
有时模型的输入输出是可变的,如RNN,或者输入输出图片的batch是可变的,
这时我们通过dynamic_axes来指定输入tensor的哪些参数可变。
如input的shape为(b,3,h,w)其中b、h、w可变
output的shape为(b,c,5)其中b、c可变
有几种方式实现:
1) 仅list(int)
dynamic_axes={'input':[0,2,3],'output':[0,1]}
2) 仅dict<int, string>
dynamic_axes={'input':{0:'batch',2:'height',3:'width'},'output':{0:'batch',1:'c'}}
3) mixed
dynamic_axes={'input':{0:'batch',2:'height',3:'width'},'output':[0,1]}
10. opset_version:int,default=9
指定onnx的opset版本,版本过低的话,不支持upsample等操作。
多输入以及不定尺寸问题
- input_names=[‘input1’, ‘input2’], # 定义输入结点的名字,有几个输入就定义几个
- dynamic_axes指定可定的axes
不支持的操作
- onnx只能输出静态图,因此不支持if-else分支。一次只能走一个分支
- onnx不支持步长为2的切片。例如a[::2,::2]
- onnx不支持对切片对象赋值。例如a[0,:,:,:]=b, 可以用torch.cat改写
- onnx里面的resize要求output shape必须为常量
- 不支持自定义的conv,支持conv1d,conv2d,conv3d
- AdaptiveAvgPool2d : 使用AvgPool2d替换
- Expand : torch.cat进行替换
- ReLU6 : 通过relu改写;即 ReLU6 = 6.0 - nn.ReLU(inplace=True)(6.0-relu)
- C++调用时数据类型要是32位浮点型
reference
Tensorflow2onnx
- 后续更新