提交 b483d12e 编写于 作者: M Macrobull

add onnx2paddle

上级 7b3054cb
# Virtualenv
/.venv/
/venv/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
/bin/
/build/
/develop-eggs/
/dist/
/eggs/
/lib/
/lib64/
/output/
/parts/
/sdist/
/var/
/*.egg-info/
/.installed.cfg
/*.egg
/.eggs
# AUTHORS and ChangeLog will be generated while packaging
/AUTHORS
/ChangeLog
# BCloud / BuildSubmitter
/build_submitter.*
/logger_client_log
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
.tox/
.coverage
.cache
.pytest_cache
nosetests.xml
coverage.xml
# Translations
*.mo
# Sphinx documentation
/docs/_build/
/examples/*/
/examples/*.gz
/examples/*.aria2
/examples/*.onnx
/examples/*.np?
Onnx2paddle
===
Inference model conversion from ONNX/PyTorch to Paddle
快速开始
---
如何构建、安装、运行
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Mar 27 11:50:03 2019
@author: Macrobull
"""
import sys
import numpy as np
from collections import OrderedDict as Dict
fn = sys.argv[1]
input_names = sys.argv[2].split(':')
output_name = sys.argv[3].split(':')
data = np.load(fn)
input_data = data['inputs']
output_data = data['outputs']
inputs = Dict(zip(input_names, [input_data]))
outputs = Dict(zip(output_name, [output_data]))
np.savez(fn, inputs=inputs, outputs=outputs) # overwrite
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Mar 27 11:50:03 2019
@author: Macrobull
"""
# import os, sys
import os
import sys
import numpy as np
import onnx
import onnx.numpy_helper as numpy_helper
from collections import OrderedDict as Dict
from glob import glob
data_dir = os.path.dirname(sys.argv[1])
input_names = sys.argv[2].split(':')
output_name = sys.argv[3].split(':')
# Load inputs
inputs = []
for fn in glob(os.path.join(data_dir, 'input_*.pb')):
tensor = onnx.TensorProto()
with open(fn, 'rb') as f:
tensor.ParseFromString(f.read())
inputs.append(numpy_helper.to_array(tensor))
# Load outputs
outputs = []
for fn in glob(os.path.join(data_dir, 'output_*.pb')):
tensor = onnx.TensorProto()
with open(fn, 'rb') as f:
tensor.ParseFromString(f.read())
outputs.append(numpy_helper.to_array(tensor))
inputs = Dict(zip(input_names, inputs))
outputs = Dict(zip(output_name, outputs))
np.savez(data_dir, inputs=inputs, outputs=outputs)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Mar 22 11:19:45 2019
@author: Macrobull
Not all ops in this file are supported by both Pytorch and ONNX
This only demostrates the conversion/validation workflow from Pytorch to ONNX to Paddle
"""
from __future__ import print_function
import torch
import torch.nn as nn
import torch.nn.functional as F
from onnx2paddle.torch_export_helper import export_onnx_with_validation
idx = 0
######### example: RNN ########
#
#class Model(nn.Module):
# def __init__(self):
# super(Model, self).__init__()
# self.rnn = nn.RNN(4, 6, 2)
#
# def forward(self, x):
# y = x
# y, h = self.rnn(y)
# return y
#
#
#model = Model()
#xb = torch.rand((2, 3, 4))
#yp = model(xb)
#idx += 1
#print('index: ', idx)
#export_onnx_with_validation(model, (xb, ), 't' + str(idx),
# ['x'], ['y'],
# verbose=True, training=False)
######### example: random ########
#
#class Model(nn.Module):
# def __init__(self):
# super(Model, self).__init__()
#
# def forward(self, x):
# y = torch.rand((2, 3)) # + torch.rand_like(xb)
# y = y + torch.randn((2, 3)) # + torch.randn_like(xb)
# return y
#
#
#model = Model()
#xb = torch.rand((2, 3))
#yp = model(xb)
#idx += 1
#print('index: ', idx)
#export_onnx_with_validation(model, (xb, ), 't' + str(idx),
# ['x'], ['y'],
# verbose=True, training=False)
######## example: fc ########
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.fc = nn.Linear(3, 8)
def forward(self, x):
y = x
y = self.fc(y)
return y
model = Model()
xb = torch.rand((2, 3))
yp = model(xb)
idx += 1
print('index: ', idx)
export_onnx_with_validation(model, (xb, ), 't' + str(idx),
['x'], ['y'],
verbose=True, training=False)
######## example: compare ########
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
def forward(self, x0, x1):
x0 = x0.clamp(-1, 1)
a = torch.max(x0, x1) == x1
b = x0 < x1
c = x0 > x1
return a, b, c
model = Model()
xb0 = torch.rand((2, 3))
xb1 = torch.rand((2, 3))
ya, yb, yc = model(xb0, xb1)
idx += 1
print('index: ', idx)
export_onnx_with_validation(model, (xb0, xb1), 't' + str(idx),
['x0', 'x1'], ['ya', 'yb', 'yc'],
verbose=True, training=False)
######## example: affine_grid ########
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
def forward(self, theta):
grid = F.affine_grid(theta, (2, 2, 8, 8))
return grid
model = Model()
theta = torch.rand((2, 2, 3))
grid = model(theta)
idx += 1
print('index: ', idx)
export_onnx_with_validation(model, (theta, ), 't' + str(idx),
['theta'], ['grid'],
verbose=True, training=False)
######## example: conv2d_transpose ########
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.conv = nn.ConvTranspose2d(3, 8, 3)
self.dropout = nn.Dropout2d()
def forward(self, x):
y = x
y = self.conv(y)
y = self.dropout(y)
return y
model = Model()
xb = torch.rand((2, 3, 4, 5))
yp = model(xb)
idx += 1
print('index: ', idx)
export_onnx_with_validation(model, (xb, ), 't' + str(idx),
['x'], ['y'],
verbose=True, training=False)
######## example: conv2d ########
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.conv = nn.Conv2d(3, 8, 3)
self.batch_norm = nn.BatchNorm2d(8)
self.pool = nn.AdaptiveAvgPool2d(2)
def forward(self, x):
y = x
y = self.conv(y)
y = self.batch_norm(y)
y = self.pool(y)
return y
model = Model()
xb = torch.rand((2, 3, 4, 5))
yp = model(xb)
idx += 1
print('index: ', idx)
export_onnx_with_validation(model, (xb, ), 't' + str(idx),
['x'], ['y'],
verbose=True, training=False)
######### example: conv1d ########
#
#class Model(nn.Module):
# def __init__(self):
# super(Model, self).__init__()
# self.batch_norm = nn.BatchNorm2d(3)
#
# def forward(self, x):
# y = x
# y = self.batch_norm(y)
# return y
#
#
#model = Model()
#xb = torch.rand((2, 3, 4, 5))
#yp = model(xb)
#idx += 1
#print('index: ', idx)
#export_onnx_with_validation(model, (xb, ), 't' + str(idx),
# ['x'], ['y'],
# verbose=True, training=False)
######## example: empty ########
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
def forward(self, x):
return x
model = Model()
xb = torch.rand((2, 3))
yp = model(xb)
idx += 1
print('index: ', idx)
export_onnx_with_validation(model, (xb, ), 't' + str(idx),
['y'], ['y'],
verbose=True, training=False)
#! /usr/bin/env sh
get_url="proxychains4 aria2c -c -s8 -x8"
base_url="https://s3.amazonaws.com/download.onnx/models/opset_9/"
flags="-de -o /tmp/export/"
bvlc_alexnet()
{
bn_tar="bvlc_alexnet"
fn_tar="$bn_tar.tar.gz"
fn_model="$bn_tar/model.onnx"
$get_url "$base_url$fn_tar"
echo "extracting ..."
tar xf "$fn_tar"
for npz in $bn_tar/*.npz
do
echo "converting $npz ..."
python convert_data_npz_0.py "$npz" "data_0" "prob_1"
python -m onnx2paddle $flags "$fn_model" -t $npz
done
for pb_dir in $bn_tar/*/
do
echo "converting $pb_dir ..."
python convert_data_pb_0.py "$pb_dir" "data_0" "prob_1"
python -m onnx2paddle $flags "$fn_model" -t echo $(dirname "$pb_dir/x").npz
done
}
bvlc_googlenet()
{
bn_tar="bvlc_googlenet"
fn_tar="$bn_tar.tar.gz"
fn_model="$bn_tar/model.onnx"
$get_url "$base_url$fn_tar"
echo "extracting ..."
tar xf "$fn_tar"
for pb_dir in $bn_tar/*/
do
echo "converting $pb_dir"
python convert_data_pb_0.py "$pb_dir" "data_0" "prob_1"
python -m onnx2paddle $flags "$fn_model" -t $(dirname "$pb_dir/x").npz
done
}
bvlc_reference_caffenet()
{
bn_tar="bvlc_reference_caffenet"
fn_tar="$bn_tar.tar.gz"
fn_model="$bn_tar/model.onnx"
$get_url "$base_url$fn_tar"
echo "extracting ..."
tar xf "$fn_tar"
for pb_dir in $bn_tar/*/
do
echo "converting $pb_dir"
python convert_data_pb_0.py "$pb_dir" "data_0" "prob_1"
python -m onnx2paddle $flags "$fn_model" -t $(dirname "$pb_dir/x").npz
done
}
bvlc_reference_rcnn_ilsvrc13()
{
bn_tar="bvlc_reference_rcnn_ilsvrc13"
fn_tar="$bn_tar.tar.gz"
fn_model="$bn_tar/model.onnx"
$get_url "$base_url$fn_tar"
echo "extracting ..."
tar xf "$fn_tar"
for pb_dir in $bn_tar/*/
do
echo "converting $pb_dir"
python convert_data_pb_0.py "$pb_dir" "data_0" "softmaxout_1"
python -m onnx2paddle $flags "$fn_model" -t $(dirname "$pb_dir/x").npz
done
}
inception_v1()
{
bn_tar="inception_v1"
fn_tar="$bn_tar.tar.gz"
fn_model="$bn_tar/model.onnx"
$get_url "$base_url$fn_tar"
echo "extracting ..."
tar xf "$fn_tar"
for npz in $bn_tar/*.npz
do
echo "converting $npz ..."
python convert_data_npz_0.py "$npz" "data_0" "prob_1"
python -m onnx2paddle $flags "$fn_model" -t $npz
done
for pb_dir in $bn_tar/*/
do
echo "converting $pb_dir"
python convert_data_pb_0.py "$pb_dir" "data_0" "prob_1"
python -m onnx2paddle $flags "$fn_model" -t $(dirname "$pb_dir/x").npz
done
}
inception_v2()
{
bn_tar="inception_v2"
fn_tar="$bn_tar.tar.gz"
fn_model="$bn_tar/model.onnx"
$get_url "$base_url$fn_tar"
echo "extracting ..."
tar xf "$fn_tar"
for npz in $bn_tar/*.npz
do
echo "converting $npz ..."
python convert_data_npz_0.py "$npz" "data_0" "prob_1"
python -m onnx2paddle $flags "$fn_model" -t $npz
done
for pb_dir in $bn_tar/*/
do
echo "converting $pb_dir"
python convert_data_pb_0.py "$pb_dir" "data_0" "prob_1"
python -m onnx2paddle $flags "$fn_model" -t $(dirname "$pb_dir/x").npz
done
}
resnet50()
{
bn_tar="resnet50"
fn_tar="$bn_tar.tar.gz"
fn_model="$bn_tar/model.onnx"
$get_url "$base_url$fn_tar"
echo "extracting ..."
tar xf "$fn_tar"
for npz in $bn_tar/*.npz
do
echo "converting $npz ..."
python convert_data_npz_0.py "$npz" "gpu_0/data_0" "gpu_0/softmaxout_1"
python -m onnx2paddle $flags "$fn_model" -t $npz
done
for pb_dir in $bn_tar/*/
do
echo "converting $pb_dir"
python convert_data_pb_0.py "$pb_dir" "gpu_0/data_0" "gpu_0/softmaxout_1"
python -m onnx2paddle $flags "$fn_model" -t $(dirname "$pb_dir/x").npz
done
}
shufflenet()
{
bn_tar="shufflenet"
fn_tar="$bn_tar.tar.gz"
fn_model="$bn_tar/model.onnx"
$get_url "$base_url$fn_tar"
echo "extracting ..."
tar xf "$fn_tar"
for pb_dir in $bn_tar/*/
do
echo "converting $pb_dir"
python convert_data_pb_0.py "$pb_dir" "gpu_0/data_0" "gpu_0/softmaxout_1"
python -m onnx2paddle $flags "$fn_model" -t $(dirname "$pb_dir/x").npz
done
}
squeezenet()
{
bn_tar="squeezenet"
fn_tar="$bn_tar.tar.gz"
fn_model="$bn_tar/model.onnx"
$get_url "$base_url$fn_tar"
echo "extracting ..."
tar xf "$fn_tar"
for pb_dir in $bn_tar/*/
do
echo "converting $pb_dir"
python convert_data_pb_0.py "$pb_dir" "data_0" "softmaxout_1"
python -m onnx2paddle $flags "$fn_model" -t $(dirname "$pb_dir/x").npz
done
}
tiny_yolov2()
{
bn_tar="tiny_yolov2"
fn_tar="$bn_tar.tar.gz"
fn_model="$bn_tar/model.onnx"
$get_url "https://onnxzoo.blob.core.windows.net/models/opset_8/tiny_yolov2/$fn_tar"
echo "extracting ..."
tar xf "$fn_tar"
for pb_dir in $bn_tar/*/
do
echo "converting $pb_dir"
python convert_data_pb_0.py "$pb_dir" "image" "grid"
python -m onnx2paddle $flags "$fn_model" -t $(dirname "$pb_dir/x").npz -x
done
}
vgg19()
{
bn_tar="vgg19"
fn_tar="$bn_tar.tar.gz"
fn_model="$bn_tar/model.onnx"
$get_url "$base_url$fn_tar"
echo "extracting ..."
tar xf "$fn_tar"
for pb_dir in $bn_tar/*/
do
echo "converting $pb_dir"
python convert_data_pb_0.py "$pb_dir" "data_0" "prob_1"
python -m onnx2paddle $flags "$fn_model" -t $(dirname "$pb_dir/x").npz
done
}
zfnet512()
{
bn_tar="zfnet512"
fn_tar="$bn_tar.tar.gz"
fn_model="$bn_tar/model.onnx"
$get_url "$base_url$fn_tar"
echo "extracting ..."
tar xf "$fn_tar"
for pb_dir in $bn_tar/*/
do
echo "converting $pb_dir"
python convert_data_pb_0.py "$pb_dir" "gpu_0/data_0" "gpu_0/softmax_1"
python -m onnx2paddle $flags "$fn_model" -t $(dirname "$pb_dir/x").npz
done
}
bvlc_alexnet # data error
bvlc_googlenet # desc error
bvlc_reference_caffenet
bvlc_reference_rcnn_ilsvrc13
inception_v1 ###
inception_v2 ###
resnet50 # data error
shufflenet ###
squeezenet
tiny_yolov2 # not supported
vgg19
zfnet512 # data error
# -*- coding: UTF-8 -*-
################################################################################
#
# Copyright (c) 2019 Baidu.com, Inc. All Rights Reserved
#
################################################################################
"""
本文件允许模块包以python -m onnx2paddle方式直接执行。
Authors: Macrobull
Date: 2019/02/22 10:25:46
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
# import argparse, logging, sys
import argparse
import logging
import sys
parser = argparse.ArgumentParser(description='onnx2paddle',
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument('model', nargs=1,
help='path to model.onnx',
)
parser.add_argument('--debug', '-d', action='store_true',
help='enable debug logging and checking',
)
parser.add_argument('--output-dir', '-o', type=str, default='',
help='output directory',
)
parser.add_argument('--test_data', '-t', type=str, default='',
help='I/O golden data for validation, e.g. test.npy, test.npz',
)
parser.add_argument('--embed_params', '-e', action='store_true',
help='try to embed parameters for trainable Paddle layers',
)
parser.add_argument('--pedantic', action='store_true', default=True,
help='accept and convert only standard ONNX opset',
)
parser.add_argument('--no-pedantic', '-x', action='store_false',
dest='pedantic',
help='process non-standard ONNX ops, this may lead to fails',
)
parser.add_argument('--precision', '-p', type=int, default=4,
help='assertion decimal for validation',
)
args = parser.parse_args()
logging_format = '[%(levelname)8s]%(name)s::%(funcName)s:%(lineno)04d: %(message)s'
logging_level = logging.DEBUG if args.debug else logging.INFO
logging.basicConfig(format=logging_format, level=logging_level)
try:
from . import cmdline
except ImportError:
import cmdline
# imports
main = cmdline.main
sys.exit(main(**args.__dict__))
# -*- coding: UTF-8 -*-
################################################################################
#
# Copyright (c) 2019 Baidu.com, Inc. All Rights Reserved
#
################################################################################
"""
本文件提供了命令行工具的入口逻辑。
Authors: Macrobull
Date: 2019/02/22 10:25:46
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
# import logging, shutil, zipfile
import logging
import shutil
import zipfile
__all__ = [
'main',
]
DEFAULT_ONNX_OPSET_VERSION = 9
DEFAULT_MODEL_MODULE = 'model'
DEFAULT_MODEL_FUNC = 'inference'
def main(**kwargs):
"""主程序入口"""
try:
from . import conversion
except ImportError:
import conversion
# imports
convert = conversion.convert
logger = logging.getLogger('onnx2paddle')
debug = kwargs.get('debug', False)
# prepare arguments
filename = kwargs['model'][0]
basepath, _ = shutil.os.path.splitext(filename)
save_dir = kwargs.get('output_dir', '')
# model.onnx -> model/
save_dir = shutil.os.path.dirname(save_dir) if save_dir else basepath
model_basename = DEFAULT_MODEL_MODULE + '.py'
model_func_name = DEFAULT_MODEL_FUNC
embed_params = kwargs.get('embed_params', False)
onnx_opset_version = DEFAULT_ONNX_OPSET_VERSION
onnx_opset_pedantic = kwargs.get('pedantic', True)
# convert
convert(filename, save_dir,
model_basename=model_basename,
model_func_name=model_func_name,
embed_params=embed_params,
onnx_opset_version=onnx_opset_version,
onnx_opset_pedantic=onnx_opset_pedantic,
debug=debug)
# validate
passed = True
golden_data_filename = kwargs.get('test_data', '')
if golden_data_filename:
try:
from . import validation
except ImportError:
import validation
# imports
validate = validation.validate
# in fact fluid can not fully clear the context
# continuous validation may be inaccurate
precision = 10 ** -kwargs.get('precision', 4)
logger.info('starting validation on desc ...')
passed &= validate(shutil.os.path.join(save_dir, '__model__'),
golden_data_filename,
precision=precision,
)
logger.info('starting validation on code ...')
passed &= validate(shutil.os.path.join(save_dir, model_basename),
golden_data_filename,
model_func_name=model_func_name,
precision=precision,
save_inference_model=debug, # this overwrite desc file for test
)
if not passed:
logger.error('validation failed, exit')
return
# create zip file
fn_zip = save_dir.rstrip('/') + '.zip'
logger.info('compressing file to %s ...', fn_zip)
fz = zipfile.ZipFile(fn_zip, 'w', compression=zipfile.ZIP_LZMA)
for fn in shutil.os.listdir(save_dir):
fz.write(shutil.os.path.join(save_dir, fn), arcname=fn)
fz.close()
logger.info('compressing done')
if __name__ == '__main__':
logging.basicConfig(
format='[%(levelname)8s]%(name)s::%(funcName)s:%(lineno)04d: %(message)s',
level=logging.DEBUG,
)
# main(model=['../examples/t5.onnx'],
# output_dir='/tmp/export/',
# embed_params=False,
# pedantic=False,
# test_data='../examples/t5.npz',
# debug=True)
main(model=['../examples/shufflenet/model.onnx'],
output_dir='/tmp/export/',
embed_params=True,
pedantic=False,
test_data='../examples/shufflenet/test_data_set_0.npz',
debug=True)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Feb 25 09:50:35 2019
@author: Macrobull
"""
from __future__ import division
# import logging, shutil
import logging
import shutil
__all__ = [
'convert',
]
def convert(onnx_model_filename, save_dir,
model_basename='model.py', model_func_name='inference',
embed_params=False,
onnx_opset_version=9, onnx_opset_pedantic=True,
debug=False):
"""
convert an ONNX model to Paddle Python code and desc pb
"""
import onnx
from onnx.checker import ValidationError
from onnx.checker import check_model
from onnx.utils import polish_model
from onnx.version_converter import convert_version
try:
from . import onnx_utils, writer
except ImportError:
import onnx_utils, writer
# imports
DEFAULT_OP_DOMAIN = onnx_utils.DEFAULT_OP_DOMAIN
graph_ops, graph_weights = onnx_utils.graph_ops, onnx_utils.graph_weights
inferred_model_value_info = onnx_utils.inferred_model_value_info
optimize_model_skip_op_for_inference = onnx_utils.optimize_model_skip_op_for_inference
optimize_model_strip_initializer = onnx_utils.optimize_model_strip_initializer
optimize_model_cast = onnx_utils.optimize_model_cast
optimize_model_slice = onnx_utils.optimize_model_slice
Program, Writer = writer.Program, writer.Writer
make_var_name = writer.make_var_name
logger = logging.getLogger('convert')
# prepare onnx model
logger.info('loading model: %s ...', onnx_model_filename)
onnx_model = onnx.load(onnx_model_filename)
try:
logger.info('checking model ...')
check_model(onnx_model)
logger.debug('using opset version: %d', onnx_opset_version)
if onnx_opset_pedantic: # WORKAROUND: RuntimeError: No Adapter For OP
onnx_model = convert_version(onnx_model, onnx_opset_version)
else: # TODO: add new argument for this option
logger.warning('opset conversion skipped for onnx_opset_pedantic is OFF')
onnx_model = polish_model(onnx_model)
except ValidationError as e:
if onnx_opset_pedantic:
raise e
else:
logger.warning('due to onnx_opset_pedantic is OFF')
logger.warning('the ONNX model sanity checking error is suppressed')
logger.warning('value_info inferring may be uncompleted')
# onnx model optimization
logger.info('optimizing model ...')
onnx_model = optimize_model_skip_op_for_inference(onnx_model)
onnx_model = optimize_model_strip_initializer(onnx_model)
onnx_model = optimize_model_cast(onnx_model)
onnx_model = optimize_model_slice(onnx_model)
# prepare filesystem
shutil.rmtree(save_dir, ignore_errors=True)
shutil.os.makedirs(save_dir, exist_ok=True)
logger.info('folder %s cleared', save_dir)
# DEBUG:
if debug:
model = onnx.shape_inference.infer_shapes(onnx_model)
debug_model_filename, _ = shutil.os.path.splitext(onnx_model_filename)
onnx.save(model, debug_model_filename + '.optimized_and_inffered.onnx')
# onnx.save(model, '/tmp/export/optimized_and_inffered.onnx')
# I/O instances
onnx_graph = onnx_model.graph
paddle_program = Program()
paddle_writer = Writer()
# model components
# graph_name = onnx_graph.name
graph_inputs = [value.name for value in onnx_graph.input]
graph_outputs = [value.name for value in onnx_graph.output]
graph_params = []
graph_value_infos = inferred_model_value_info(onnx_model)
# prepare additional value_info
# for weights
for name, weight in graph_weights(onnx_graph):
value_info = graph_value_infos[name]
value_info['embeded_as'] = []
value_info['get_weight'] = lambda: weight.tolist() # lazy getter
logger.info('conversion started')
# op set conversion
# topo = 'backward' if embed_params else 'forward'
topo = 'forward'
for name, domain, op_type, inputs, outputs, attrs in graph_ops(onnx_graph, topo=topo):
logger.debug('translating op %s %s::%s ...', name, domain, op_type)
if domain == DEFAULT_OP_DOMAIN:
domain = ''
try:
paddle_writer.emit_op(paddle_program, name, domain, op_type,
inputs, outputs, attrs,
graph_value_infos,
embed_params=embed_params,
)
except BaseException as e:
logger.fatal('conversion failed for:\n\t%s -> %s::%s -> %s',
inputs, domain, op_type, outputs)
raise e
op_codes = paddle_program.codes
paddle_program.codes = []
logger.info('%d ops converted', len(paddle_program.op_descs))
# weight writer
for name, weight in graph_weights(onnx_graph):
graph_params.append(name)
value_info = graph_value_infos[name]
var_names = value_info.get('embeded_as', [])
if var_names:
if len(var_names) > 1:
logger.info('weight %s is shared between ops, more disk space will be consumed', name)
logger.debug('saving weight %s with size of %d, in %d bytes, as %s ...',
name, weight.size, weight.nbytes, var_names)
for var_name in var_names: # multiple references
paddle_writer.write_weight(weight, shutil.os.path.join(save_dir, var_name))
else:
logger.debug('saving weight %s with size of %d, in %d bytes, to %s ...',
name, weight.size, weight.nbytes, make_var_name(name))
paddle_writer.write_weight(weight, shutil.os.path.join(save_dir, make_var_name(name)))
paddle_writer.emit_param(paddle_program, name, value_info)
param_codes = paddle_program.codes
paddle_program.codes = []
logger.info('%d weights converted', len(graph_params))
# input writer
external_inputs = []
for name in graph_inputs:
if name not in graph_params:
value_info = graph_value_infos[name]
assert value_info['external']
external_inputs.append(name)
paddle_writer.emit_inputs(paddle_program, external_inputs, graph_value_infos, remove_batch=False) # TODO:
input_codes = paddle_program.codes
paddle_program.codes = []
logger.info('%d inputs converted', len(external_inputs))
# output writer
external_outputs = []
for name in graph_outputs:
if name not in graph_params:
value_info = graph_value_infos[name]
assert value_info['external']
external_outputs.append(name)
paddle_writer.emit_outputs(paddle_program, external_outputs)
output_codes = [''] + paddle_program.codes # add an empty line
paddle_program.codes = []
logger.info('%d outputs converted', len(external_outputs))
# code generation
code_filename = shutil.os.path.join(save_dir, model_basename)
paddle_writer.write_code_file(code_filename, paddle_writer.header_code(model_func_name),
input_codes, param_codes, op_codes, output_codes)
logger.info('code saved to %s, factory function: %s', code_filename, model_func_name)
# desc generation
desc_filename = shutil.os.path.join(save_dir, '__model__')
paddle_writer.write_desc_file(desc_filename,
op_descs=paddle_program.op_descs,
var_descs=paddle_program.var_descs,
)
logger.info('program saved to %s', desc_filename)
logger.info('conversion finished')
# globals().update(locals())
if __name__ == '__main__':
logging.basicConfig(
format='[%(levelname)8s]%(name)s::%(funcName)s:%(lineno)04d: %(message)s',
level=logging.DEBUG,
)
model_list = [
'../examples/t1.onnx',
'../examples/t2.onnx',
'../examples/t3.onnx',
'../examples/t4.onnx',
'../examples/t5.onnx',
'../examples/t6.onnx',
# '../examples/t7.onnx',
# '../examples/t8.onnx',
]
for model in model_list:
pathname, _ = shutil.os.path.splitext(model)
convert(model, pathname,
onnx_opset_pedantic=False, debug=True)
convert(model, pathname + '.embeded',
embed_params=True, onnx_opset_pedantic=False, debug=True)
此差异已折叠。
此差异已折叠。
此差异已折叠。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Mar 22 11:22:46 2019
@author: Macrobull
"""
import numpy as np
import torch
from collections import OrderedDict as Dict
def _ensure_list(obj):
if isinstance(obj, (list, set, tuple)):
return list(obj)
return [obj]
def _ensure_tuple(obj):
if isinstance(obj, (list, set, tuple)):
return tuple(obj)
return (obj, )
def _flatten_list(obj,
out=None):
assert isinstance(obj, list)
if out is None:
out = type(obj)()
for item in obj:
if isinstance(item, list):
_flatten_list(item, out)
else:
out.append(item)
return out
def export_data(state_dict,
prefix=''):
"""
export binary data with meta text for raw C++ inference engines
"""
def _str(obj):
if isinstance(obj, (tuple, list)):
return str(obj)[1:-1].replace(' ', '')
return str(obj)
prefix_ = prefix + ('_' if prefix else '')
fp = open('{}.txt'.format(prefix if prefix else 'meta'), 'w')
for key, value in state_dict.items():
data = None
if torch and torch.is_tensor(value):
data = value.data.cpu().numpy()
elif np and isinstance(value, np.ndarray):
data = value
if data is not None:
data.tofile('{}{}.bin'.format(prefix_, key))
fp.write('{}.dtype={}\n'.format(key, _str(data.dtype.name)))
fp.write('{}.shape={}\n'.format(key, _str(data.shape)))
else:
fp.write('{}={}\n'.format(key, _str(value)))
fp.close()
def export_onnx_with_validation(model, inputs, export_basepath,
input_names=None, output_names=None,
use_npz=True,
*args, **kwargs):
"""
export PyTorch model to ONNX model and export sample inputs and outputs in a Numpy file
"""
is_list_or_tuple = lambda x: isinstance(x, (list, tuple))
def _tensors_to_arrays(tensors):
if torch.is_tensor(tensors):
return tensors.data.cpu().numpy()
arrays = []
for tensor in tensors:
arrays.append(_tensors_to_arrays(tensor))
return arrays
def _zip_dict(keys, values):
ret = Dict()
for idx, (key, value) in enumerate(zip(keys, values)):
is_key_list = is_list_or_tuple(key)
is_value_list = is_list_or_tuple(value)
assert is_key_list == is_value_list, 'keys and values mismatch'
if is_value_list:
ret[str(idx)] = _zip_dict(key, value)
else:
ret[key] = value
return ret
torch_inputs = _ensure_tuple(inputs) # WORKAROUND: for torch.onnx
outputs = torch.onnx.export(model, torch_inputs, export_basepath + '.onnx',
input_names=_flatten_list(input_names),
output_names=_flatten_list(output_names),
*args, **kwargs)
if outputs is None: # WORKAROUND: for torch.onnx
outputs = model(*inputs)
torch_outputs = _ensure_tuple(outputs)
inputs = _zip_dict(input_names, _tensors_to_arrays(torch_inputs))
outputs = _zip_dict(output_names, _tensors_to_arrays(torch_outputs))
if use_npz:
np.savez(export_basepath + '.npz', inputs=inputs, outputs=outputs)
else:
np.save(export_basepath + '.npy',
np.array(Dict(inputs=inputs, outputs=outputs)))
return torch_outputs
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Mar 22 12:17:19 2019
@author: Macrobull
"""
# import importlib, logging, os, sys
import importlib
import logging
import os
import sys
def _flatten_dict(obj,
out=None):
assert isinstance(obj, dict)
if out is None:
out = type(obj)()
for key, value in obj.items():
if isinstance(value, dict):
_flatten_dict(value, out)
else:
assert key not in out
out[key] = value
return out
def _ensure_list(obj):
for cls in [list, set, tuple]:
if isinstance(obj, cls):
return list(obj)
return [obj]
def validate(paddle_model_filename, golden_data_filename,
model_func_name='inference',
precision=1e-4,
save_inference_model=False):
"""
inferece the converted Paddle model, validate with given golden data
"""
import numpy as np
import paddle.fluid as fluid
logger = logging.getLogger('validate')
place = fluid.CPUPlace()
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())
# load model
paddle_model_dir, basename = os.path.split(paddle_model_filename)
if basename == '__model__': # is desc model
logger.debug('using desc file %s', basename)
prog, in_names, var_outs = fluid.io.load_inference_model(paddle_model_dir, exe)
out_names = var_outs # HINT: pass var if fetch ops already created
logger.info('model load passed')
elif basename.endswith('.py'): # is python code
logger.debug('using python code file %s', basename)
module_name, _ = os.path.splitext(basename)
sys_path = sys.path.copy()
sys.path.append(paddle_model_dir)
try:
module = importlib.import_module(module_name)
func = getattr(module, model_func_name)
except AttributeError:
module_name = module_name + '.' + module_name
module = importlib.import_module(module_name)
func = getattr(module, model_func_name)
sys.path = sys_path
logger.debug('from %s imported %s: %s', module_name, model_func_name, func)
var_outs = func()
var_outs = _ensure_list(var_outs)
out_names = [var.name for var in var_outs] # HINT: pass string to create fetch ops
logger.info('import passed')
prog = fluid.default_main_program()
fluid.io.load_persistables(executor=exe, dirname=paddle_model_dir, main_program=prog)
logger.info('weight load passed')
else:
raise ValueError('unsupported Paddle model')
# load data
logger.info('using golden data %s', golden_data_filename)
if golden_data_filename.endswith('.npz'):
test_data = np.load(golden_data_filename)
input_data = test_data['inputs'].tolist()
output_data = test_data['outputs'].tolist()
else:
test_data = np.load(golden_data_filename).tolist()
input_data = input_data['inputs']
output_data = output_data['outputs']
input_data = _flatten_dict(input_data)
output_data = _flatten_dict(output_data)
logger.info('found %d I/O golden data, starting test ...', len(test_data))
# DEBUG: reload test for python code
if basename.endswith('.py') and save_inference_model:
fluid.io.save_inference_model(paddle_model_dir, input_data.keys(), var_outs, exe,
main_program=prog, export_for_deployment=True)
logger.info('model re-save passed')
fluid.io.load_inference_model(paddle_model_dir, exe)
logger.info('model re-load passed')
# execute
outputs = exe.run(prog, feed=input_data, fetch_list=out_names)
logger.info('execution passed')
# validate
passed = True
for (name, truth), output in zip(output_data.items(), outputs):
logger.info('testing output {} ...'.format(name))
try:
np.testing.assert_almost_equal(output, truth, decimal=precision)
except AssertionError as e:
passed = False
logger.error('failed: %s\n', e)
if passed:
logger.info('accuracy passed')
else:
logger.info('accuracy not passed')
# globals().update(locals())
return passed
if __name__ == '__main__':
logging.basicConfig(
format='[%(levelname)8s]%(name)s::%(funcName)s:%(lineno)04d: %(message)s',
level=logging.DEBUG,
)
logger = logging.getLogger('validation_test')
model_rc_list = [
'../examples/t{}/model.py',
'../examples/t{}/__model__',
'../examples/t{}.embeded/model.py',
'../examples/t{}.embeded/__model__',
]
import numpy as np
idx_model = np.random.randint(1, 7)
model = np.random.choice(model_rc_list).format(idx_model)
precision = 10 ** (np.random.rand() * -4 - 2)
debug = False
model = '/tmp/export/model.py'
# model = '../examples/t1/__model__'
# model = '../examples/t1.embeded/model.py'
# model = '../examples/t1.embeded/__model__'
debug = True
logger.info('args: %s %.6f', model, precision)
data_dir, dir_name = os.path.split(os.path.split(model)[0])
data_pathname = os.path.splitext(dir_name)[0]
# proto debug test
from framework_pb2 import ProgramDesc
pd = ProgramDesc()
pd.ParseFromString(open(os.path.join(data_dir, dir_name, '__model__'), 'rb').read())
# validate
# validate(model, os.path.join(data_dir, data_pathname + '.npz'),
# precision=precision, save_inference_model=debug)
validate(model, '../examples/bvlc_alexnet/test_data_0.npz',
precision=precision, save_inference_model=debug)
此差异已折叠。
-e .
onnx>=1.4.0
paddlepaddle
\ No newline at end of file
此差异已折叠。
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
################################################################################
#
# Copyright (c) 2019 Baidu.com, Inc. All Rights Reserved
#
################################################################################
"""
Setup script.
Authors: Macrobull
Date: 2019/02/22 10:25:46
"""
import setuptools
setuptools.setup()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册