首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何将PyTorch、TensorFlow模型转换为PaddlePaddle模型

如何将PyTorch、TensorFlow模型转换为PaddlePaddle模型

作者头像
用户1386409
发布2020-07-06 10:13:43
2.5K0
发布2020-07-06 10:13:43
举报
文章被收录于专栏:PaddlePaddlePaddlePaddlePaddlePaddle

本文手把手教你使用X2Paddle将PyTorch、TensorFlow模型转换为PaddlePaddle模型,并提供了PaddlePaddle模型的使用实例。

本项目适合以下人群:

  • 已有PyTorch、TF模型却苦于没有算力运行的你
  • 希望快速将PyTorch、TF工程迁移为PaddlePaddle的你
  • 希望快速使用PaddlePaddle又不想重新训练模型的你
  • 垂涎AI Studio的V100已久却不想花太多时间学习PaddlePaddle细节的你

将PyTorch模型转换为

PaddlePaddle模型

将PyTorch模型转换为PaddlePaddle模型需要先把PyTorch转换为onnx模型,然后转换为PaddlePaddle模型。

1. 安装依赖库:

在实践下述代码前,你需要确保本地环境已安装以下依赖库:

  • torch
  • onnx
pip install onnx==1.6.0
pip install onnxruntime==1.0.0
  • PaddlePaddle >= 1.6.0
  • X2Paddle
git clone https://github.com/PaddlePaddle/X2Paddle.git
cd X2Paddle
git checkout develop
python setup.py install

2. 实验环境:

本文所用PyTorch模型为nasnet-a_mobile ,通过迁移训练在Stanford Dogs数据集全集上训练20个epochs所得。

  • PyTorch模型定义文件,本文采用nasnet_mobile.py
  • PyTorch模型参数,本文中所用为nasnet_mobile.pkl

note:

  1. 上文所提两文件均在/home/aistudio目录下,读者可自行下载进行实验
  2. 如果你需要转换自己的PyTorch模型同样也需要提供模型定义文件和模型参数文件。

3. 实验步骤:

3.1 PyTorch模型转换为onnx模型

定义一个py文件名为trans.py,具体代码如下:

#coding: utf-8
import torch
#import torchvision
# 1.导入PyTorch模型定义
from nasnet_mobile import nasnetamobile
# 2.指定输入大小的shape
dummy_input = torch.randn(1, 3, 224, 224)

# 3. 构建PyTorch model
model = nasnetamobile(121,pretrained=False)
# 4. 载入模型参数
model.load_state_dict(torch.load('/home/aistudio/data/data23875/nasnet_mobile.pkl', map_location='cpu'))

# 5.导出onnx模型文件
torch.onnx.export(model, dummy_input, "nasnet.onnx",verbose=True)

note:如果你想转换自己的模型,在此需要修改,在本地终端中输入:

python trans.py

所转换的onnx模型nasnet.onnx将存放在当前目录。

3.2 将onnx模型转换为PaddlePaddle模型

在本地终端输入以下代码:

x2paddle --framework=onnx --model=nasnet.onnx --save_dir=pd_model

最终的PaddlePaddle模型存放在pd_model目录。

pd_model目录下有两个文件夹

  • inference_model 存放模型的网络结构和参数。
  • model_with_code 存放模型构建的代码model.py和模型参数。

4. 转换所得PaddlePaddle模型应用示例

下面我们用一张图片看看转换所得PaddlePaddle模型是否可以正常运行。

我们在AI Studio的环境上存放以下文件:

  • 在目录/home/aistudio/下的n02085782_1039.jpg文件,这是 一张小狗的图片,类别标签为32。
  • 在目录 /home/aistudio/pd_model/model_with_code下保存有转换所得Paddle模型的参数与模型定义。

下面我们开始构建Paddle程序,看看模型的推理结果是否如预期。

cd ./pd_model/
/home/aistudio/pd_model

tar = zipfile.ZipFile('/home/aistudio/pd_model/model_with_code_zip.zip','r')
tar.extractall()

cd ./model_with_code/
/home/aistudio/pd_model/model_with_code

import argparse
import functools
import numpy as np
import paddle.fluid as fluid
from model import x2paddle_net
use_gpu=True
######Attack graph
adv_program=fluid.Program()
#完成初始化
with fluid.program_guard(adv_program):
    #设置为可以计算梯度
    input_layer.stop_gradient=False

    # model definition
    inputs ,out_logits = x2paddle_net()
    out = fluid.layers.softmax(out_logits[0])

    place = fluid.CUDAPlace(0) if use_gpu else fluid.CPUPlace()
    exe = fluid.Executor(place)
    exe.run(fluid.default_startup_program())

    #记载模型参数
    fluid.io.load_persistables(exe, "./")

#创建测试用评估模式
eval_program = adv_program.clone(for_test=True)

import cv2
#定义一个预处理图像的函数
def process_img(img_path="",image_shape=[3,224,224]):

    mean = [0.485, 0.456, 0.406] 
    std = [0.229, 0.224, 0.225] 

    img = cv2.imread(img_path)
    img = cv2.resize(img,(image_shape[1],image_shape[2]))
    #img = cv2.resize(img,(256,256))
    #img = crop_image(img, image_shape[1], True)

    #RBG img [224,224,3]->[3,224,224]
    img = img[:, :, ::-1].astype('float32').transpose((2, 0, 1)) / 255
    #img = img.astype('float32').transpose((2, 0, 1)) / 255
    img_mean = np.array(mean).reshape((3, 1, 1))
    img_std = np.array(std).reshape((3, 1, 1))
    img -= img_mean
    img /= img_std

    img=img.astype('float32')
    img=np.expand_dims(img, axis=0)

    return img
#模型推理函数
def inference(img):
    fetch_list = [out.name]
result = exe.run(eval_program,
fetch_list=fetch_list,
feed={inputs[0].name: img})
    result = result[0][0]
    pred_label = np.argmax(result)
    pred_score = result[pred_label].copy()
    return pred_label, pred_score

#将标签为32的图片进行预处理
img = process_img("/home/aistudio/n02085782_1039.jpg")

#用PaddlePaddle模型推理图片标签
pred_label, pred_score = inference(img)

print("预测图片{}的标签为{}".format("/home/aistudio/n02085782_1039.jpg",pred_label))

预测图片/home/aistudio/n02085782_1039.jpg的标签为32。可见模型可以如期推理出标签,那么我们的转换大功告成,接下来就可以在AI Studio平台愉快的用所转换的模型做各种下游任务了。

将TensorFlow模型转换

为PaddlePaddle模型

注:model.pb为TF训练好的模型,pb_model为转换为PaddlePaddle之后的文件。

1. 安装依赖库:

在实践下述代码前,你需要确保本地环境满足以下依赖库:

  • TensorFlow1.14
  • PaddlePaddle1.8
pip install paddlepaddle -i https://mirror.baidu.com/pypi/simple
  • TensorFlow
conda install tensorflow ==1.1
  • PaddlePaddle >= 1.6.0
conda install paddlepaddle
  • X2Paddle
pip install x2paddle

2. 实验步骤:

首先训练TF网络,并保存成pb文件。本教程的主要目的是如何转换自己训练的TF模型到Paddle模型,所以只搭建了Lenet5这个最简单的网络。数据集为猫狗大战数据集,数据示例如下所示,相关数据已经制作成tfrecords格式。

注意 TensorFlow模型在导出时,只需要导出前向计算部分(即模型预测部分,不需要训练部分回传的网络结构)。

目前,X2Paddle中支持TF保存的pb模型,但是需要注意的是,在保存pb模型的时候,只需要导出前向计算部分(即模型预测部分,不需要训练部分回传的网络结构)。为了方便大家,模型保存的函数如下。

def freeze_model(sess, output_tensor_names, freeze_model_path):
    out_graph = graph_util.convert_variables_to_constants(
        sess, sess.graph.as_graph_def(), output_tensor_names)
    with tf.gfile.GFile(freeze_model_path, 'wb') as f:
        f.write(out_graph.SerializeToString())
    print("freeze model saved in {}".format(freeze_model_path))

开启训练。因为是在CPU中进行计算,所以项目中设置了10次迭代,仅仅是对训练过程进行演示。

在终端中运行如下命令安装TF1.14:

pip install tensorflow==1.14 –i https://mirror.baidu.com/pypi/simple

执行如下命令开启训练过程:

!python work/X2Paddle_ISSUE/train.py

在本地终端输入以下代码将TF模型转换为PaddlePaddle模型:

x2paddle --framework=tensorflow --model=/home/aistudio/work/X2Paddle_ISSUE/save_model/model.pb --save_dir=/home/aistudio/pd_model

最终的转换出的PaddlePaddle模型将存放在pd_model目录中。

pd_model目录下有两个文件夹

  • inference_model 只存放了模型参数。
  • model_with_code 不仅存放了模型参数,还生成了模型定义。

3. 转换所得PaddlePaddle模型应用示例

下面我们用一张图片看看转换所得PaddlePaddle模型是否可以正常运行。

我们有以下文件:

  • work/X2Paddle_ISSUE/dog.jpg 一张小狗的图片,类别标签为1
  • /home/aistudio/pd_model/model_with_code 转换所得Paddle模型的参数与模型定义

为将图片以参数形式传入型,/home/aistudio/pd_model/model_with_code/model.py中需修改两处:

1)def x2paddle_net(): 修改为 def x2paddle_net(input):

2) x2paddle_input_1 = fluid.layers.data(dtype='float32', shape=[1, 3, 224, 224], name='x2paddle_input_1', append_batch_size=False)

修改为x2paddle_input_1 = input

下面展示了X2Paddle生成的网络结构定义函数,如果仔细看的话,我们能看出网络结构,但是这个代码确实不像是阳间的Paddle代码。

def x2paddle_net(input):
    # Placeholder = fluid.layers.data(dtype='float32', shape=[1, 3, 32, 32], name='Placeholder', append_batch_size=False)
    Placeholder = input
    layer1_conv1_Variable_1 = fluid.layers.create_parameter(dtype='float32', shape=[64], name='layer1_conv1_Variable_1', default_initializer=Constant(0.0))
    layer3_conv2_Variable_1 = fluid.layers.create_parameter(dtype='float32', shape=[128], name='layer3_conv2_Variable_1', default_initializer=Constant(0.0))
    layer5_fc1_Variable = fluid.layers.create_parameter(dtype='float32', shape=[8192, 512], name='layer5_fc1_Variable', default_initializer=Constant(0.0))
    layer5_fc1_Variable_1 = fluid.layers.create_parameter(dtype='float32', shape=[512], name='layer5_fc1_Variable_1', default_initializer=Constant(0.0))
    layer5_fc1_dropout_rate = fluid.layers.create_parameter(dtype='float32', shape=[1], name='layer5_fc1_dropout_rate', default_initializer=Constant(0.5))
    layer5_fc1_dropout_random_uniform_min = fluid.layers.create_parameter(dtype='float32', shape=[1], name='layer5_fc1_dropout_random_uniform_min', default_initializer=Constant(0.0))
    layer5_fc1_dropout_random_uniform_max = fluid.layers.create_parameter(dtype='float32', shape=[1], name='layer5_fc1_dropout_random_uniform_max', default_initializer=Constant(1.0))
    layer5_fc1_dropout_sub_x = fluid.layers.create_parameter(dtype='float32', shape=[1], name='layer5_fc1_dropout_sub_x', default_initializer=Constant(1.0))
    layer5_fc1_dropout_truediv_x = fluid.layers.create_parameter(dtype='float32', shape=[1], name='layer5_fc1_dropout_truediv_x', default_initializer=Constant(1.0))
    layer6_fc2_Variable = fluid.layers.create_parameter(dtype='float32', shape=[512, 2], name='layer6_fc2_Variable', default_initializer=Constant(0.0))
    layer6_fc2_Variable_1 = fluid.layers.create_parameter(dtype='float32', shape=[2], name='layer6_fc2_Variable_1', default_initializer=Constant(0.0))
    layer5_fc1_dropout_random_uniform_RandomUniform = fluid.layers.uniform_random(shape=[1, 512], min=0.0, max=0.9999)
    layer5_fc1_dropout_random_uniform_sub = fluid.layers.elementwise_sub(x=layer5_fc1_dropout_random_uniform_max, y=layer5_fc1_dropout_random_uniform_min)
    layer5_fc1_dropout_sub = fluid.layers.elementwise_sub(x=layer5_fc1_dropout_sub_x, y=layer5_fc1_dropout_rate)
    layer1_conv1_Relu = fluid.layers.conv2d(Placeholder, bias_attr='layer1_conv1_Variable_1', param_attr='layer1_conv1_Variable', num_filters=64, filter_size=[5, 5], stride=[1, 1], dilation=[1, 1], padding='SAME', act='relu')
    y_tmp = fluid.layers.expand(layer5_fc1_dropout_random_uniform_sub, expand_times=[512])
    layer5_fc1_dropout_random_uniform_mul = fluid.layers.elementwise_mul(x=layer5_fc1_dropout_random_uniform_RandomUniform, y=y_tmp)
    layer5_fc1_dropout_truediv = fluid.layers.elementwise_div(x=layer5_fc1_dropout_truediv_x, y=layer5_fc1_dropout_sub)
    y_tmp = fluid.layers.expand(layer5_fc1_dropout_random_uniform_min, expand_times=[512])
    layer5_fc1_dropout_random_uniform = fluid.layers.elementwise_add(x=layer5_fc1_dropout_random_uniform_mul, y=y_tmp)
    layer5_fc1_dropout_GreaterEqual = fluid.layers.greater_equal(x=layer5_fc1_dropout_random_uniform, y=layer5_fc1_dropout_rate)
    layer2_pool1_MaxPool = fluid.layers.pool2d(layer1_conv1_Relu, pool_size=[2, 2], pool_type='max', pool_padding='SAME', pool_stride=[2, 2])
    layer5_fc1_dropout_Cast = fluid.layers.cast(layer5_fc1_dropout_GreaterEqual, dtype='float32')
    layer3_conv2_Relu = fluid.layers.conv2d(layer2_pool1_MaxPool, bias_attr='layer3_conv2_Variable_1', param_attr='layer3_conv2_Variable', num_filters=128, filter_size=[5, 5], stride=[1, 1], dilation=[1, 1], padding='SAME', act='relu')
    layer4_pool2_MaxPool = fluid.layers.pool2d(layer3_conv2_Relu, pool_size=[2, 2], pool_type='max', pool_padding='SAME', pool_stride=[2, 2])
    layer4_pool2_Reshape = fluid.layers.transpose(layer4_pool2_MaxPool, perm=[0, 2, 3, 1])
    layer4_pool2_Reshape = fluid.layers.reshape(layer4_pool2_Reshape, shape=[1, 8192])
    layer5_fc1_MatMul = fluid.layers.matmul(x=layer4_pool2_Reshape, y=layer5_fc1_Variable, transpose_x=False, transpose_y=False)
    layer5_fc1_add = fluid.layers.elementwise_add(x=layer5_fc1_MatMul, y=layer5_fc1_Variable_1)
    layer5_fc1_Relu = fluid.layers.relu(layer5_fc1_add)
    y_tmp = fluid.layers.expand(layer5_fc1_dropout_truediv, expand_times=[512])
    layer5_fc1_dropout_mul = fluid.layers.elementwise_mul(x=layer5_fc1_Relu, y=y_tmp)
    layer5_fc1_dropout_mul_1 = fluid.layers.elementwise_mul(x=layer5_fc1_dropout_mul, y=layer5_fc1_dropout_Cast)
    layer6_fc2_MatMul = fluid.layers.matmul(x=layer5_fc1_dropout_mul_1, y=layer6_fc2_Variable, transpose_x=False, transpose_y=False)
    layer6_fc2_add = fluid.layers.elementwise_add(x=layer6_fc2_MatMul, y=layer6_fc2_Variable_1)

    return [Placeholder], [layer6_fc2_add]

下面我们开始构建Paddle程序,看看模型的推理结果是否如预期。预测用示例图像如下所示,在训练过程中,我们将cat的标签转换为0,dog的标签为1。

执行如下命令进行预测:

!python work/X2Paddle_ISSUE/test_paddle.py

最终预测图片work/X2Paddle_ISSUE/dog.jpg的标签为1。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-07-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PaddlePaddle 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 本文手把手教你使用X2Paddle将PyTorch、TensorFlow模型转换为PaddlePaddle模型,并提供了PaddlePaddle模型的使用实例。
    • 1. 安装依赖库:
      • 2. 实验环境:
        • 3. 实验步骤:
          • 3.1 PyTorch模型转换为onnx模型
          • 3.2 将onnx模型转换为PaddlePaddle模型
        • 4. 转换所得PaddlePaddle模型应用示例
          • 1. 安装依赖库:
            • 3. 转换所得PaddlePaddle模型应用示例
            相关产品与服务
            内容识别
            内容识别(Content Recognition,CR)是腾讯云数据万象推出的对图片内容进行识别、理解的服务,集成腾讯云 AI 的多种强大功能,对存储在腾讯云对象存储 COS 的数据提供图片标签、图片修复、二维码识别、语音识别、质量评估等增值服务。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档