Skip to content

Commit

Permalink
Update to opset 13 (#156)
Browse files Browse the repository at this point in the history
  • Loading branch information
jiafatom authored Dec 17, 2020
1 parent c75e326 commit 7b3ac07
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 32 deletions.
2 changes: 1 addition & 1 deletion onnxconverter_common/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
This framework performs optimization for ONNX models and
includes common utilities for ONNX converters.
"""
__version__ = "1.7.0"
__version__ = "1.8.0"
__author__ = "Microsoft"
__producer__ = "OnnxMLTools"
__producer_version__ = __version__
Expand Down
2 changes: 2 additions & 0 deletions onnxconverter_common/_opt_const_folding.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ def _OnSub(self, node, inputs):

def _OnUnsqueeze(self, node, inputs):
axes = OnnxGraphContext.get_attribute(node, 'axes')
if axes is None:
axes = inputs[1]
shape_in = inputs[0].shape
dims_out = len(shape_in) + len(axes)
shape_in = iter(shape_in)
Expand Down
4 changes: 3 additions & 1 deletion onnxconverter_common/onnx_ex.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
from .metadata_props import add_metadata_props

DEFAULT_OPSET_NUMBER = 12 # The maximum opset supported by the converter in the code branch.
# From https://github.com/onnx/onnx/blob/master/docs/Versioning.md
OPSET_TO_IR_VERSION = {
1: 3, 2: 3, 3: 3, 4: 3, 5: 3, 6: 3,
7: 3, 8: 4, 9: 4, 10: 5, 11: 6, 12: 7
7: 3, 8: 3, 9: 4, 10: 5, 11: 6, 12: 7,
13: 7
}


Expand Down
73 changes: 64 additions & 9 deletions onnxconverter_common/onnx_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,33 @@ def apply_reciprocal(scope, input_name, output_name, container, operator_name=No
_apply_unary_operation(scope, 'Reciprocal', input_name, output_name, container, operator_name=operator_name)


def apply_reducesum(scope, input_name, output_name, container, operator_name=None, axes=None, keepdims=None, rank=0):
name = _create_name_or_use_existing_one(scope, 'ReduceSum', operator_name)
if container.target_opset < 13:
if container.target_opset < 11:
op_version = 1
axes = [axis if axis >= 0 else axis + rank + 1 for axis in axes]
else:
op_version = 11
container.add_node('ReduceSum', input_name, output_name, name=name,
op_version=op_version, axes=axes, keepdims=keepdims)
else:
if not isinstance(input_name, list):
input_name = [input_name]
op_version = 13
if isinstance(axes, str):
container.add_node('ReduceSum', input_name + [axes], output_name,
op_version=op_version, name=name, keepdims=keepdims)
elif axes is None or len(axes) == 0:
container.add_node('ReduceSum', input_name, output_name,
op_version=op_version, name=name, keepdims=keepdims)
else:
axes_name = scope.get_unique_variable_name(name + '_reducesum')
container.add_initializer(axes_name, onnx_proto.TensorProto.INT64, [len(axes)], axes)
container.add_node('ReduceSum', input_name + [axes_name], output_name,
op_version=op_version, name=name, keepdims=keepdims)


def apply_relu(scope, input_name, output_name, container, operator_name=None):
_apply_unary_operation(scope, 'Relu', input_name, output_name, container, operator_name)

Expand Down Expand Up @@ -860,8 +887,10 @@ def apply_selu(scope, input_name, output_name, container, operator_name=None, al
_apply_unary_operation(scope, 'Selu', input_name, output_name, container, operator_name, alpha=alpha, gamma=gamma)


def apply_softmax(scope, input_name, output_name, container, operator_name=None, axis=1):
def apply_softmax(scope, input_name, output_name, container, operator_name=None, axis=None):
name = _create_name_or_use_existing_one(scope, 'Softmax', operator_name)
if axis is None:
axis = 1 if container.target_opset < 13 else -1
container.add_node('Softmax', input_name, output_name, name=name, axis=axis)


Expand Down Expand Up @@ -969,12 +998,25 @@ def apply_split(scope, input_name, output_names, container, operator_name=None,
op_version = 1
elif container.target_opset < 11:
op_version = 2
else:
elif container.target_opset < 13:
op_version = 11
else:
op_version = 13

attrs = {'name': name}
if split is not None:
attrs['split'] = split
if container.target_opset < 13:
attrs['split'] = split
else:
if not isinstance(input_name, list):
input_name = [input_name]
if isinstance(split, str):
split_name = split
else:
split_name = scope.get_unique_variable_name(name + '_split')
container.add_initializer(split_name, onnx_proto.TensorProto.INT64, [len(split)], split)
input_name = input_name + [split_name]

if axis is not None:
attrs['axis'] = axis

Expand All @@ -988,17 +1030,30 @@ def apply_sqrt(scope, input_name, output_name, container, operator_name=None):
def _apply_squeeze_unsqueeze(scope, input_name, output_name, container, squeeze_str, operator_name=None, axes=None,
rank=0):
name = _create_name_or_use_existing_one(scope, squeeze_str, operator_name)
if container.target_opset < 11:
op_version = 1
axes = [axis if axis >= 0 else axis + rank + 1 for axis in axes]
if container.target_opset < 13:
if container.target_opset < 11:
op_version = 1
axes = [axis if axis >= 0 else axis + rank + 1 for axis in axes]
else:
op_version = 11
container.add_node(squeeze_str, input_name, output_name, name=name, op_version=op_version, axes=axes)
else:
op_version = 11
container.add_node(squeeze_str, input_name, output_name, name=name, op_version=op_version, axes=axes)
op_version = 13
if not isinstance(input_name, list):
input_name = [input_name]
if isinstance(axes, str):
container.add_node(squeeze_str, input_name + [axes], output_name, op_version=op_version, name=name)
elif len(axes) == 0:
container.add_node(squeeze_str, input_name, output_name, op_version=op_version, name=name)
else:
axes_name = scope.get_unique_variable_name(name + '_axes')
container.add_initializer(axes_name, onnx_proto.TensorProto.INT64, [len(axes)], axes)
container.add_node(squeeze_str, input_name + [axes_name], output_name, op_version=op_version, name=name)


def apply_squeeze(scope, input_name, output_name, container, operator_name=None, axes=None, rank=0):
if axes is None:
axes = [0]
axes = []
_apply_squeeze_unsqueeze(scope, input_name, output_name, container, 'Squeeze', operator_name, axes, rank)


Expand Down
86 changes: 65 additions & 21 deletions onnxconverter_common/optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
class LinkedNode(object):
reserved_names_in_graph = frozenset()

def __init__(self, node=None, in_n=None, out_n=None, tensors_n=None):
def __init__(self, node=None, in_n=None, out_n=None, tensors_n=None, target_opset=None):
self.origin = node # type: onnx_proto.NodeProto
if in_n is None and node is not None:
in_n = node.input
Expand All @@ -29,6 +29,7 @@ def __init__(self, node=None, in_n=None, out_n=None, tensors_n=None):
self.successor = []
self.attributes = {}
self.unique_name = self.origin.name if self.origin and self.origin.name else str(uuid4().hex)
self.target_opset = target_opset

def __repr__(self):
return "name: {}, node: <{}>".format(self.unique_name, str(self.origin) if self.origin else 'None')
Expand Down Expand Up @@ -283,11 +284,11 @@ def add_precedence(self, pre, tname):
assert tname in self.input.values() and tname in pre.output.values()

@staticmethod
def build_from_onnx(onnx_nodes, nchw_inputs, inputs, outputs, initializers=None):
def build_from_onnx(onnx_nodes, nchw_inputs, inputs, outputs, initializers=None, target_opset=None):
view = []
var_map = {}
for o_ in onnx_nodes:
ln = LinkedNode(o_)
ln = LinkedNode(o_, target_opset=target_opset)
view.append(ln)
for var_ in o_.output:
assert var_map.get(var_) is None
Expand All @@ -305,9 +306,10 @@ def build_from_onnx(onnx_nodes, nchw_inputs, inputs, outputs, initializers=None)
assert var_ == '' or var_ in inputs
if initializer_map is not None and var_ in initializer_map:
target = LinkedNode(out_n=[var_],
tensors_n=[initializer_map[var_]]) # create an empty node as input
tensors_n=[initializer_map[var_]],
target_opset=target_opset) # create an empty node as input
else:
target = LinkedNode(out_n=[var_])
target = LinkedNode(out_n=[var_], target_opset=target_opset)
new_output = var_ + '_nhwc'
if var_ in nchw_inputs:
nnode = LinkedNode(
Expand All @@ -316,7 +318,8 @@ def build_from_onnx(onnx_nodes, nchw_inputs, inputs, outputs, initializers=None)
[var_],
[new_output],
name='Transpose_nchw_' + str(count_nchw),
perm=[0, 2, 3, 1]))
perm=[0, 2, 3, 1]),
target_opset=target_opset)
count_nchw = count_nchw + 1
var_map[new_output] = nnode
nnode.add_precedence(target, var_)
Expand All @@ -330,7 +333,7 @@ def build_from_onnx(onnx_nodes, nchw_inputs, inputs, outputs, initializers=None)
for n_ in view: # add a dummy output node.
for var_ in n_.origin.output:
if var_ in outputs:
LinkedNode(in_n=[var_]).add_precedence(n_, var_)
LinkedNode(in_n=[var_], target_opset=target_opset).add_precedence(n_, var_)

return view + additional_nodes

Expand Down Expand Up @@ -642,6 +645,18 @@ def _get_pad_from_Pad(node):
return pads


def _get_axes_from_Squeeze_Unsqueeze(node):
axes = node.get_attribute('axes')
if axes is None:
if len(node.origin.input) == 2:
axes_tensor = node.get_precedence_by_idx(1)
if axes_tensor is None:
axes = numpy_helper.to_array(node.initializers[0]).tolist()
else:
axes = numpy_helper.to_array(node.get_precedence_by_idx(1).tensors[0]).tolist()
return axes


class MergePadConvSolution(Solution):

def __init__(self, begin, begin_n, end_p, end):
Expand Down Expand Up @@ -968,11 +983,13 @@ class MergeSqueezeUnsqueezeOptimizer(object):
@staticmethod
def find(node):
if node.origin.op_type == 'Squeeze' and len(node.successor) == 1:
axes_0 = node.get_attribute('axes')
axes_0 = _get_axes_from_Squeeze_Unsqueeze(node)
next = node.successor[0]
if next.origin is not None and next.origin.op_type == 'Unsqueeze' and len(next.successor) == 1:
axes_1 = next.get_attribute('axes')
if axes_0 == axes_1:
flag = next.origin is not None and axes_0 is not None \
and next.origin.op_type == 'Unsqueeze' and len(next.successor) == 1
if flag:
axes_1 = _get_axes_from_Squeeze_Unsqueeze(next)
if axes_1 is not None and axes_0 == axes_1:
solution = Solution(node.get_precedence_by_idx(0), node, next, next.successor[0])
return solution

Expand All @@ -993,6 +1010,10 @@ def _transpose_pass(node):
if node.element_wise:
return True

if node.origin.op_type in ['Squeeze', 'Unsqueeze']:
axes = _get_axes_from_Squeeze_Unsqueeze(node)
return axes is not None

if node.origin.op_type in _transpose_pass_type_set:
return True

Expand Down Expand Up @@ -1131,9 +1152,8 @@ def _process_transpose_pad(node, node_list, node_transpose_pass_name, cur_perm_m

def _process_transpose_squeeze(node, node_list, node_transpose_pass_name, cur_perm_map):
cur_perm = cur_perm_map[node.get_precedence_by_idx(0).unique_name]
squeeze_axes = node.get_attribute('axes')
squeeze_axes = _get_axes_from_Squeeze_Unsqueeze(node)
squeeze_axes = [cur_perm[idx_] for idx_ in squeeze_axes]
attrs = {'axes': squeeze_axes}
temp_perm = cur_perm.copy()
sub_list = [0] * len(cur_perm)
for axis in squeeze_axes:
Expand All @@ -1145,18 +1165,39 @@ def _process_transpose_squeeze(node, node_list, node_transpose_pass_name, cur_pe
temp_perm[idx_] = temp_perm[idx_] - sub_list[temp_perm[idx_]]
target_perm = temp_perm
new_node_name = node.origin.name + '_squeeze_' + str(PushTransposeSolution.transpose_number)
node.origin = helper.make_node('Squeeze', node.origin.input, node.origin.output, new_node_name, **attrs)
if node.target_opset < 13:
attrs = {'axes': squeeze_axes}
node.origin = helper.make_node('Squeeze', node.origin.input, node.origin.output, new_node_name, **attrs)
else:
squeeze_axes = np.asarray(squeeze_axes, dtype=np.int64)
add_initilizer = numpy_helper.from_array(squeeze_axes, name=node.origin.name + '_initializer_' + str(
PushTransposeSolution.transpose_number))
node.initializers = [add_initilizer]
pred_1 = node.get_precedence_by_idx(1)
if pred_1 is not None:
node.precedence.remove(pred_1)
node.in_redirect(node.get_input_by_idx(1), add_initilizer.name)
PushTransposeSolution.transpose_number += 1
cur_perm_map[node.unique_name] = target_perm
return cur_perm_map


def _process_transpose_unsqueeze(node, node_list, node_transpose_pass_name, cur_perm_map):
unsqueeze_axes = node.get_attribute('axes')
unsqueeze_axes = _get_axes_from_Squeeze_Unsqueeze(node)
assert len(unsqueeze_axes) == 1
attrs = {'axes': unsqueeze_axes}
new_node_name = node.origin.name + '_unsqueeze_' + str(PushTransposeSolution.transpose_number)
node.origin = helper.make_node('Unsqueeze', node.origin.input, node.origin.output, new_node_name, **attrs)
if node.target_opset < 13:
attrs = {'axes': unsqueeze_axes}
node.origin = helper.make_node('Unsqueeze', node.origin.input, node.origin.output, new_node_name, **attrs)
else:
unsqueeze_axes = np.asarray(unsqueeze_axes, dtype=np.int64)
add_initilizer = numpy_helper.from_array(unsqueeze_axes, name=node.origin.name + '_initializer_' + str(
PushTransposeSolution.transpose_number))
node.initializers = [add_initilizer]
pred_1 = node.get_precedence_by_idx(1)
if pred_1 is not None:
node.precedence.remove(pred_1)
node.in_redirect(node.get_input_by_idx(1), add_initilizer.name)
PushTransposeSolution.transpose_number += 1
prev_perm = cur_perm_map[node.precedence[0].unique_name]
cur_axes = unsqueeze_axes[0]
Expand Down Expand Up @@ -1190,7 +1231,8 @@ def _process_transpose_pass_node(node, node_list, node_transpose_pass_name, cur_
node_list, cur_perm_map = _process_transpose_pass_broadcast(node, node_list, node_transpose_pass_name,
cur_perm_map)
elif node.origin.op_type in type_func_map:
cur_perm_map = type_func_map[node.origin.op_type](node, node_list, node_transpose_pass_name, cur_perm_map)
cur_perm_map = type_func_map[node.origin.op_type](node, node_list, node_transpose_pass_name,
cur_perm_map)
else:
for idx_ in range(len(node.precedence)):
pred_name = node.get_precedence_by_idx(idx_).unique_name
Expand Down Expand Up @@ -1238,7 +1280,7 @@ def apply(self, node_list):
if not success:
return None, False
elif node.origin.op_type == 'Unsqueeze':
unsqueeze_axes = node.get_attribute('axes')
unsqueeze_axes = _get_axes_from_Squeeze_Unsqueeze(node)
if unsqueeze_axes and len(unsqueeze_axes) > 1:
return None, False

Expand Down Expand Up @@ -1762,7 +1804,8 @@ def optimize_onnx(onnx_nodes, nchw_inputs=None, inputs=None, outputs=None, targe
node_list = LinkedNode.build_from_onnx(onnx_nodelist,
nchw_inputs if nchw_inputs else [],
[] if inputs is None else [i_.name for i_ in inputs],
[] if outputs is None else [o_.name for o_ in outputs])
[] if outputs is None else [o_.name for o_ in outputs],
target_opset=target_opset)
node_list = _process_optimization(node_list, target_opset)

if target_opset is None or target_opset < 9:
Expand Down Expand Up @@ -1826,7 +1869,8 @@ def optimize_onnx_graph(onnx_nodes, nchw_inputs=None, inputs=None, outputs=None,
nchw_inputs if nchw_inputs else [],
[] if in_inputs is None else [i_.name for i_ in in_inputs],
[] if outputs is None else [o_.name for o_ in outputs],
initializers)
initializers,
target_opset=target_opset)

node_list = _process_optimization(node_list, target_opset)
node_list = [n_ for n_ in node_list if n_.origin is not None]
Expand Down

0 comments on commit 7b3ac07

Please sign in to comment.