def _parse_onnx_api(topology, model, inputs): """ This function handles all input ONNX models. Args: topology: The ``onnxconverter_common.topology.Topology`` where the model will be added model: A ONNX model object inputs: A list of `onnxconverter_common.topology.Variable`s Returns: A list of output `onnxconverter_common.topology.Variable` which will be passed to next stage """ if isinstance(model, str): raise RuntimeError("Parameter model must be an object not a " "string '{0}'.".format(model)) # Parse an ONNX-ML model into our internal data structure (i.e., LinkedNode) graph = model.graph inputs_names = [in_.raw_name for in_ in inputs] output_names = [] if graph.output is None else [o_.name for o_ in graph.output] initializers = [] if graph.initializer is None else [in_ for in_ in graph.initializer] node_list = LinkedNode.build_from_onnx(graph.node, [], inputs_names + [in_.name for in_ in initializers], output_names) # This a new node list but with some node been removed plus eventual variable renaming. new_node_list = _remove_zipmap(node_list) # Add each operator in the LinkedNode data structure to the topology. for node in new_node_list: _parse_onnx_single_operator(topology, node)
def _convert_onnxml(model, test_input=None, extra_config={}): """ This function converts the specified [ONNX-ML] model into its [ONNX] counterpart. The supported operators can be found at `hummingbird.ml.supported`. The ONNX-ML converter requires either a test_input of a the initial types set through the exta_config parameter. [ONNX-ML]: https://github.com/onnx/onnx/blob/master/docs/Operators-ml.md [ONNX]: https://github.com/onnx/onnx/blob/master/docs/Operators.md Args: model: A model containing ONNX-ML operators test_input: Some input data used to trace the model execution. For the ONNX backend the test_input size is supposed to be as large as the expected batch size. extra_config: Extra configurations to be used by the individual operator converters. The set of supported extra configurations can be found at `hummingbird.ml.supported` Examples: extra_config = {} extra_config[constans.ONNX_INITIAL_TYPES] =[('input', FloatTensorType([1, 20])] >>> onnx_model = _convert_onnxml(onnx_ml_model, None, extra_config) Returns: A model containing only *ONNX* operators. The mode is equivalent to the input *ONNX-ML* model """ assert model is not None assert torch_installed(), "To use Hummingbird you need to install torch." assert ( onnx_runtime_installed() ), "To use the onnxml converter you need to install onnxruntime (or `pip install hummingbird-ml[onnx]`)." output_model_name = initial_types = input_names = output_names = None target_opset = 9 # Set optional configuration options if any. if constants.ONNX_OUTPUT_MODEL_NAME in extra_config: output_model_name = extra_config[constants.ONNX_OUTPUT_MODEL_NAME] if constants.ONNX_INITIAL_TYPES in extra_config: initial_types = extra_config[constants.ONNX_INITIAL_TYPES] if constants.ONNX_INPUT_NAMES in extra_config: input_names = extra_config[constants.ONNX_INPUT_NAMES] if constants.ONNX_OUTPUT_NAMES in extra_config: output_names = extra_config[constants.ONNX_OUTPUT_NAMES] if constants.ONNX_TARGET_OPSET in extra_config: target_opset = extra_config[constants.ONNX_TARGET_OPSET] assert ( test_input is not None and len(test_input) > 0 ) or initial_types is not None, "Cannot generate test input data. Either pass some input data or the initial_types" from .ir_converters.linked_node import convert as linked_node_converter # We modify the model during translation. model = deepcopy(model) # Parse an ONNX-ML model into our internal data structure (i.e., LinkedNode) graph = model.graph input_names = input_names if input_names is not None else [in_.name for in_ in graph.input] inputs = [in_ for in_ in graph.input if in_.name in input_names] assert len(inputs) > 0, "Provided input name does not match with any model's input." assert len(inputs) == 1, "Hummingbird currently do not support models with more than 1 input." assert initial_types is None or len(initial_types) == 1, "len(initial_types) {} differs from len(inputs) {}.".format( len(initial_types), len(inputs) ) if output_names is None: output_names = [] if graph.output is None else [o_.name for o_ in graph.output] if test_input is None: assert ( not initial_types[0][1].shape is None ), "Cannot generate test input data. Initial_types do not contain shape information." assert len(initial_types[0][1].shape) == 2, "Hummingbird currently support only inputs with len(shape) == 2." from onnxconverter_common.data_types import FloatTensorType, Int32TensorType test_input = np.random.rand(initial_types[0][1].shape[0], initial_types[0][1].shape[1]) extra_config[constants.N_FEATURES] = initial_types[0][1].shape[1] if type(initial_types[0][1]) is FloatTensorType: test_input = np.array(test_input, dtype=np.float32) elif type(initial_types[0][1]) is Int32TensorType: test_input = np.array(test_input, dtype=np.int32) else: raise RuntimeError( "Type {} not supported. Please fill an issue on https://github.com/microsoft/hummingbird/.".format( type(initial_types[0][1]) ) ) initializers = [] if graph.initializer is None else [in_ for in_ in graph.initializer] onnx_ir = LinkedNode.build_from_onnx( graph.node, [], [in_.name for in_ in inputs] + [in_.name for in_ in initializers], output_names ) # Convert the input onnx_ir object into ONNX. The outcome is a model containing only ONNX operators. onnx_model = linked_node_converter( onnx_ir, inputs, initializers, output_names, test_input, output_model_name, target_opset, extra_config ) return onnx_model