未验证 提交 81ca8ecd 编写于 作者: N neonhuang 提交者: GitHub

add paddle2onnx doc (#5446)

* update paddle2onnx readme
上级 3b7e01b1
# Paddle2ONNX 推理
# 目录
- [1. 简介](#1)
- [2. Paddle2ONNX推理过程](#2)
- [2.1 准备推理环境](#2.1)
- [2.2 模型转换](#2.2)
- [2.3 ONNX 推理](#2.3)
- [3. FAQ](#3)
## 1. 简介
Paddle2ONNX 支持将 PaddlePaddle 模型格式转化到 ONNX 模型格式,算子目前稳定支持导出 ONNX Opset 9~11,部分Paddle算子支持更低的ONNX Opset转换。
本文档主要介绍 MobileNetV3 模型如何转化为 ONNX 模型,并基于 ONNXRuntime 引擎预测。
更多细节可参考 [Paddle2ONNX官方教程](https://github.com/PaddlePaddle/Paddle2ONNX/blob/develop/README_zh.md)
## 2. Paddle2ONNX推理过程
### 2.1 准备推理环境
需要准备 Paddle2ONNX 模型转化环境,和 ONNX 模型预测环境
- 安装 Paddle2ONNX
```
python3 -m pip install paddle2onnx
```
- 安装 ONNXRuntime
```
# 建议安装 1.9.0 版本,可根据环境更换版本号
python3 -m pip install onnxruntime==1.9.0
```
- 下载代码
```bash
git clone https://github.com/PaddlePaddle/models.git
cd models/tutorials/mobilenetv3_prod/Step6
```
### 2.2 模型转换
- Paddle 模型动转静导出
使用下面的命令完成`mobilenet_v3_net`模型的动转静导出。
```bash
#下载预训练好的参数
wget https://paddle-model-ecology.bj.bcebos.com/model/mobilenetv3_reprod/mobilenet_v3_small_pretrained.pdparams
#生成推理模型
python tools/export_model.py --pretrained=./mobilenet_v3_small_pretrained.pdparams --save-inference-dir="./mobilenet_v3_small_infer" --model=mobilenet_v3_small
```
最终在`mobilenet_v3_small_infer/`文件夹下会生成下面的3个文件。
```
mobilenet_v3_small_infer
|----inference.pdiparams : 模型参数文件
|----inference.pdmodel : 模型结构文件
|----inference.pdiparams.info: 模型参数信息文件
```
- ONNX 模型转换
使用 Paddle2ONNX 将Paddle静态图模型转换为ONNX模型格式:
```
paddle2onnx --model_dir=./mobilenetv3_model/ \
--model_filename=inference.pdmodel \
--params_filename=inference.pdiparams \
--save_file=./inference/mobilenetv3_model/model.onnx \
--opset_version=10 \
--enable_onnx_checker=True
```
执行完毕后,ONNX 模型会被保存在 `./inference/mobilenetv3_model/` 路径下
更多关于参数的用法,可参考 [Paddle2ONNX官方教程](https://github.com/PaddlePaddle/Paddle2ONNX/blob/develop/README_zh.md)
### 2.3 ONNX 推理
ONNX模型测试步骤如下:
- Step1:初始化`ONNXRuntime`库并配置相应参数, 并进行预测
- Step2:`ONNXRuntime`预测结果和`Paddle Inference`预测结果对比
对于下面的图像进行预测
<div align="center">
<img src="../../images/demo.jpg" width=300">
</div>
执行如下命令:
```
python3 deploy/onnx_python/infer.py \
--onnx_file ./inference/mobilenetv3_model/model.onnx \
--params_file ./mobilenet_v3_small_pretrained.pdparams \
--img_path ./images/demo.jpg
```
`ONNXRuntime`输出结果如下。
```
ONNXRuntime predict:
class_id: 8, prob: 0.9091270565986633
```
表示预测的类别ID是`8`,置信度为`0.909`,该结果与基于训练引擎的结果完全一致
`ONNXRuntime`预测结果和`Paddle Inference`预测结果对比,如下。
```
ONNXRuntime and Paddle Inference result diff:
The difference of results between ONNXRuntime and Paddle looks good!
max_abs_diff: 1.5646219e-07
```
`ONNXRuntime``Paddle Inference`的预测结果diff可见,两者的结果几乎完全一致
## 3. FAQ
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import argparse
import numpy as np
from PIL import Image
import paddle
import paddle.nn as nn
from onnxruntime import InferenceSession
# 从模型代码中导入模型
from paddlevision.models import mobilenet_v3_small
from presets import ClassificationPresetEval
def infer():
# Step1:初始化ONNXRuntime库并配置相应参数, 并进行预测
# 加载ONNX模型
sess = InferenceSession(FLAGS.onnx_file)
# define transforms
input_shape = sess.get_inputs()[0].shape[2:]
eval_transforms = ClassificationPresetEval(
crop_size=input_shape, resize_size=FLAGS.crop_size)
# 准备输入
with open(FLAGS.img_path, 'rb') as f:
img = Image.open(f).convert('RGB')
img = eval_transforms(img)
img = np.expand_dims(img, axis=0)
# 模型预测
ort_outs = sess.run(output_names=None,
input_feed={sess.get_inputs()[0].name: img})
output = ort_outs[0]
class_id = output.argmax()
prob = output[0][class_id]
print("ONNXRuntime predict: ")
print(f"class_id: {class_id}, prob: {prob}")
# Step2:ONNXRuntime预测结果和Paddle Inference预测结果对比
# 实例化 Paddle 模型
model = mobilenet_v3_small(pretrained=FLAGS.params_file)
model = nn.Sequential(model, nn.Softmax())
# 将模型设置为推理状态
model.eval()
# 对比ONNXRuntime和Paddle预测的结果
paddle_outs = model(paddle.to_tensor(img))
diff = ort_outs[0] - paddle_outs.numpy()
max_abs_diff = np.fabs(diff).max()
print("ONNXRuntime and Paddle Inference result diff: ")
if max_abs_diff < 1e-05:
print(
"The difference of results between ONNXRuntime and Paddle looks good!"
)
else:
relative_diff = max_abs_diff / np.fabs(paddle_outs.numpy()).max()
if relative_diff < 1e-05:
print(
"The difference of results between ONNXRuntime and Paddle looks good!"
)
else:
print(
"The difference of results between ONNXRuntime and Paddle looks bad!"
)
print('relative_diff: ', relative_diff)
print('max_abs_diff: ', max_abs_diff)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
'--onnx_file',
type=str,
default="model.onnx",
help="onnx model filename")
parser.add_argument(
'--params_file',
type=str,
default="model.pdparams",
help="params filename")
parser.add_argument(
'--img_path', type=str, default="image.jpg", help="image filename")
parser.add_argument('--crop_size', default=256, help='crop_szie')
FLAGS = parser.parse_args()
infer()
...@@ -2,6 +2,198 @@ ...@@ -2,6 +2,198 @@
# 目录 # 目录
- [1. 简介](#1---) - [1. 简介](#1)
- [2. Paddle2ONNX功能开发](#2---) - [2. Paddle2ONNX推理过程开发](#2)
- [3. FAQ](#3---) - [2.1 准备环境](#2.1)
- [2.2 转换模型](#2.2)
- [2.3 开发数据预处理程序](#2.3)
- [2.4 开发ONNX模型推理程序](#2.4)
- [2.5 开发数据后处理程序](#2.5)
- [2.6 验证ONNX推理结果正确性](#2.6)
- [3. FAQ](#3)
## 1. 简介
Paddle2ONNX 支持将 PaddlePaddle 模型格式转化到 ONNX 模型格式,算子目前稳定支持导出 ONNX Opset 9~11,部分Paddle算子支持更低的ONNX Opset转换。
本文档主要介绍飞桨模型如何转化为 ONNX 模型,并基于 ONNXRuntime 引擎的推理过程开发。
更多细节可参考 [Paddle2ONNX官方教程](https://github.com/PaddlePaddle/Paddle2ONNX/blob/develop/README_zh.md)
## 2. Paddle2ONNX推理过程开发
基于Paddle2ONNX的推理过程可以分为6个步骤,如下图所示。
<div align="center">
<img src="./images/py2onnx_inference_pipeline.png" width="600">
</div>
其中设置了2个核验点,分别为
* 准备推理模型
* 验证推理结果正确性
### 2.1 准备环境
**【数据】**
从验证集或者测试集中抽出至少一张图像,用于后续推理过程验证。
**【环境】**
需要准备 Paddle2ONNX 模型转化环境,和 ONNX 模型预测环境
- 安装 Paddle2ONNX
```
python3 -m pip install paddle2onnx
```
- 安装 ONNXRuntime
```
# 建议安装 1.9.0 版本,可根据环境更换版本号
python3 -m pip install onnxruntime==1.9.0
```
### 2.2 转换模型
- Paddle 模型动转静导出
**【基本内容】**
`模型动转静`方法可以将训练得到的动态图模型转化为用于推理的静态图模型,具体可参考[Linux GPU/CPU 模型推理开发文档](https://github.com/PaddlePaddle/models/blob/release%2F2.2/docs/tipc/train_infer_python/infer_python.md#2.2)中第2.2章节。
**【实战】**
参考MobileNetV3的Paddle2ONNX [说明文档](../../mobilenetv3_prod/Step6/deploy/onnx_python/README.md) 中的第2.2章节
- ONNX 模型转换
**【基本内容】**
使用 Paddle2ONNX 将Paddle静态图模型转换为ONNX模型格式:
```
paddle2onnx --model_dir=${your_inference_model_dir}
--model_filename=${your_pdmodel_file}
--params_filename=${your_pdiparams_file}
--save_file=${output_file}
--opset_version=10
--enable_onnx_checker=True
```
- 参数说明:
- ${your_inference_model_dir}指的是Paddle模型所在目录.
- ${your_pdmodel_file}指的是网络结构的文件.
- ${your_pdiparams_file}指的是模型参数的文件.
- ${output_file}指的是需要导出的onnx模型.
- ${opset_version}指的是ONNX Opset,目前稳定支持9~11,默认是10.
- ${enable_onnx_checker}指的是否检查导出为ONNX模型的正确性.
更多关于参数的用法,可参考 [Paddle2ONNX官方教程](https://github.com/PaddlePaddle/Paddle2ONNX/blob/develop/README_zh.md)
**【实战】**
参考MobileNetV3的Paddle2ONNX [说明文档](../../mobilenetv3_prod/Step6/deploy/onnx_python/README.md) 中的第2.2章节
**【核验】**
执行完毕后,将产出${output_file} ONNX 模型文件,其中文件后缀为.onnx。
### 2.3 开发数据预处理程序
**【基本内容】**
读取指定图像,对其进行数据变换,转化为符合模型推理所需要的输入格式。
使用ONNX模型进行推理时,使用的数据预处理方法,和使用Paddle Inference进行推理时的预处理方法一样。
### 2.4 开发ONNX模型推理程序
ONNX作为开源的神经网络交换格式,得到大多数推理引擎的部署支持。在本文档中我们采用微软开源的ONNXRuntime推理引擎,进行转换后模型的正确性较验。
**【基本内容】**
初始化`ONNXRuntime`库并配置相应参数, 并进行预测
```
from onnxruntime import InferenceSession
# 加载ONNX模型
sess = InferenceSession('${your_onnx_model_name}.onnx')
# 模型预测
ort_outs = sess.run(output_names=None, input_feed={sess.get_inputs()[0].name: ${input_data})
```
**【注意事项】**
${input_data} 是预处理后的数据,作为网络的输入,数据是ndarray类型。
### 2.5 开发数据后处理程序
在完成ONNX模型进行推理后,基于不同的任务,需要对网络的输出进行后处理,这部分和使用Paddle Inference进行模型推理后的后处理方法一样。
### 2.6 验证ONNX推理结果正确性
**【基本内容】**
`ONNXRuntime`预测结果和`Paddle Inference`预测结果对比
```
import os
import time
import paddle
# 从模型代码中导入模型
from paddlevision.models import mobilenet_v3_small
# 实例化模型
model = mobilenet_v3_small('${your_paddle_model_name}.pdparams')
# 将模型设置为推理状态
model.eval()
# 对比ONNXRuntimePaddle预测的结果
paddle_outs = model(paddle.to_tensor(${input_data}))
diff = ort_outs[0] - paddle_outs.numpy()
max_abs_diff = np.fabs(diff).max()
if max_abs_diff < 1e-05:
print("The difference of results between ONNXRuntime and Paddle looks good!")
else:
relative_diff = max_abs_diff / np.fabs(paddle_outs.numpy()).max()
if relative_diff < 1e-05:
print("The difference of results between ONNXRuntime and Paddle looks good!")
else:
print("The difference of results between ONNXRuntime and Paddle looks bad!")
print('relative_diff: ', relative_diff)
print('max_abs_diff: ', max_abs_diff)
```
**【注意事项】**
${input_data} 是预处理后的数据,和 ONNXRuntime 的输入一样。
ort_outs 是 ONNXRuntime 的输出结果
paddlevision 模块位于MobileNetV3_prod/Step6目录下
**【核验】**
执行完毕后,如果 max_abs_diff < 1e-05,那么意味着,ONNXRuntime和Paddle Inference的输出是一致的。
**【实战】**
参考MobileNetV3的Paddle2ONNX [说明文档](../../mobilenetv3_prod/Step6/deploy/onnx_python/README.md) 中的第2.3章节
## 3. FAQ
如果您在使用该文档完成Paddle模型转ONNX的过程中遇到问题,可以给在[这里](https://github.com/PaddlePaddle/Paddle2ONNX/issues)提一个ISSUE,我们会高优跟进。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册