Files
onnx--onnx/docs/PythonAPIOverview.md
T
Chun-Wei Chen 09a4e65bb0 Catch >2GB models in checker (#2744)
* Try to enable full_check

* revert meaningless modification

This reverts commit fdaa6a91eae123f68141370aafa13841551b0295, reversing
changes made to 40d56bd08714534edca3dae674d82aba1a7356de.

Debug for all_types

Revert "Debug for all_types"

This reverts commit 3aa921a9ea7d82080265d1d95b7ec6cf3cdfa343.

restore onnx

This reverts commit fdaa6a91eae123f68141370aafa13841551b0295, reversing
changes made to 40d56bd08714534edca3dae674d82aba1a7356de.

Debug for all_types

Revert "Debug for all_types"

This reverts commit 3aa921a9ea7d82080265d1d95b7ec6cf3cdfa343.

Revert "restore onnx"

This reverts commit aadc4da654960c8248b502dd71a592d95eafd6db.

restore onnx due to gitignore them unintentionally

This reverts commit fdaa6a91eae123f68141370aafa13841551b0295, reversing
changes made to 40d56bd08714534edca3dae674d82aba1a7356de.

Debug for all_types

Revert "Debug for all_types"

This reverts commit 3aa921a9ea7d82080265d1d95b7ec6cf3cdfa343.

restore onnx

This reverts commit fdaa6a91eae123f68141370aafa13841551b0295, reversing
changes made to 40d56bd08714534edca3dae674d82aba1a7356de.

Debug for all_types

Revert "Debug for all_types"

This reverts commit 3aa921a9ea7d82080265d1d95b7ec6cf3cdfa343.

Revert "restore onnx"

This reverts commit aadc4da654960c8248b502dd71a592d95eafd6db.

* Accumulate error msgs for checker

* Accumulate error messages and trigger runtime error while checking type consistency.

Print type consistency

add nextline between various error msgs

add nextline

* Change external tensors into default after loading; Add filepath field;
pass to checker with filepath

* Decouple the check of inference error to another PR

* Revert the commit of introducing model_path in model proto

* Add warning for large models which is > 2GB

* Improve catching 2GB

* Use (str, Warning) to prevent (unicode) error

* Force to use string

* Use expcetion instead of warning for catching large models

* add comments for load external data

* test check 2gb

* Change to ValueError from RuntimeError for 2GB models

* Refactor external data test and use iteration to avoid memory exceed

* Create ExternalData.md

* Add usage for using external data

* load and checker for external data in PythonAPI

* Add a link to ExternalData.md in IR.md

Co-authored-by: Vinitra Swamy <vinitras@gmail.com>
Co-authored-by: G. Ramalingam <grama@microsoft.com>
2020-06-12 13:05:23 -07:00

8.4 KiB

Python API Overview

Loading an ONNX Model

import onnx

onnx_model = onnx.load('path/to/the/model.onnx')
# `onnx_model` is a ModelProto struct

Runnable IPython notebooks:

Loading an ONNX Model with External Data

  • [Default] If the external data is under the same directory of the model, simply use onnx.load()
import onnx

onnx_model = onnx.load('path/to/the/model.onnx')
  • If the external data is under another directory, use load_external_data_for_model() to specify the directory path and load after using onnx.load()
import onnx
from onnx.external_data_helper import load_external_data_for_model

onnx_model = onnx.load('path/to/the/model.onnx', load_external_data=False)
load_external_data_for_model(onnx_model, 'data/directory/path/')
# Then the onnx_model has loaded the external data from the specific directory

Saving an ONNX Model

import onnx

onnx_model = ... # Your model in memory as ModelProto

# Save the ONNX model
onnx.save(onnx_model, 'path/to/the/model.onnx')

Runnable IPython notebooks:

Manipulating TensorProto and Numpy Array

import numpy
import onnx
from onnx import numpy_helper

# Preprocessing: create a Numpy array
numpy_array = numpy.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]], dtype=float)
print('Original Numpy array:\n{}\n'.format(numpy_array))

# Convert the Numpy array to a TensorProto
tensor = numpy_helper.from_array(numpy_array)
print('TensorProto:\n{}'.format(tensor))

# Convert the TensorProto to a Numpy array
new_array = numpy_helper.to_array(tensor)
print('After round trip, Numpy array:\n{}\n'.format(new_array))

# Save the TensorProto
with open('tensor.pb', 'wb') as f:
    f.write(tensor.SerializeToString())

# Load a TensorProto
new_tensor = onnx.TensorProto()
with open('tensor.pb', 'rb') as f:
    new_tensor.ParseFromString(f.read())
print('After saving and loading, new TensorProto:\n{}'.format(new_tensor))

Runnable IPython notebooks:

Creating an ONNX Model Using Helper Functions

import onnx
from onnx import helper
from onnx import AttributeProto, TensorProto, GraphProto


# The protobuf definition can be found here:
# https://github.com/onnx/onnx/blob/master/onnx/onnx.proto


# Create one input (ValueInfoProto)
X = helper.make_tensor_value_info('X', TensorProto.FLOAT, [3, 2])
pads = helper.make_tensor_value_info('pads', TensorProto.FLOAT, [1, 4])

value = helper.make_tensor_value_info('value', AttributeProto.FLOAT, [1])


# Create one output (ValueInfoProto)
Y = helper.make_tensor_value_info('Y', TensorProto.FLOAT, [3, 4])

# Create a node (NodeProto) - This is based on Pad-11
node_def = helper.make_node(
    'Pad', # node name
    ['X', 'pads', 'value'], # inputs
    ['Y'], # outputs
    mode='constant', # attributes
)

# Create the graph (GraphProto)
graph_def = helper.make_graph(
    [node_def],
    'test-model',
    [X, pads, value],
    [Y],
)

# Create the model (ModelProto)
model_def = helper.make_model(graph_def, producer_name='onnx-example')

print('The model is:\n{}'.format(model_def))
onnx.checker.check_model(model_def)
print('The model is checked!')

Runnable IPython notebooks:

Checking an ONNX Model

import onnx

# Preprocessing: load the ONNX model
model_path = 'path/to/the/model.onnx'
onnx_model = onnx.load(model_path)

print('The model is:\n{}'.format(onnx_model))

# Check the model
onnx.checker.check_model(onnx_model)
print('The model is checked!')

Runnable IPython notebooks:

Checking a Large ONNX Model >2GB

Current checker supports checking models with external data, but for those models larger than 2GB, please use the model path for onnx.checker and the external data needs to be under the same directory.

import onnx

onnx.checker.check_model('path/to/the/model.onnx')
# onnx.checker.check_model(loaded_onnx_model) will fail if given >2GB model

Optimizing an ONNX Model

import onnx
from onnx import optimizer

# Preprocessing: load the model to be optimized.
model_path = 'path/to/the/model.onnx'
original_model = onnx.load(model_path)

print('The model before optimization:\n{}'.format(original_model))

# A full list of supported optimization passes can be found using get_available_passes()
all_passes = optimizer.get_available_passes()
print("Available optimization passes:")
for p in all_passes:
    print(p)
print()

# Pick one pass as example
passes = ['fuse_consecutive_transposes']

# Apply the optimization on the original model
optimized_model = optimizer.optimize(original_model, passes)

print('The model after optimization:\n{}'.format(optimized_model))

# One can also apply the default passes on the (serialized) model
# Check the default passes here: https://github.com/onnx/onnx/blob/master/onnx/optimizer.py#L43
optimized_model = optimizer.optimize(original_model)

Runnable IPython notebooks:

Running Shape Inference on an ONNX Model

import onnx
from onnx import helper, shape_inference
from onnx import TensorProto


# Preprocessing: create a model with two nodes, Y's shape is unknown
node1 = helper.make_node('Transpose', ['X'], ['Y'], perm=[1, 0, 2])
node2 = helper.make_node('Transpose', ['Y'], ['Z'], perm=[1, 0, 2])

graph = helper.make_graph(
    [node1, node2],
    'two-transposes',
    [helper.make_tensor_value_info('X', TensorProto.FLOAT, (2, 3, 4))],
    [helper.make_tensor_value_info('Z', TensorProto.FLOAT, (2, 3, 4))],
)

original_model = helper.make_model(graph, producer_name='onnx-examples')

# Check the model and print Y's shape information
onnx.checker.check_model(original_model)
print('Before shape inference, the shape info of Y is:\n{}'.format(original_model.graph.value_info))

# Apply shape inference on the model
inferred_model = shape_inference.infer_shapes(original_model)

# Check the model and print Y's shape information
onnx.checker.check_model(inferred_model)
print('After shape inference, the shape info of Y is:\n{}'.format(inferred_model.graph.value_info))

Runnable IPython notebooks:

Converting Version of an ONNX Model within Default Domain (""/"ai.onnx")

import onnx
from onnx import version_converter, helper

# Preprocessing: load the model to be converted.
model_path = 'path/to/the/model.onnx'
original_model = onnx.load(model_path)

print('The model before conversion:\n{}'.format(original_model))

# A full list of supported adapters can be found here:
# https://github.com/onnx/onnx/blob/master/onnx/version_converter.py#L21
# Apply the version conversion on the original model
converted_model = version_converter.convert_version(original_model, <int target_version>)

print('The model after conversion:\n{}'.format(converted_model))

Utility Functions

Polishing the Model

Function polish_model runs model checker, optimizer, shape inference engine on the model, and also strips the doc_string for you.

import onnx
import onnx.utils


model = onnx.load('path/to/the/model.onnx')
polished_model = onnx.utils.polish_model(model)

Tools

Updating Model's Inputs Outputs Dimension Sizes with Variable Length

Function update_inputs_outputs_dims updates the dimension of the inputs and outputs of the model, to the provided values in the parameter. You could provide both static and dynamic dimension size, by using dim_param. For more information on static and dynamic dimension size, checkout Tensor Shapes.

The function runs model checker after the input/output sizes are updated.

import onnx
from onnx.tools import update_model_dims

model = onnx.load('path/to/the/model.onnx')
# Here both 'seq', 'batch' and -1 are dynamic using dim_param.
variable_length_model = update_model_dims.update_inputs_outputs_dims(model, {'input_name': ['seq', 'batch', 3, -1]}, {'output_name': ['seq', 'batch', 1, -1]})