提交 e161a582 编写于 作者: C Channingss

optimize code structure

上级 4bb2953c
...@@ -172,12 +172,11 @@ def onnx2paddle(model_path, save_dir, params_merge=False): ...@@ -172,12 +172,11 @@ def onnx2paddle(model_path, save_dir, params_merge=False):
return return
print("Now translating model from onnx to paddle.") print("Now translating model from onnx to paddle.")
from x2paddle.op_mapper.onnx.onnx_helper import ONNXOpMapperFactory from x2paddle.op_mapper.onnx_op_mapper import ONNXOpMapper
from x2paddle.decoder.onnx_decoder import ONNXDecoder from x2paddle.decoder.onnx_decoder import ONNXDecoder
from x2paddle.optimizer.onnx_optimizer import ONNXOptimizer from x2paddle.optimizer.onnx_optimizer import ONNXOptimizer
model = ONNXDecoder(model_path) model = ONNXDecoder(model_path)
factory = ONNXOpMapperFactory() mapper = ONNXOpMapper(model)
mapper = factory.create_onnx_op_mapper(model)
print("Model optimizing ...") print("Model optimizing ...")
optimizer = ONNXOptimizer(mapper) optimizer = ONNXOptimizer(mapper)
print("Model optimized.") print("Model optimized.")
......
...@@ -25,6 +25,7 @@ class Layer(object): ...@@ -25,6 +25,7 @@ class Layer(object):
self.inputs = dict() self.inputs = dict()
self.output = None self.output = None
self.is_custom_layer = False self.is_custom_layer = False
self.use_fluid = False
def get_code(self): def get_code(self):
layer_code = "" layer_code = ""
...@@ -38,6 +39,8 @@ class Layer(object): ...@@ -38,6 +39,8 @@ class Layer(object):
layer_code = layer_code + self.op + "(" layer_code = layer_code + self.op + "("
elif self.op == "=": elif self.op == "=":
layer_code = layer_code layer_code = layer_code
elif self.use_fluid:
layer_code = layer_code + "fluid." + self.op + "("
else: else:
layer_code = layer_code + "fluid.layers." + self.op + "(" layer_code = layer_code + "fluid.layers." + self.op + "("
...@@ -108,9 +111,11 @@ class FluidCode(object): ...@@ -108,9 +111,11 @@ class FluidCode(object):
inputs, inputs,
output, output,
param_attr=None, param_attr=None,
use_fluid=False,
is_custom_layer=False): is_custom_layer=False):
layer = Layer() layer = Layer()
layer.op = op layer.op = op
layer.use_fluid = use_fluid
layer.is_custom_layer = is_custom_layer layer.is_custom_layer = is_custom_layer
if inputs is not None: if inputs is not None:
layer.inputs = inputs layer.inputs = inputs
......
# Copyright (c) 2019 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.
from collections import OrderedDict as _dict
import numpy as _np
default_op_mapping_field_values = _dict()
default_op_mapping_field_values['FLUID_OP'] = ''
default_op_mapping_field_values['FLUID_INPUT_ARGS'] = None
default_op_mapping_field_values['FLUID_OUTPUT_ARGS'] = None
default_op_mapping_field_values['ATTR_MAPPING'] = dict()
default_op_mapping_field_values['DEFAULTS'] = dict()
default_op_mapping_field_values['INPUT_PERM'] = None
default_op_mapping_field_values['OUTPUT_PERM'] = None
default_op_mapping_field_values['FILL_NAME_FIELD'] = True
default_op_mapping = {
'Shape': ['shape', ['X'], ['Out']],
'Clip': [
'clip', ['X'], ['Out'], dict(), dict(
min=(_np.asarray(
[255, 255, 127, 255], dtype=_np.uint8).view(_np.float32)[0]),
max=(_np.asarray(
[255, 255, 127, 127], dtype=_np.uint8).view(_np.float32)[0]), )
],
'Erf': ['erf', ['X'], ['Out']],
'Ceil': ['ceil', ['X'], ['Out']],
'ReduceMean': [
'reduce_mean', ['X'], ['Out'], dict(
axes='dim', keepdims='keep_dim'), dict(keep_dim=1)
],
'ReduceSum': [
'reduce_sum', ['X'], ['Out'], dict(
axes='dim', keepdims='keep_dim'), dict(keep_dim=1)
],
'ReduceMin': [
'reduce_min', ['X'], ['Out'], dict(
axes='dim', keepdims='keep_dim'), dict(keep_dim=1)
],
'ReduceMax': [
'reduce_max', ['X'], ['Out'], dict(
axes='dim', keepdims='keep_dim'), dict(keep_dim=1)
],
#active function
'Relu': ['relu', ['X'], ['Out']],
'LeakyRelu': ['leaky_relu', ['X'], ['Out'], dict(), dict(alpha=.01)],
'Elu': ['elu', ['X'], ['Out'], dict(), dict(alpha=1.)],
'ThresholdedRelu': [
'thresholded_relu', ['X'], ['Out'], dict(alpha='threshold'),
dict(alpha=1.)
],
'Tanh': ['tanh', ['X'], ['Out']],
'Sigmoid': ['sigmoid', ['X'], ['Out']],
'HardSigmoid': [
'hard_sigmoid', ['X'], ['Out'], dict(
alpha='slope', beta='offset'), dict(
slope=.2, offset=.5)
],
'Softsign': ['softsign', ['X'], ['Out']],
'Softplus': ['softplus', ['X'], ['Out']],
'Exp': ['exp', ['X'], ['Out']],
'Softmax': ['softmax', ['X'], ['Out'], dict(), dict(axis=1)],
'Sqrt': ['sqrt', ['X'], ['Out']],
'Floor': ['floor', ['X'], ['Out']],
'Abs': ['abs', ['X'], ['Out']],
}
default_ioa_constraint = {
'Gather': [(lambda i, o, a: a.get('axis', 0) == 0,
'only axis = 0 is supported')],
}
...@@ -12,30 +12,81 @@ ...@@ -12,30 +12,81 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from x2paddle.op_mapper.onnx.opset9 import ONNXOpMapperOpSet9 from x2paddle.op_mapper.onnx_opsets.opset9 import OpSet9
from x2paddle.core.op_mapper import OpMapper
from x2paddle.op_mapper.onnx_opsets.custom_layer import *
from x2paddle.decoder.onnx_decoder import ONNXGraph, ONNXGraphNode, ONNXGraphDataNode
class ONNXOpMapperFactory: class ONNXOpMapper(OpMapper):
def __init__(self): def __init__(self, decoder):
super(ONNXOpMapper, self).__init__()
self.support_op_sets = [9, ] self.support_op_sets = [9, ]
self.default_op_set = 9 self.default_op_set = 9
self.graph = decoder.graph
self.opset = self.create_opset(decoder)
if not self.op_checker():
raise Exception("Model are not supported yet.")
#mapping op
print("Total nodes: {}".format(
sum([
isinstance(node, ONNXGraphNode)
for name, node in self.graph.node_map.items()
])))
def create_onnx_op_mapper(self, decoder): print("Nodes converting ...")
for node_name in self.graph.topo_sort:
node = self.graph.get_node(node_name)
op = node.layer_type
if hasattr(self.opset, op):
func = getattr(self.opset, op)
func(node)
elif op in self.opset.default_op_mapping:
self.opset.directly_map(node)
elif op in custom_layers:
self.opser.deal_custom_layer(node)
elif op in self.opset.elementwise_ops:
self.opset.elementwise_map(node)
print("Nodes converted.")
self.weights = self.opset.weights
self.omit_nodes = self.opset.omit_nodes
self.used_custom_layers = self.opset.used_custom_layers
def op_checker(self):
unsupported_ops = set()
for node_name in self.graph.topo_sort:
node = self.graph.get_node(node_name)
op = node.layer_type
if not hasattr(self.opset, op) and \
op not in self.opset.default_op_mapping and \
op not in custom_layers and \
op not in self.opset.elementwise_ops:
unsupported_ops.add(op)
if len(unsupported_ops) == 0:
return True
else:
print("There are {} ops not supported yet, list as below".format(
len(unsupported_ops)))
for op in unsupported_ops:
print(op)
return False
def create_opset(self, decoder):
run_op_set = self.default_op_set run_op_set = self.default_op_set
OpMapper = '' opset = ''
if decoder.op_set in self.support_op_sets: if decoder.op_set in self.support_op_sets:
OpMapper = 'ONNXOpMapperOpSet' + str(decoder.op_set) opset = 'OpSet' + str(decoder.op_set)
elif decoder.op_set < self.default_op_set: elif decoder.op_set < self.default_op_set:
OpMapper = 'ONNXOpMapperOpSet' + str(self.default_op_set) opset = 'OpSet' + str(self.default_op_set)
else: else:
for op_set in self.support_op_sets: for op_set in self.support_op_sets:
if decoder.op_set > op_set: if decoder.op_set > op_set:
run_op_set = op_set run_op_set = op_set
else: else:
break break
OpMapper = 'ONNXOpMapperOpSet' + str(run_op_set) opset = 'OpSet' + str(run_op_set)
print( print(
'Now, onnx2paddle support convert onnx model opset_verison {},' 'Now, onnx2paddle support convert onnx model opset_verison {},'
'opset_verison of your onnx model is {}, automatically treated as op_set: {}.' 'opset_verison of your onnx model is {}, automatically treated as op_set: {}.'
.format(self.support_op_sets, decoder.op_set, run_op_set)) .format(self.support_op_sets, decoder.op_set, run_op_set))
return eval(OpMapper)(decoder) return eval(opset)(decoder)
...@@ -12,13 +12,12 @@ ...@@ -12,13 +12,12 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from x2paddle.decoder.onnx_decoder import ONNXGraph, ONNXGraphNode, ONNXGraphDataNode
from x2paddle.core.graph import GraphNode from x2paddle.core.graph import GraphNode
from x2paddle.core.op_mapper import OpMapper
from x2paddle.core.fluid_code import Layer from x2paddle.core.fluid_code import Layer
from x2paddle.core.fluid_code import FluidCode from x2paddle.core.fluid_code import FluidCode
from x2paddle.decoder.onnx_decoder import ONNXGraph, ONNXGraphNode, ONNXGraphDataNode
from x2paddle.op_mapper.onnx.custom_layer import *
from x2paddle.core.util import string from x2paddle.core.util import string
from functools import reduce
import numpy as np import numpy as np
import onnx import onnx
import onnx.numpy_helper as numpy_helper import onnx.numpy_helper as numpy_helper
...@@ -28,7 +27,6 @@ from collections import OrderedDict ...@@ -28,7 +27,6 @@ from collections import OrderedDict
import math import math
import os import os
import shutil import shutil
from functools import reduce
_logger = _logging.getLogger(__name__) _logger = _logging.getLogger(__name__)
...@@ -66,7 +64,7 @@ def print_mapping_info(func): ...@@ -66,7 +64,7 @@ def print_mapping_info(func):
return run_mapping return run_mapping
class ONNXOpMapperOpSet9(OpMapper): class OpSet9():
elementwise_ops = { elementwise_ops = {
'Add': 'elementwise_add', 'Add': 'elementwise_add',
'Div': 'elementwise_div', 'Div': 'elementwise_div',
...@@ -139,57 +137,13 @@ class ONNXOpMapperOpSet9(OpMapper): ...@@ -139,57 +137,13 @@ class ONNXOpMapperOpSet9(OpMapper):
} }
def __init__(self, decoder): def __init__(self, decoder):
super(ONNXOpMapperOpSet9, self).__init__() super(OpSet9, self).__init__()
self.graph = decoder.graph self.graph = decoder.graph
self.input_shapes = [] self.input_shapes = []
self.weights = dict() self.weights = dict()
self.omit_nodes = list() self.omit_nodes = list()
self.used_custom_layers = dict() self.used_custom_layers = dict()
if not self.op_checker():
raise Exception("Model are not supported yet.")
#mapping op
print("Total nodes: {}".format(
sum([
isinstance(node, ONNXGraphNode)
for name, node in self.graph.node_map.items()
])))
print("Nodes converting ...")
for node_name in self.graph.topo_sort:
node = self.graph.get_node(node_name)
op = node.layer_type
if hasattr(self, op):
func = getattr(self, op)
func(node)
elif op in self.default_op_mapping:
self.directly_map(node)
elif op in custom_layers:
self.deal_custom_layer(node)
elif op in self.elementwise_ops:
self.elementwise_map(node)
print("Nodes converted.")
def op_checker(self):
unsupported_ops = set()
for node_name in self.graph.topo_sort:
node = self.graph.get_node(node_name)
op = node.layer_type
if not hasattr(self, op) and \
op not in self.default_op_mapping and \
op not in custom_layers and \
op not in self.elementwise_ops:
unsupported_ops.add(op)
if len(unsupported_ops) == 0:
return True
else:
print("There are {} ops not supported yet, list as below".format(
len(unsupported_ops)))
for op in unsupported_ops:
print(op)
return False
@print_mapping_info @print_mapping_info
def directly_map(self, node, name='', *args, **kwargs): def directly_map(self, node, name='', *args, **kwargs):
inputs = node.layer.input inputs = node.layer.input
......
...@@ -2,6 +2,8 @@ import onnx ...@@ -2,6 +2,8 @@ import onnx
import numpy as np import numpy as np
from onnx import onnx_pb, helper from onnx import onnx_pb, helper
MAX_FLOAT = np.asarray([255, 255, 127, 127], dtype=np.uint8).view(np.float32)[0]
def get_old_name(arg, name_prefix=''): def get_old_name(arg, name_prefix=''):
prefix_index = arg.find(name_prefix) prefix_index = arg.find(name_prefix)
...@@ -747,36 +749,53 @@ def yolo_box(op, block): ...@@ -747,36 +749,53 @@ def yolo_box(op, block):
outputs_pred_box_x2_clip = [model_name + "@pred_box_x2_clip"] outputs_pred_box_x2_clip = [model_name + "@pred_box_x2_clip"]
outputs_pred_box_y2_clip = [model_name + "@pred_box_y2_clip"] outputs_pred_box_y2_clip = [model_name + "@pred_box_y2_clip"]
min_const_name = model_name + "@pred_box_min_const"
max_const_name = model_name + "@pred_box_max_const"
min_const = onnx.helper.make_node(
'Constant',
inputs=[],
outputs=[min_const_name],
value=onnx.helper.make_tensor(
name=min_const_name,
data_type=onnx.TensorProto.FLOAT,
dims=(),
vals=[0.0]))
node_list.append(min_const)
max_const = onnx.helper.make_node(
'Constant',
inputs=[],
outputs=[max_const_name],
value=onnx.helper.make_tensor(
name=max_const_name,
data_type=onnx.TensorProto.FLOAT,
dims=(),
vals=[MAX_FLOAT]))
node_list.append(max_const)
node_pred_box_x1_clip = onnx.helper.make_node( node_pred_box_x1_clip = onnx.helper.make_node(
'Clip', 'Clip',
inputs=outputs_pred_box_x1_decode, inputs=outputs_pred_box_x1_decode + [min_const_name, max_const_name],
outputs=outputs_pred_box_x1_clip, outputs=outputs_pred_box_x1_clip)
min=0.0,
max=float(np.inf))
node_list.append(node_pred_box_x1_clip) node_list.append(node_pred_box_x1_clip)
node_pred_box_y1_clip = onnx.helper.make_node( node_pred_box_y1_clip = onnx.helper.make_node(
'Clip', 'Clip',
inputs=outputs_pred_box_y1_decode, inputs=outputs_pred_box_y1_decode + [min_const_name, max_const_name],
outputs=outputs_pred_box_y1_clip, outputs=outputs_pred_box_y1_clip)
min=0.0,
max=float(np.inf))
node_list.append(node_pred_box_y1_clip) node_list.append(node_pred_box_y1_clip)
node_pred_box_x2_clip = onnx.helper.make_node( node_pred_box_x2_clip = onnx.helper.make_node(
'Clip', 'Clip',
inputs=outputs_pred_box_x2_sub_w, inputs=outputs_pred_box_x2_sub_w + [min_const_name, max_const_name],
outputs=outputs_pred_box_x2_clip, outputs=outputs_pred_box_x2_clip)
min=0.0,
max=float(np.inf))
node_list.append(node_pred_box_x2_clip) node_list.append(node_pred_box_x2_clip)
node_pred_box_y2_clip = onnx.helper.make_node( node_pred_box_y2_clip = onnx.helper.make_node(
'Clip', 'Clip',
inputs=outputs_pred_box_y2_sub_h, inputs=outputs_pred_box_y2_sub_h + [min_const_name, max_const_name],
outputs=outputs_pred_box_y2_clip, outputs=outputs_pred_box_y2_clip)
min=0.0,
max=float(np.inf))
node_list.append(node_pred_box_y2_clip) node_list.append(node_pred_box_y2_clip)
outputs_pred_box_x2_res = [model_name + "@box_x2_res"] outputs_pred_box_x2_res = [model_name + "@box_x2_res"]
......
...@@ -99,6 +99,18 @@ class PaddleOpMapper(object): ...@@ -99,6 +99,18 @@ class PaddleOpMapper(object):
self.name_counter[name] += 1 self.name_counter[name] += 1
return name + '.{}'.format(self.name_counter[name]) return name + '.{}'.format(self.name_counter[name])
def im2sequence(self, op, block):
from .paddle_custom_layer.im2sequence import im2sequence
return im2sequence(op, block)
def yolo_box(self, op, block):
from .paddle_custom_layer.yolo_box import yolo_box
return yolo_box(op, block)
def multiclass_nms(self, op, block):
from .paddle_custom_layer.multiclass_nms import multiclass_nms
return multiclass_nms(op, block)
def convert_weights(self, program): def convert_weights(self, program):
var_names = program.global_block().vars var_names = program.global_block().vars
nodes = list() nodes = list()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册