parameters: (self, sym, params, in_shapes, in_types, verbose=False, opset_version=None,
                                  dynamic=True, dynamic_input_shapes=None)
return_statement: return graph
docstring: Convert MXNet graph to ONNX graph
  
          Parameters
          ----------
          sym : :class:`~mxnet.symbol.Symbol`
              MXNet symbol object
          params : dict of ``str`` to :class:`~mxnet.ndarray.NDArray`
              Dict of converted parameters stored in ``mxnet.ndarray.NDArray`` format
          in_shapes : List of tuple
              Input shape of the model e.g [(1,3,224,224)]
          in_types : List of Int
              Input ONNX data types
          verbose : Boolean
              If true will print logs of the model conversion
          opset_version : Int
              ONNX opset version to use for export, defaults to latest supported by onnx package
          dynamic: Boolean
              If True will allow for dynamic input shapes to the model
          dynamic_input_shapes: list of tuple
              Specifies the dynamic input_shapes. If None then all dimensions are set to None
  
          Returns
          -------
          graph : GraphProto
              ONNX graph
docstring_summary: Convert MXNet graph to ONNX graph
docstring_tokens: Convert MXNet graph to ONNX graph
function: def create_onnx_graph_proto(self, sym, params, in_shapes, in_types, verbose=False, opset_version=None,
                                  dynamic=True, dynamic_input_shapes=None):
          """Convert MXNet graph to ONNX graph
  
          Parameters
          ----------
          sym : :class:`~mxnet.symbol.Symbol`
              MXNet symbol object
          params : dict of ``str`` to :class:`~mxnet.ndarray.NDArray`
              Dict of converted parameters stored in ``mxnet.ndarray.NDArray`` format
          in_shapes : List of tuple
              Input shape of the model e.g [(1,3,224,224)]
          in_types : List of Int
              Input ONNX data types
          verbose : Boolean
              If true will print logs of the model conversion
          opset_version : Int
              ONNX opset version to use for export, defaults to latest supported by onnx package
          dynamic: Boolean
              If True will allow for dynamic input shapes to the model
          dynamic_input_shapes: list of tuple
              Specifies the dynamic input_shapes. If None then all dimensions are set to None
  
          Returns
          -------
          graph : GraphProto
              ONNX graph
          """
          try:
              from onnx import (helper, NodeProto, ValueInfoProto, TensorProto)
              from onnx.helper import make_tensor_value_info
              from onnx.defs import onnx_opset_version
          except ImportError:
              raise ImportError("Onnx and protobuf need to be installed. "
                                + "Instructions to install - https://github.com/onnx/onnx")
  
          if opset_version is None:
              opset_version = onnx_opset_version()
  
          # When MXNet model is saved to json file , MXNet adds a node for label.
          # The name of this node is, name of the last node + "_label" ( i.e if last node
          # name is "Softmax", this node will have a name "Softmax_label". Also, the new node
          # will always be second last node in the json graph.
          # Deriving the output_label name.
          output_label = sym.get_internals()[len(sym.get_internals()) - 1].name + "_label"
  
          weights = MXNetGraph.convert_weights_to_numpy(params)
  
          mx_graph = json.loads(sym.tojson())["nodes"]
  
          class NodeOutput:
              def __init__(self, name, dtype):
                  self.name = name
                  self.dtype = np.dtype(dtype)
  
          initializer = []
          all_processed_nodes = []
          onnx_processed_nodes = []
          onnx_processed_inputs = []
          onnx_processed_outputs = []
          outputs_lookup = []
  
          # Determine graph output names, shapes, and dtypes. Also update in_shapes
          in_shapes, graph_outputs = MXNetGraph.get_outputs(sym, params, in_shapes, output_label,
                                                            in_types, dynamic, dynamic_input_shapes)
          appeared_names = set()
          graph_input_idx = 0
          for idx, node in enumerate(mx_graph):
              op = node["op"]
              # check if the current node has the same name as nodes before
              if node["name"] in appeared_names:
                  node["name"] = 'idx_' + str(idx) + '_' + node["name"]
              else:
                  appeared_names.add(node["name"])
              name = node["name"]
              if verbose:
                  logging.info("Converting idx: %d, op: %s, name: %s", idx, op, name)
  
              # A node is an input node if its op_name is "null" and is not
              # in params dict
              if op == "null" and name not in params:
                  # Handle graph input
  
                  # Skip output_label node, as this node is not part of graph
                  # Refer to "output_label" assignment above for more details.
                  if name == output_label:
                      continue
  
                  converted, dtypes = MXNetGraph.convert_layer(
                      node,
                      is_input=True,
                      mx_graph=mx_graph,
                      weights=weights,
                      in_shape=in_shapes[graph_input_idx],
                      in_type=in_types[graph_input_idx],
                      proc_nodes=all_processed_nodes,
                      initializer=initializer,
                      outputs_lookup=outputs_lookup)
                  graph_input_idx += 1
              else:
                  # Handle graph layers
                  converted, dtypes = MXNetGraph.convert_layer(
                      node,
                      is_input=False,
                      mx_graph=mx_graph,
                      weights=weights,
                      proc_nodes=all_processed_nodes,
                      initializer=initializer,
                      outputs_lookup=outputs_lookup,
                      idx=idx,
                      opset_version=opset_version
                  )
              if isinstance(converted, list):
                  # Collect all the node's output names
                  node_possible_names = [name] + [name + str(i) for i in range(100)]
                  node_output_names = []
                  # Collect all the graph's output names
                  graph_output_names = []
                  # Iterate for all converted nodes
                  for converted_node in converted:
                      # If converted node is ValueInfoProto, add it in inputs
                      if isinstance(converted_node, ValueInfoProto):
                          onnx_processed_inputs.append(converted_node)
                      # If converted node is NodeProto, add it in processed nodes list
                      elif isinstance(converted_node, NodeProto):
                          onnx_processed_nodes.append(converted_node)
                          # some operators have multiple outputs,
                          # therefore, check all output node names
                          node_names = list(converted_node.output)
                          for nodename in node_names:
                              if nodename in node_possible_names:
                                  node_output_names.append(nodename)
                              if nodename in graph_outputs:
                                  graph_output_names.append(nodename)
                                  if verbose:
                                      logging.info("Output node is: %s", nodename)
                      elif isinstance(converted_node, TensorProto):
                          raise ValueError("Did not expect TensorProto")
                      else:
                          raise ValueError("node is of an unrecognized type: %s" % type(node))
  
                      all_processed_nodes.append(converted_node)
  
                  # if node_output_names is empty then we use the last returned node as output
                  if not node_output_names:
                      node_output_names = [converted[-1].name]
                  # process node outputs (sort by output index)
                  def str2int(s, l):
                      if len(s) == l:
                          return -1
                      else:
                          return int(s[l:])
  
                  node_output_names = sorted(node_output_names, key=lambda x: str2int(x, len(name)))
  
                  # match the output names to output dtypes
                  if dtypes is not None:
                      assert len(node_output_names) == len(dtypes)
                      node_outputs = [NodeOutput(node_output_names[i], dtypes[i])
                                      for i in range(len(dtypes))]
                  else:
                      # in case dtypes is None, we just default to the dtype of the first input
                      assert len(node["inputs"]) > 0
                      first_input = node["inputs"][0]
                      first_input_dtype = outputs_lookup[first_input[0]][first_input[1]].dtype
                      node_outputs = [NodeOutput(n, first_input_dtype)
                                      for n in node_output_names]
                  outputs_lookup.append(node_outputs)
  
                  # process graph outputs (sort by alphabetical order)
                  graph_output_names.sort()
                  for nodename in graph_output_names:
                      onnx_processed_outputs.append(
                          make_tensor_value_info(
                              name=nodename,
                              elem_type=graph_outputs[nodename]['dtype'],
                              shape=graph_outputs[nodename]['shape']
                          )
                      )
  
              else:
                  logging.info("Operator converter function should always return a list")
  
          # sometimes the graph output can also be in the intializer
          for i in initializer:
              if i.name in graph_outputs:
                  onnx_processed_outputs.append(
                      make_tensor_value_info(
                          name=i.name,
                          elem_type=graph_outputs[i.name]['dtype'],
                          shape=graph_outputs[i.name]['shape']
                      )
                  )
  
          graph = helper.make_graph(
              onnx_processed_nodes,
              "mxnet_converted_model",
              onnx_processed_inputs,
              onnx_processed_outputs
          )
  
          graph.initializer.extend(initializer)
  
          return graph
function_tokens: def create_onnx_graph_proto ( self , sym , params , in_shapes , in_types , verbose = False , opset_version = None , dynamic = True , dynamic_input_shapes = None ) : try : from onnx import ( helper , NodeProto , ValueInfoProto , TensorProto ) from onnx . helper import make_tensor_value_info from onnx . defs import onnx_opset_version except ImportError : raise ImportError ( "Onnx and protobuf need to be installed. " + "Instructions to install - https://github.com/onnx/onnx" ) if opset_version is None : opset_version = onnx_opset_version ( ) # When MXNet model is saved to json file , MXNet adds a node for label. # The name of this node is, name of the last node + "_label" ( i.e if last node # name is "Softmax", this node will have a name "Softmax_label". Also, the new node # will always be second last node in the json graph. # Deriving the output_label name. output_label = sym . get_internals ( ) [ len ( sym . get_internals ( ) ) - 1 ] . name + "_label" weights = MXNetGraph . convert_weights_to_numpy ( params ) mx_graph = json . loads ( sym . tojson ( ) ) [ "nodes" ] class NodeOutput : def __init__ ( self , name , dtype ) : self . name = name self . dtype = np . dtype ( dtype ) initializer = [ ] all_processed_nodes = [ ] onnx_processed_nodes = [ ] onnx_processed_inputs = [ ] onnx_processed_outputs = [ ] outputs_lookup = [ ] # Determine graph output names, shapes, and dtypes. Also update in_shapes in_shapes , graph_outputs = MXNetGraph . get_outputs ( sym , params , in_shapes , output_label , in_types , dynamic , dynamic_input_shapes ) appeared_names = set ( ) graph_input_idx = 0 for idx , node in enumerate ( mx_graph ) : op = node [ "op" ] # check if the current node has the same name as nodes before if node [ "name" ] in appeared_names : node [ "name" ] = 'idx_' + str ( idx ) + '_' + node [ "name" ] else : appeared_names . add ( node [ "name" ] ) name = node [ "name" ] if verbose : logging . info ( "Converting idx: %d, op: %s, name: %s" , idx , op , name ) # A node is an input node if its op_name is "null" and is not # in params dict if op == "null" and name not in params : # Handle graph input # Skip output_label node, as this node is not part of graph # Refer to "output_label" assignment above for more details. if name == output_label : continue converted , dtypes = MXNetGraph . convert_layer ( node , is_input = True , mx_graph = mx_graph , weights = weights , in_shape = in_shapes [ graph_input_idx ] , in_type = in_types [ graph_input_idx ] , proc_nodes = all_processed_nodes , initializer = initializer , outputs_lookup = outputs_lookup ) graph_input_idx += 1 else : # Handle graph layers converted , dtypes = MXNetGraph . convert_layer ( node , is_input = False , mx_graph = mx_graph , weights = weights , proc_nodes = all_processed_nodes , initializer = initializer , outputs_lookup = outputs_lookup , idx = idx , opset_version = opset_version ) if isinstance ( converted , list ) : # Collect all the node's output names node_possible_names = [ name ] + [ name + str ( i ) for i in range ( 100 ) ] node_output_names = [ ] # Collect all the graph's output names graph_output_names = [ ] # Iterate for all converted nodes for converted_node in converted : # If converted node is ValueInfoProto, add it in inputs if isinstance ( converted_node , ValueInfoProto ) : onnx_processed_inputs . append ( converted_node ) # If converted node is NodeProto, add it in processed nodes list elif isinstance ( converted_node , NodeProto ) : onnx_processed_nodes . append ( converted_node ) # some operators have multiple outputs, # therefore, check all output node names node_names = list ( converted_node . output ) for nodename in node_names : if nodename in node_possible_names : node_output_names . append ( nodename ) if nodename in graph_outputs : graph_output_names . append ( nodename ) if verbose : logging . info ( "Output node is: %s" , nodename ) elif isinstance ( converted_node , TensorProto ) : raise ValueError ( "Did not expect TensorProto" ) else : raise ValueError ( "node is of an unrecognized type: %s" % type ( node ) ) all_processed_nodes . append ( converted_node ) # if node_output_names is empty then we use the last returned node as output if not node_output_names : node_output_names = [ converted [ - 1 ] . name ] # process node outputs (sort by output index) def str2int ( s , l ) : if len ( s ) == l : return - 1 else : return int ( s [ l : ] ) node_output_names = sorted ( node_output_names , key = lambda x : str2int ( x , len ( name ) ) ) # match the output names to output dtypes if dtypes is not None : assert len ( node_output_names ) == len ( dtypes ) node_outputs = [ NodeOutput ( node_output_names [ i ] , dtypes [ i ] ) for i in range ( len ( dtypes ) ) ] else : # in case dtypes is None, we just default to the dtype of the first input assert len ( node [ "inputs" ] ) > 0 first_input = node [ "inputs" ] [ 0 ] first_input_dtype = outputs_lookup [ first_input [ 0 ] ] [ first_input [ 1 ] ] . dtype node_outputs = [ NodeOutput ( n , first_input_dtype ) for n in node_output_names ] outputs_lookup . append ( node_outputs ) # process graph outputs (sort by alphabetical order) graph_output_names . sort ( ) for nodename in graph_output_names : onnx_processed_outputs . append ( make_tensor_value_info ( name = nodename , elem_type = graph_outputs [ nodename ] [ 'dtype' ] , shape = graph_outputs [ nodename ] [ 'shape' ] ) ) else : logging . info ( "Operator converter function should always return a list" ) # sometimes the graph output can also be in the intializer for i in initializer : if i . name in graph_outputs : onnx_processed_outputs . append ( make_tensor_value_info ( name = i . name , elem_type = graph_outputs [ i . name ] [ 'dtype' ] , shape = graph_outputs [ i . name ] [ 'shape' ] ) ) graph = helper . make_graph ( onnx_processed_nodes , "mxnet_converted_model" , onnx_processed_inputs , onnx_processed_outputs ) graph . initializer . extend ( initializer ) return graph