Paddle2.0:ONNX模型的导出和部署

引入

  • 除了动态图转静态图的方式导出推理模型之外
  • Paddle2.0中也正式内置了ONNX模型的导出功能
  • 本文将通过一个实例演示一下如何将Paddle模型导出为ONNX模型
  • 并在ONNXRunTime上完成模型的推理预测

ONNX

  • Open Neural Network Exchange (ONNX) ,是一个机器学习模型的开放标准,方便不同框架之间进行模型交换
  • 你可以在很多支持ONNX模型导出的框架上构建模型,然后导出ONNX模型进行预测部署

Paddle2ONNX

  • 目前Paddle导出ONNX模型需要安装Paddle2ONNX进行额外支持
  • Paddle2ONNX支持将PaddlePaddle模型格式转化到ONNX模型格式。
    • 模型格式,支持Paddle静态图和动态图模型转为ONNX,可转换由save_inference_model导出的静态图模型。动态图转换目前处于实验状态,将伴随Paddle 2.0正式版发布后,提供详细使用教程
    • 算子支持,目前稳定支持导出ONNX Opset 9~11,部分Paddle算子支持更低的ONNX Opset转换,详情可参考算子列表
    • 模型类型,官方测试可转换的模型请参考模型库
  • 更多详情请参考Paddle2ONNX的Github主页
# PIP 安装
$ pip install paddle2onnx
# 源码安装
$ git clone https://github.com/paddlepaddle/paddle2onnx
$ cd paddle2onnx 
$ python setup.py install

动态图ONNX模型导出

  • 如果使用Paddle2.0构建的动态图模型,可以通过调用paddle.onnx.export()来实现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.onnx.export(model, [path to the save onnx model], input_spec=[input_spec], opset_version=[opset version])
2021-01-09 17:12:24 [INFO]	ONNX model saved in u2netp.onnx

静态图模型转换

  • 除了动态图模型可以导出为ONNX模型
  • 静态图的推理模型当然也可以转换为ONNX模型
  • 通过命令行调用如下命令即可完成转换
  • 更多细节请参考paddle2onnx官方Github文档
$ paddle2onnx \
    --model_dir [model dir] \
    --model_filename [model filename] \
    --params_filename [params filename] \
    --save_file [save file] \
    --opset_version [opset version]
2021-01-09 17:12:28 [INFO]	ONNX model saved in u2netp_static.onnx

模型可视化

  • 通过VisualDL工具可以轻松的进行模型结构的可视化查看
  • 选择刚才保存后缀为.onnx的模型文件
  • 具体的可视化图像就像下图所示的那样:


模型测试

  • 这里使用ONNXRunTime来进行ONNX模型验证测试
# 安装ONNXRunTime
$ pip install onnxruntime
import time
import numpy as np
from onnxruntime import InferenceSession

# 加载ONNX模型
model = InferenceSession([path to the save onnx model])

# 准备输入
x = np.random.random((1, 3, 320, 320)).astype('float32')

# 模型预测
d0, _, _, _, _, _, _ = model.run(output_names=None, input_feed={'image': x})

# 打印输出形状
print(d0.shape)

# 速度测试
start = time.time()
d0, _, _, _, _, _, _ = model.run(output_names=None, input_feed={'image': x})
end = time.time()
print('predict time: %.04f s' % (end - start))
(1, 1, 320, 320)
predict time: 0.7178 s

部署实例

  • 接下来通过加入数据预处理和后处理来完成完整的模型推理部署
import cv2
import time
import numpy as np
import matplotlib.pyplot as plt

from onnxruntime import InferenceSession
from processor import preprocess, postprocess

# 输入输出设置
img_path = [path to the input image]
output_dir = [output dir]

# 数据预处理
img = preprocess(img_path)

# 加载模型
model = InferenceSession([path to the save onnx model])

# 模型推理
start = time.time()
d0, _, _, _, _, _, _ = model.run(output_names=None, input_feed={'image': img})
end = time.time()
print('predict time: %.04f s' % (end - start))

# 结果后处理
mask_path, result_path = postprocess(d0, img_path, output_dir)

# 图像显示
img = np.concatenate([
    cv2.imread(img_path),
    cv2.imread(mask_path),
    cv2.imread(result_path)
], 1)
plt.axis('off')
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.show()
predict time: 0.7305 s

在这里插入图片描述

总结

  • Paddle2.0目前内置了导出ONNX模型的接口,可以较为方便的导出ONNX模型
  • 对于之前的静态图模型,使用Paddle2ONNX工具也可以进行转换
  • 使用ONNX模型进行推理部署也比较简单和方便
  • 但目前仍有一些Paddle算子存在兼容性问题,导致一些模型无法正常的进行导出操作
  • 总体体验还是不错的,也希望这个功能未来能够更加完善,支持更多算子
要将Paddle模型导出ONNX格式并在ONNXRuntime C中使用,可以按照以下步骤进行: 首先,需要使用Paddle框架训练或加载一个现有的模型。在训练或加载模型后,可以使用以下代码将Paddle模型导出ONNX格式: ```python import paddle import paddle.nn as nn import paddle.onnx as onnx # 定义并训练Paddle模型 class MyModel(nn.Layer): def __init__(self): super(MyModel, self).__init__() self.fc = nn.Linear(10, 10) def forward(self, x): x = self.fc(x) return x model = MyModel() # 进行模型训练 # 将Paddle模型导出ONNX格式 onnx_model_path = "model.onnx" paddle.onnx.export(model, onnx_model_path) ``` 然后,安装ONNXRuntime C库,并使用以下代码在C中加载和运行导出ONNX模型: ```c #include <onnxruntime_c_api.h> // 加载ONNX模型 const wchar_t* model_path = L"model.onnx"; OrtEnv* env; OrtCreateEnv(ORT_LOGGING_LEVEL_WARNING, "ONNXModel", &env); OrtSessionOptions* session_options; OrtCreateSessionOptions(&session_options); OrtSession* session; OrtCreateSession(env, model_path, session_options, &session); // 设置输入张量 OrtAllocator* allocator; OrtCreateAllocatorWithDefaultOptions(&allocator); int input_tensor_shape[] = {1, 10}; float input_tensor_data[] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}; const char* input_tensor_name[] = {"input"}; size_t input_tensor_size = sizeof(input_tensor_data); OrtValue* input_tensor; OrtStatus* status; OrtCreateTensorWithDataAsOrtValue(allocator, input_tensor_data, input_tensor_size, input_tensor_shape, 2, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, &input_tensor); OrtStatus* input_status; OrtSessionGetInputCount(session, &input_count); OrtInput* input_def; OrtSessionGetInput(session, 0, &input_def); OrtSessionFillInputTensor(session, input_tensor, input_def, input_tensor_data, input_tensor_size); // 运行模型 OrtStatus* run_status; const char* output_names[] = {"output"}; OrtValue* output_tensor; OrtStatus* output_status; int output_tensor_count = 1; OrtStatus* session_status; OrtRun(session, NULL, input_tensor_name, (const OrtValue* const*)&input_tensor, 1, output_names, output_tensor_count, &output_tensor); // 获取输出结果 float* output_tensor_data; OrtGetTensorMutableData(output_tensor, (void**)&output_tensor_data); for (int i = 0; i < 10; i++) { printf("%f ", output_tensor_data[i]); } // 释放资源 OrtAllocatorFree(allocator, input_tensor); OrtReleaseSession(session); OrtReleaseSessionOptions(session_options); OrtReleaseEnvironment(env); ``` 这样,就可以使用ONNXRuntime C加载和运行导出ONNX模型。注意,在使用ONNXRuntime C之前,需要根据平台和编译器的要求进行相应的设置和安装。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值