onnxruntime/tools/python/create_reduced_build_config.py
Chi Lo b713855a98
Release 1.11.0 cherry pick round 1 (#10915)
* Update to flatbuffers v2.0.0 (#10866)

* Fix Reduced ops pipeline (#10861)

* Fix a couple of issues with the python package tools (#10858)

* Tweaks to the model utils
  * Add handling for a dim_value of -1 when replacing the entire input shape. This occurs in models exported from PaddlePaddle
  * make pytorch helpers accessible in package
  * make QDQ helpers accessible in package

* Fix wrong percentile values returned during calibration (#10847)

* Use numpy.percentile to get the lookup value.

* Use 1.0 as float value rather than integer.

* Add missing cdf parameter for `np.percentile`.

* Use 100. instead of 1.0

* Remove print.

* Update from @yufenglee

* Add support for opset 16 to transpose optimizer. (#10841)

* Add support for opset 16 to transpose optimizer.

Only change required is for GridSample to be added to the layout sensitive ops. The existing handling for layout transpose works with that as the first input and first output are layout sensitive.

Update the optimize to be able to return an error message if it fails.

* Use separate build directories for full and mobile iOS packages. (#10835)

* Address performance issue with abseil flat_hash_table. (#10819)

When returning by value in a cross DLL call, the hash table
even though containing all the entries that are originally there
can not find at least some of them. Reverting to std::unordered_set
pending further investigation.

* Mark end of version 11 C API. (#10803)

* Mark end of version 11 C API

* Add static_assert

* avoid using LocalFree on FormatMessageW buffer (#10796)

* remove local free

* Remove local free from onnxruntime

* don't allocate

* Change to use constexpr to satisfy  CPU build warning

* Integrate C-API tests into Pipelines for release packages (#10794)

* add c-api test for package

* fix bug for running c-api test for package

* refine run application script

* remove redundant code

* include CUDA test

* Remove testing CUDA EP temporarily

* fix bug

* Code refactor

* try to fix YAML bug

* try to fix YAML bug

* try to fix YAML bug

* fix bug for multiple directories in Pipelines

* fix bug

* add comments and fix bug

* Update c-api-noopenmp-packaging-pipelines.yml

* Remove failOnStandardError flag in Pipelines

* Detect runtime CUDA JIT and warn the user (#10781)

* Use cudaMalloc vs cudaDeviceSynchronize and show the total time

* Update convert_onnx_models_to_ort.py to support runtime optimizations. (#10765)

Add runtime optimization support to ONNX -> ORT format conversion script.
Replace `--optimization_level`, `--use_nnapi`, and `--use_coreml` with a new `--optimization_style` option.

* Add multithreading test and put a lock on nvinfer1::createInferRuntime() for TRT EP (#10714)

* Add multithread unit test and put lock on library call

* update code

* remove debug code

* add comment

* add one session multi-threads inference

* Put lock for build engine all the time

* Update naming and comment

* remove unnecessary lock

* Revert "remove unnecessary lock"

This reverts commit 9c2317b1d2273dec0ebdeb52160bc757839e5edc.

* Fix handling of nodes inserted by NHWC transformer. (#10904) (#10925)

* Revert "Upsample support NHWC (#10554)" (#10917)

This reverts commit bd08f11a58.

Co-authored-by: Yufeng Li <liyufeng1987@gmail.com>

* [python API] Change raise import error when `C:\Windows\System32\vcruntime140_1.dll` is not found to warning (#10927)

* remove throw if C:\\Windows\\System32\\vcruntime140_1.dll cannot be found

* Add comments and update warning message

* adding back accidentally removed line

Co-authored-by: gwang0000 <62914304+gwang0000@users.noreply.github.com>

* [js] Create npm packaging pipeline (#10886)

* create npm packaging pipeline

* fix indentations

* Update npm-packaging-pipeline.yml for Azure Pipelines

* Update npm-packaging-pipeline.yml for Azure Pipelines

* Update npm-packaging-pipeline.yml for Azure Pipelines

* react-native-ci as a template

* fix typos

* fix template paths

* add a depencendy

* change a stage name

* set different artifact name for each package

* fix typo

* Update npm-packaging-pipeline.yml for Azure Pipelines

Set a build Id for node npm package as a parameter

* Update npm-packaging-pipeline.yml for Azure Pipelines

Set a build Id for node npm package as a parameter

* Update npm-packaging-pipeline.yml for Azure Pipelines

* Follow up update for python API checking if `vcruntime140_1.dll` is available (#10927) (#10933)

Co-authored-by: Hariharan Seshadri <hasesh@microsoft.com>
Co-authored-by: Scott McKay <skottmckay@gmail.com>
Co-authored-by: Funtowicz Morgan <mfuntowicz@users.noreply.github.com>
Co-authored-by: Edward Chen <18449977+edgchen1@users.noreply.github.com>
Co-authored-by: Dmitri Smirnov <yuslepukhin@users.noreply.github.com>
Co-authored-by: Pranav Sharma <prs@microsoft.com>
Co-authored-by: Ryan Lai <rylai@microsoft.com>
Co-authored-by: Ryan Hill <38674843+RyanUnderhill@users.noreply.github.com>
Co-authored-by: Yi-Hong Lyu <yilyu@microsoft.com>
Co-authored-by: Yufeng Li <liyufeng1987@gmail.com>
Co-authored-by: Guoyu Wang <62914304+gwang-msft@users.noreply.github.com>
Co-authored-by: gwang0000 <62914304+gwang0000@users.noreply.github.com>
Co-authored-by: Sunghoon <35605090+hanbitmyths@users.noreply.github.com>
2022-03-18 11:16:30 -07:00

145 lines
6 KiB
Python

#!/usr/bin/env python3
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
import argparse
import onnx
import pathlib
import sys
import typing
from util.file_utils import files_from_file_or_dir, path_match_suffix_ignore_case
def _get_suffix_match_predicate(suffix: str):
def predicate(file_path: pathlib.Path):
return path_match_suffix_ignore_case(file_path, suffix)
return predicate
def _extract_ops_from_onnx_graph(graph, operators, domain_opset_map):
'''Extract ops from an ONNX graph and all subgraphs'''
for operator in graph.node:
# empty domain is used as an alias for 'ai.onnx'
domain = operator.domain if operator.domain else 'ai.onnx'
if domain not in operators or domain not in domain_opset_map:
continue
operators[domain][domain_opset_map[domain]].add(operator.op_type)
for attr in operator.attribute:
if attr.type == onnx.AttributeProto.GRAPH: # process subgraph
_extract_ops_from_onnx_graph(attr.g, operators, domain_opset_map)
elif attr.type == onnx.AttributeProto.GRAPHS:
# Currently no ONNX operators use GRAPHS.
# Fail noisily if we encounter this so we can implement support
raise RuntimeError('Unexpected attribute proto of GRAPHS')
def _process_onnx_model(model_path, required_ops):
model = onnx.load(model_path)
# create map of domain to opset for the model
domain_opset_map = {}
for opset in model.opset_import:
# empty domain == ai.onnx
domain = opset.domain if opset.domain else 'ai.onnx'
domain_opset_map[domain] = opset.version
if domain not in required_ops:
required_ops[domain] = {opset.version: set()}
elif opset.version not in required_ops[domain]:
required_ops[domain][opset.version] = set()
# check the model imports at least one opset. if it does not it's an unexpected edge case that we have to ignore
# as we don't know what opset nodes in the graph belong to.
if domain_opset_map:
_extract_ops_from_onnx_graph(model.graph, required_ops, domain_opset_map)
def _extract_ops_from_onnx_model(model_files: typing.Iterable[pathlib.Path]):
'''Extract ops from ONNX models'''
required_ops = {}
for model_file in model_files:
if not model_file.is_file():
raise ValueError(f"Path is not a file: '{model_file}'")
_process_onnx_model(model_file, required_ops)
return required_ops
def create_config_from_onnx_models(model_files: typing.Iterable[pathlib.Path], output_file: pathlib.Path):
required_ops = _extract_ops_from_onnx_model(model_files)
output_file.parent.mkdir(parents=True, exist_ok=True)
with open(output_file, 'w') as out:
out.write("# Generated from ONNX model/s:\n")
for model_file in sorted(model_files):
out.write(f"# - {model_file}\n")
for domain in sorted(required_ops.keys()):
for opset in sorted(required_ops[domain].keys()):
ops = required_ops[domain][opset]
if ops:
out.write("{};{};{}\n".format(domain, opset, ','.join(sorted(ops))))
def main():
argparser = argparse.ArgumentParser(
'Script to create a reduced build config file from either ONNX or ORT format model/s. '
'See /docs/Reduced_Operator_Kernel_build.md for more information on the configuration file format.',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
argparser.add_argument('-f', '--format', choices=['ONNX', 'ORT'], default='ONNX',
help='Format of model/s to process.')
argparser.add_argument('-t', '--enable_type_reduction', action='store_true',
help='Enable tracking of the specific types that individual operators require. '
'Operator implementations MAY support limiting the type support included in the build '
'to these types. Only possible with ORT format models.')
argparser.add_argument('model_path_or_dir', type=pathlib.Path,
help='Path to a single model, or a directory that will be recursively searched '
'for models to process.')
argparser.add_argument('config_path', nargs='?', type=pathlib.Path, default=None,
help='Path to write configuration file to. Default is to write to required_operators.config '
'or required_operators_and_types.config in the same directory as the models.')
args = argparser.parse_args()
if args.enable_type_reduction and args.format == 'ONNX':
print('Type reduction requires model format to be ORT.', file=sys.stderr)
sys.exit(-1)
model_path_or_dir = args.model_path_or_dir.resolve()
if args.config_path:
config_path = args.config_path.resolve()
else:
config_path = model_path_or_dir if model_path_or_dir.is_dir() else model_path_or_dir.parent
if config_path.is_dir():
filename = 'required_operators_and_types.config' if args.enable_type_reduction else 'required_operators.config'
config_path = config_path.joinpath(filename)
if args.format == 'ONNX':
model_files = files_from_file_or_dir(model_path_or_dir, _get_suffix_match_predicate(".onnx"))
create_config_from_onnx_models(model_files, config_path)
else:
from util.ort_format_model import create_config_from_models as create_config_from_ort_models
model_files = files_from_file_or_dir(model_path_or_dir, _get_suffix_match_predicate(".ort"))
create_config_from_ort_models(model_files, config_path, args.enable_type_reduction)
# Debug code to validate that the config parsing matches
# from util import parse_config
# required_ops, op_type_usage_processor, _ = parse_config(args.config_path, True)
# op_type_usage_processor.debug_dump()
if __name__ == "__main__":
main()