使用 X2Paddle 迁移推理模型¶
飞桨开源了模型转换工具 X2Paddle,可帮助其它深度学习框架用户快速迁移至飞桨框架。本文介绍推理模型的迁移方法,迁移后的推理模型可直接使用飞桨一系列的模型部署工具(如服务器部署 Paddle Inference、移动/IoT 端部署 Paddle Lite 等)完成模型推理部署。
说明:通常情况下,如果迁移后的模型不需要再训练,仅用于推理部署,可采用本章方法;如果还需要训练,则不能用此方法,需参考迁移训练代码的方法,如 从 PyTorch 迁移到飞桨 章节。
一、概述¶
1.1 支持迁移的源模型¶
PyTorch、ONNX、TensorFlow、Caffe 模型,可以通过 X2Paddle 直接完成模型转换,各框架支持的版本请参见下文 1.4 迁移环境依赖。
其他框架如 MXNet、MindSpore 等,可以先转为 ONNX 格式的模型,再使用 X2Paddle 进行转换。
说明:需要模型中用到的算子(OP)X2Paddle 均支持,才能实现转换,如果存在不支持的 OP 转换时会给出报错提示。目前 X2Paddle 支持大部分主流的 CV 和 NLP 模型转换,支持 130 多个 PyTorch OP,90 多个 ONNX OP,90 多个 TensorFlow OP 以及 30 多个 Caffe OP,详见 X2Paddle 支持 OP 列表。
1.2 支持迁移的目标模型¶
飞桨提供了一系列的模型部署工具,覆盖服务器端、移动/IoT 端、网页端、服务化部署等各种场景。如果转换后的推理模型要部署到:
服务器端,可以通过 X2Paddle 直接转换为 Paddle Inference 支持的格式,即
.pdmodel
、.pdiparams
、.pdiparams.info
格式文件。移动/IoT 端,可以通过 X2Paddle 直接转换为 Paddle Lite 支持的格式,即
.nb
格式文件。其他部署环境,如服务化部署(Paddle Serving)、网页端部署(Paddle.js),可以通过 X2Paddle 先转为 Paddle Inference 的模型格式,再使用对应工具转为其支持的格式。飞桨所有部署工具支持的模型格式,其实都可以用原生推理库 Paddle Inference 支持的模型格式转换而来。
1.3 迁移工具和用法¶
1.3.1 飞桨模型转换工具 X2Paddle¶
X2Paddle 是飞桨官方提供的模型转换工具,简洁易用,通过一条命令行或者一个 API 即可完成模型转换。已在 GitHub 社区开源:https://github.com/PaddlePaddle/X2Paddle
1.3.2 使用 Python API 迁移¶
X2Paddle 提供了一组 Python API,支持不同框架的模型迁移:
PyTorch 模型迁移:x2paddle.convert.pytorch2paddle
ONNX 模型迁移:x2paddle.convert.onnx2paddle
TensorFlow 模型迁移:x2paddle.convert.tf2paddle
Caffe 模型迁移:x2paddle.convert.caffe2paddle
以 x2paddle.convert.pytorch2paddle 为例,迁移 PyTorch 模型的使用方式如下:
from x2paddle.convert import pytorch2paddle
# 省略模型定义和参数加载的代码
torch_module.eval()
pytorch2paddle(module=torch_module,
save_dir="./pd_model",
jit_type="trace",
input_examples=[torch_input])
enable_code_optim=False,
convert_to_lite=False,
lite_valid_places="arm",
lite_model_type="naive_buffer")
(1)模型迁移配置说明
PyTorch 模型的迁移主要需要获取 Module 组网,加载模型参数 state_dict()
,然后切换到 eval()
模式进行转换,使用默认参数下将转换为 Paddle Inference 的模型格式,通过 convert_to_lite
参数设置是否转换为 Paddle Lite 的模型格式。
说明:
PyTorch 模型迁移需要准备 Module 组网代码和训练好的
.pth
模型参数文件;ONNX 模型迁移需要准备
.onnx
模型文件;TensorFlow 模型迁移需要准备
.pb
模型文件;Caffe 模型迁移需要准备
.prototxt
模型文件和.caffemodel
模型参数文件。
(2)模型迁移过程说明
通常情况下,实际转换过程是先将 PyTorch 模型代码转为 PaddlePaddle 动态图代码(为中间产物,将保存在 x2paddle_code.py
文件中)和模型参数文件(model.pdparams
文件),然后执行动转静,保存静态图模型到磁盘中(即 inference_model
文件夹)。
(3)x2paddle.convert.pytorch2paddle API 参数说明:
参数 | 说明 |
---|---|
module | PyTorch 的 Module。 |
save_dir | 转换后模型保存路径。 |
jit_type | 转换方式,对应 PyTorch 中定义的两种模型转换方式 trace 和 script。默认为 trace。"trace" 方式生成的代码可读性较强,较为接近原版 PyTorch 代码的组织结构,支持大部分模型,但是不支持模型输入是动态 shape 的情况;"script" 方式不需要知道输入数据的类型和大小即可转换(支持动态 shape),使用上较为方便,但目前 PyTorch 支持的 script 代码方式有所限制,可能存在一些 op 和语法不支持。优先推荐使用 "trace" 方式。 |
input_examples | torch.nn. Module 的输入示例,list 的长度必须与输入的长度一致。默认为 None。jit_type 为 "trace" 时,input_examples 不可为 None,转换后自动进行动转静;jit_type 为 "script" 时,当 input_examples 为 None 时,只生成动态图代码;当 input_examples 不为 None 时,才能自动动转静。 |
enable_code_optim | 是否对转换后的代码进行优化,默认为 False。对生成的 PaddlePaddle 动态图代码做一定优化,比如模块化处理,以增加生成的代码可读性。无论是否优化,通常不影响动转静后生成的静态图模型,一般使用默认值 False 即可。 |
convert_to_lite | 是否使用 opt 工具 转成 Paddle Lite 支持的格式,默认为 False。 |
lite_valid_places | lite_valid_places 参数目前可支持 arm、 opencl、 x86、 metal、 xpu、 bm、 mlu、 intel_fpga、 huawei_ascend_npu、imagination_nna、 rockchip_npu、 mediatek_apu、 huawei_kirin_npu、 amlogic_npu,可以同时指定多个硬件平台(以逗号分隔,优先级高的在前),opt 将会自动选择最佳方式。如果需要支持华为麒麟 NPU,应当设置为 "huawei_kirin_npu,arm"。 |
lite_model_type | 指定模型转化类型,目前支持两种类型:protobuf 和 naive_buffer,默认为 naive_buffer。其中 naive_buffer 是一种更轻量级的序列化/反序列化实现。若需要在移动端执行模型预测,请将此选项设置为 naive_buffer。 |
1.3.3 使用命令行迁移¶
除了 Python API 方式,X2Paddle 还提供了更加便捷的命令行迁移方式,该方式支持 ONNX、TensorFlow、Caffe 模型迁移,不支持 PyTorch 模型迁移。
ONNX 模型迁移
x2paddle --framework=onnx --model=onnx_model.onnx --save_dir=pd_model
TensorFlow 模型迁移
x2paddle --framework=tensorflow --model=tf_model.pb --save_dir=pd_model
Caffe 模型迁移
x2paddle --framework=caffe --prototxt=deploy.prototxt --weight=deploy.caffemodel --save_dir=pd_model
X2Paddle 命令行参数 说明:
参数 | 说明 |
---|---|
framework | 源模型类型(tensorflow、caffe、onnx) |
model | 当 framework 为 tensorflow/onnx 时,该参数指定 tensorflow 的 pb 模型文件或 onnx 模型路径 |
prototxt | 当 framework 为 caffe 时,该参数指定 caffe 模型的 proto 文件路径 |
weight | 当 framework 为 caffe 时,该参数指定 caffe 模型的参数文件路径 |
save_dir | 指定转换后的模型保存目录路径 |
define_input_shape | [可选] For TensorFlow, 当指定该参数时,强制用户输入每个 Placeholder 的 shape,见文档 Q2 |
caffe_proto | [可选] 由 caffe.proto 编译成 caffe_pb2.py 文件的存放路径,当存在自定义 Layer 时使用,默认为 None |
to_lite | [可选] 是否使用 opt 工具转成 Paddle-Lite 支持格式,默认为 False |
lite_valid_places | [可选] 指定转换类型,可以同时指定多个 backend(以逗号分隔),opt 将会自动选择最佳方式,默认为 arm |
lite_model_type | [可选] 指定模型转化类型,目前支持两种类型:protobuf 和 naive_buffer,默认为 naive_buffer |
disable_feedback | [可选] 是否关闭 X2Paddle 使用反馈;X2Paddle 默认会统计用户在进行模型转换时的成功率,以及转换框架来源等信息,以便于帮忙 X2Paddle 根据用户需求进行迭代,不会上传用户的模型文件。如若不想参与反馈,可指定此参数为 False 即可 |
1.3.4 查看转换结果¶
在指定的 save_dir 目录下查看转换结果:
inference_model : 该目录下存放转换后的飞桨静态图模型结构以及参数文件
.pdiparams
文件:存放模型中所有的权重数据.pdmodel
文件:存放模型的网络结构.pdiparams.info
:存放和参数状态有关的额外信息
x2paddle_code.py : 文件中存放生成的飞桨动态图组网代码
model.pdparams : 该文件即生成的飞桨动态图模型参数文件
opt.nb: 该文件即生成的 Paddle Lite 支持的模型文件
说明:通常情况下,取用 inference_model 或 opt.nb 模型文件作为转换的最终产物即可。x2paddle_code.py 和 model.pdparams 作为中间产物,一般不需要用,某些情况下可使用,比如想用 "trace" 方式导出动态 shape 的模型时,可修改 x2paddle_code.py 中的动态图代码后手动转为静态图模型。
1.4 迁移环境依赖¶
Python >= 3.5
PaddlePaddle >= 2.0.0 (推荐使用最新版本)
PyTorch >= 1.5.0(如需转换 PyTorch 模型)
其他依赖:使用 PyTorch trace 方式时需安装 pandas、treelib
ONNX >= 1.6.0(如需转换 ONNX 模型)
TensorFlow == 1.14(如需转换 TensorFlow 模型)
Paddle Lite >= 2.9.0(如需一键转换成 Paddle Lite 支持格式,推荐最新版本)
Caffe 若无自定义 Layer,可使用 X2Paddle 自带 caffe_pb2.py,否则需自行将 caffe.proto 编译成 caffe_pb2.py 文件
接下来通过两个示例,介绍使用 X2Paddle 迁移推理模型的方法,为了能完整体验,先安装相关环境:
(1)安装 PaddlePaddle
pip install paddlepaddle==2.3.2
(2)安装 X2Paddle
# 方式一:pip 安装
pip install X2Paddle==1.3.9
# 方式二:源码安装
git clone https://github.com/PaddlePaddle/X2Paddle.git
cd X2Paddle
python setup.py install
(3)安装 PyTorch
pip install torch==1.12.0 torchvision==0.13.0
# 示例中用到 trace 方式,需要安装如下两个依赖
pip install pandas
pip install treelib
(4)安装 ONNX
pip install onnx==1.11.0
(5)安装 Paddle Lite
pip install paddlelite==2.11
二、迁移 PyTorch 模型示例¶
介绍迁移 PyTorch 模型为 Paddle Inference 可部署的模型的示例。
本示例中,将 PyTorch 图像分类模型 AlexNet 转换为 PaddlePaddle 模型,然后验证并比对转换前后模型的输出误差。
2.1 转换模型¶
(1)加载 PyTorch 模型和参数
说明:PyTorch 模型转换需要准备 Module 组网代码和训练好的
.pth
模型参数文件。
from torchvision.models import AlexNet
from torch.hub import load_state_dict_from_url
# 获取 PyTorch Module,并加载模型参数
torch_model = AlexNet()
torch_state_dict = load_state_dict_from_url('https://download.pytorch.org/models/alexnet-owt-4df8aa71.pth')
torch_model.load_state_dict(torch_state_dict)
# 设置为 eval 模式
torch_model.eval()
(2)构造输入示例
PyTorch 到 PaddlePaddle 的转换需要传入输入的示例,才可以进行转换,以下为构建输入的过程(输入也可为值随机初始化的 Tensor):
import numpy as np
# 随机生成数组
img = np.random.randn(1, 3, 224, 224).astype("float32")
# 转为 Torch.Tensor
import torch
input_tensor = torch.tensor(img)
(3)转换模型
方式一: Trace 方式 模型输入的 shape 固定,PyTorch 模型基本均支持此方式转换。
from x2paddle.convert import pytorch2paddle
save_dir = "pd_model_trace"
jit_type = "trace" # 指定 trace 转换方式
pytorch2paddle(module=torch_model,
save_dir=save_dir,
jit_type=jit_type,
input_examples=[input_tensor])
查看 Trace 方式转换结果
转换成功后,模型参数类型、参数量与 PyTorch 是一致的。
pd_model_trace
inference_model # 转换后的飞桨静态图模型结构以及参数文件
model.pdiparams
model.pdmodel
model.pdiparams.info
x2paddle_code.py # 转换后的飞桨动态图组网代码
model.pdparams # 转换后的飞桨动态图模型参数文件
方式二: Script 方式 模型输入的 shape 可不固定,由于 PyTorch 的 Script 方式可识别的代码格式有限,所以 PyTorch 模型在此方式下转换的支持度较低。
from x2paddle.convert import pytorch2paddle
save_dir = "pd_model_script"
jit_type = "script" # 指定 script 转换方式
pytorch2paddle(module=torch_model,
save_dir=save_dir,
jit_type=jit_type,
input_examples=None)
以上示例中未指定输入大小,因此只生成了飞桨动态图代码 x2paddle_code.py 和 模型参数文件 model.pdparams。若想导出动态 shape 的静态图模型,可在此文件中添加如下代码,然后运行 main 函数手动动转静,动转静相关用法可参见 动态图转静态图 章节。
def main(x0):
# There are 0 inputs.
paddle.disable_static()
params = paddle.load('pd_model_script/model.pdparams')
model = AlexNet()
model.set_dict(params)
model.eval()
## convert to jit
sepc_list = list()
sepc_list.append(
paddle.static.InputSpec(
shape=[-1, 3, 224, 224], name="x0", dtype="float32"))
static_model = paddle.jit.to_static(model, input_spec=sepc_list)
paddle.jit.save(static_model, "pd_model_script/inference_model/model")
out = model(x0)
return out
查看 Script 方式转换结果
转换成功后,模型参数类型、参数量与 PyTorch 是一致的。
pd_model_script
inference_model # 转换后的飞桨静态图模型结构以及参数文件
model.pdiparams
model.pdmodel
model.pdiparams.info
x2paddle_code.py # 转换后的飞桨动态图组网代码
model.pdparams # 转换后的飞桨动态图模型参数文件
2.2 验证模型¶
将 PyTorch 输入输出保存为 numpy 格式,保存为 input.npy 和 output.npy,通过如下脚本比较相同输入下 PyTorch 与 PaddlePaddle 结果绝对误差是否在 1e-5。
import paddle
import numpy as np
import sys
f = open('result.txt', 'w')
f.write("======AlexNet: \n")
try:
# 加载 Paddle 模型
paddle_path = "pd_model_trace/inference_model/model"
model = paddle.jit.load(paddle_path)
model.eval()
dummy_input = paddle.to_tensor(np.load("input.npy"))
# run
result = model(dummy_input)
paddle_result = result.numpy()
pytorch_result = np.load("output.npy")
is_successd = True
# 比较 diff
for i in range(1):
diff = paddle_result - pytorch_result
max_abs_diff = np.fabs(diff).max()
if max_abs_diff >= 1e-05:
relative_diff_all = max_abs_diff / np.fabs(pytorch_result).max()
relative_diff = relative_diff_all.max()
if relative_diff >= 1e-05:
is_successd = False
if is_successd:
f.write("Dygraph Successed\n")
else:
f.write("!!!!!Dygraph Failed\n")
except:
f.write("!!!!!Failed\n")
最终比较结果写在 result.txt 当中,若显示 Dygraph Successed 表示成功,验证通过后,则可使用 Paddle Inference 部署该模型。
三、迁移 ONNX 模型示例¶
介绍迁移 ONNX 模型为 Paddle Lite 可部署的模型的示例。
本示例中,将 ONNX 模型 YOLOv5Lite-E 转换为 Paddle Lite 可部署的 .nb 模型。
3.1 转换模型¶
下载一个 YOLOv5Lite-E 的 ONNX 模型,直接通过命令行转换 ONNX 模型。
# 下载一个 ONNX 模型
wget https://bj.bcebos.com/paddlehub/fastdeploy/v5Lite-e-sim-320.onnx
# 执行模型转换命令
x2paddle --framework=onnx --model=v5Lite-e-sim-320.onnx --save_dir=pd_model --to_lite=True
(4)查看转换结果
转换成功后,模型参数类型、大小与 PyTorch 是一致的。
pd_model
inference_model # 转换后的飞桨静态图模型结构以及参数文件
model.pdiparams
model.pdmodel
model.pdiparams.info
x2paddle_code.py # 转换后的飞桨动态图组网代码
model.pdparams # 转换后的飞桨动态图模型参数文件
opt.nb # 转换后的 Paddle Lite 支持的模型
3.2 验证模型¶
转换成功后,可通过 Paddle Lite 部署到端侧验证效果,具体示例可参考 Paddle Lite 文档。
四、迁移常见问题¶
Q:模型转换后提示 OP 不支持怎么处理?
A:模型转换后,如果存在不支持的 OP,将提示类似下图信息:
遇到此问题,或者其他 X2Paddle 的使用问题,请以 Github Issues 的形式提交给我们。
获取 更多 FAQ。