Clean up some mobile package related files and their usages. (#21606)

The mobile packages have been removed.
This commit is contained in:
Edward Chen 2024-08-05 16:38:20 -07:00 коммит произвёл GitHub
Родитель bcc01ac123
Коммит a5ce65d87a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
8 изменённых файлов: 0 добавлений и 690 удалений

Просмотреть файл

@ -508,7 +508,6 @@ file(GLOB onnxruntime_ort_format_model_srcs CONFIGURE_DEPENDS
)
file(GLOB onnxruntime_mobile_helpers_srcs CONFIGURE_DEPENDS
${REPO_ROOT}/tools/python/util/mobile_helpers/*.py
${REPO_ROOT}/tools/ci_build/github/android/mobile_package.required_operators.config
${REPO_ROOT}/tools/ci_build/github/android/nnapi_supported_ops.md
${REPO_ROOT}/tools/ci_build/github/apple/coreml_supported_mlprogram_ops.md
${REPO_ROOT}/tools/ci_build/github/apple/coreml_supported_neuralnetwork_ops.md

Просмотреть файл

@ -1,132 +0,0 @@
# ONNX Runtime Mobile Pre-Built Package Operator and Type Support
## Supported operators and types
The supported operators and types are based on what is required to support float32 and quantized versions of popular models. The full list of input models used to determine this list is available [here](https://github.com/microsoft/onnxruntime/blob/main/tools/ci_build/github/android/mobile_package.required_operators.readme.txt)
## Supported data input types
- float
- int8_t
- uint8_t
NOTE: Operators used to manipulate dimensions and indices will support int32 and int64.
## Supported Operators
|Operator|Opsets|
|--------|------|
|**ai.onnx**||
|ai.onnx:Abs|12, 13, 14, 15|
|ai.onnx:Add|12, 13, 14, 15|
|ai.onnx:And|12, 13, 14, 15|
|ai.onnx:ArgMax|12, 13, 14, 15|
|ai.onnx:ArgMin|12, 13, 14, 15|
|ai.onnx:AveragePool|12, 13, 14, 15|
|ai.onnx:Cast|12, 13, 14, 15|
|ai.onnx:Ceil|12, 13, 14, 15|
|ai.onnx:Clip|12, 13, 14, 15|
|ai.onnx:Concat|12, 13, 14, 15|
|ai.onnx:ConstantOfShape|12, 13, 14, 15|
|ai.onnx:Conv|12, 13, 14, 15|
|ai.onnx:ConvTranspose|12, 13, 14, 15|
|ai.onnx:Cos|12, 13, 14, 15|
|ai.onnx:CumSum|12, 13, 14, 15|
|ai.onnx:DepthToSpace|12, 13, 14, 15|
|ai.onnx:DequantizeLinear|12, 13, 14, 15|
|ai.onnx:Div|12, 13, 14, 15|
|ai.onnx:DynamicQuantizeLinear|12, 13, 14, 15|
|ai.onnx:Elu|12, 13, 14, 15|
|ai.onnx:Equal|12, 13, 14, 15|
|ai.onnx:Erf|12, 13, 14, 15|
|ai.onnx:Exp|12, 13, 14, 15|
|ai.onnx:Expand|12, 13, 14, 15|
|ai.onnx:Flatten|12, 13, 14, 15|
|ai.onnx:Floor|12, 13, 14, 15|
|ai.onnx:Gather|12, 13, 14, 15|
|ai.onnx:GatherND|12, 13, 14, 15|
|ai.onnx:Gemm|12, 13, 14, 15|
|ai.onnx:GlobalAveragePool|12, 13, 14, 15|
|ai.onnx:Greater|12, 13, 14, 15|
|ai.onnx:GreaterOrEqual|12, 13, 14, 15|
|ai.onnx:HardSigmoid|12, 13, 14, 15|
|ai.onnx:Identity|12, 13, 14, 15|
|ai.onnx:If|12, 13, 14, 15|
|ai.onnx:InstanceNormalization|12, 13, 14, 15|
|ai.onnx:LRN|12, 13, 14, 15|
|ai.onnx:LayerNormalization|1|
|ai.onnx:LeakyRelu|12, 13, 14, 15|
|ai.onnx:Less|12, 13, 14, 15|
|ai.onnx:LessOrEqual|12, 13, 14, 15|
|ai.onnx:Log|12, 13, 14, 15|
|ai.onnx:LogSoftmax|12, 13, 14, 15|
|ai.onnx:Loop|12, 13, 14, 15|
|ai.onnx:MatMul|12, 13, 14, 15|
|ai.onnx:MatMulInteger|12, 13, 14, 15|
|ai.onnx:Max|12, 13, 14, 15|
|ai.onnx:MaxPool|12, 13, 14, 15|
|ai.onnx:Mean|12, 13, 14, 15|
|ai.onnx:Min|12, 13, 14, 15|
|ai.onnx:Mul|12, 13, 14, 15|
|ai.onnx:Neg|12, 13, 14, 15|
|ai.onnx:NonMaxSuppression|12, 13, 14, 15|
|ai.onnx:NonZero|12, 13, 14, 15|
|ai.onnx:Not|12, 13, 14, 15|
|ai.onnx:Or|12, 13, 14, 15|
|ai.onnx:PRelu|12, 13, 14, 15|
|ai.onnx:Pad|12, 13, 14, 15|
|ai.onnx:Pow|12, 13, 14, 15|
|ai.onnx:QLinearConv|12, 13, 14, 15|
|ai.onnx:QLinearMatMul|12, 13, 14, 15|
|ai.onnx:QuantizeLinear|12, 13, 14, 15|
|ai.onnx:Range|12, 13, 14, 15|
|ai.onnx:Reciprocal|12, 13, 14, 15|
|ai.onnx:ReduceMax|12, 13, 14, 15|
|ai.onnx:ReduceMean|12, 13, 14, 15|
|ai.onnx:ReduceMin|12, 13, 14, 15|
|ai.onnx:ReduceProd|12, 13, 14, 15|
|ai.onnx:ReduceSum|12, 13, 14, 15|
|ai.onnx:Relu|12, 13, 14, 15|
|ai.onnx:Reshape|12, 13, 14, 15|
|ai.onnx:Resize|12, 13, 14, 15|
|ai.onnx:ReverseSequence|12, 13, 14, 15|
|ai.onnx:Round|12, 13, 14, 15|
|ai.onnx:Scan|12, 13, 14, 15|
|ai.onnx:ScatterND|12, 13, 14, 15|
|ai.onnx:Shape|12, 13, 14, 15|
|ai.onnx:Sigmoid|12, 13, 14, 15|
|ai.onnx:Sin|12, 13, 14, 15|
|ai.onnx:Size|12, 13, 14, 15|
|ai.onnx:Slice|12, 13, 14, 15|
|ai.onnx:Softmax|12, 13, 14, 15|
|ai.onnx:SpaceToDepth|12, 13, 14, 15|
|ai.onnx:Split|12, 13, 14, 15|
|ai.onnx:Sqrt|12, 13, 14, 15|
|ai.onnx:Squeeze|12, 13, 14, 15|
|ai.onnx:Sub|12, 13, 14, 15|
|ai.onnx:Sum|12, 13, 14, 15|
|ai.onnx:Tanh|12, 13, 14, 15|
|ai.onnx:ThresholdedRelu|12, 13, 14, 15|
|ai.onnx:Tile|12, 13, 14, 15|
|ai.onnx:TopK|12, 13, 14, 15|
|ai.onnx:Transpose|12, 13, 14, 15|
|ai.onnx:Unique|12, 13, 14, 15|
|ai.onnx:Unsqueeze|12, 13, 14, 15|
|ai.onnx:Where|12, 13, 14, 15|
|||
|**com.microsoft**||
|com.microsoft:DynamicQuantizeMatMul|1|
|com.microsoft:FusedConv|1|
|com.microsoft:FusedGemm|1|
|com.microsoft:FusedMatMul|1|
|com.microsoft:Gelu|1|
|com.microsoft:MatMulIntegerToFloat|1|
|com.microsoft:NhwcMaxPool|1|
|com.microsoft:QLinearAdd|1|
|com.microsoft:QLinearAveragePool|1|
|com.microsoft:QLinearConv|1|
|com.microsoft:QLinearGlobalAveragePool|1|
|com.microsoft:QLinearLeakyRelu|1|
|com.microsoft:QLinearMul|1|
|com.microsoft:QLinearSigmoid|1|
|||

Просмотреть файл

@ -1,46 +0,0 @@
# Android package for ORT Mobile operator and type reduction configuration
#
# The list of operators was generated from:
# - the ONNX operators use by the tf2onnx tflite converter
# - the operators used in a set of tflite models from tfhub, the tflite examples, and the mlperf mobile models
# - models were optimized with optimizations set to 'basic', 'extended' and 'all'
# - see the readme file for full details
# allow float, int8, uint8. operators that manipulate shapes or indices have int32 and int64 enabled internally.
!globally_allowed_types;float,int8_t,uint8_t
# ops used by the tf2onnx tflite converter.
ai.onnx;12,13,14,15;Abs,Add,And,ArgMax,ArgMin,AveragePool,Cast,Ceil,Clip,Concat,ConstantOfShape,Conv,ConvTranspose,Cos,CumSum,DepthToSpace,DequantizeLinear,Div,DynamicQuantizeLinear,Elu,Equal,Exp,Expand,Flatten,Floor,Gather,GatherND,Gemm,Greater,GreaterOrEqual,Identity,If,LRN,LeakyRelu,Less,LessOrEqual,Log,LogSoftmax,Loop,MatMul,Max,MaxPool,Mean,Min,Mul,Neg,NonMaxSuppression,NonZero,Not,Or,PRelu,Pad,Pow,QuantizeLinear,Range,Reciprocal,ReduceMax,ReduceMean,ReduceMin,ReduceProd,ReduceSum,Relu,Reshape,Resize,ReverseSequence,Round,ScatterND,Shape,Sigmoid,Sin,Size,Slice,Softmax,SpaceToDepth,Split,Sqrt,Squeeze,Sub,Sum,Tanh,ThresholdedRelu,Tile,TopK,Transpose,Unique,Unsqueeze,Where
# other ops found in test models
ai.onnx;12,13,14,15;Erf,GlobalAveragePool,InstanceNormalization,HardSigmoid,MatMulInteger,QLinearConv,QLinearMatMul
# Control flow ops
# - If and Loop are covered by the tflite converter list
# - Scan tends to be used in speech models (it's more efficient than Loop) so include it for support of those
ai.onnx;12,13,14,15;Scan
# Changed ONNX ops by opset version for the above ops. This list is to provide context as to how much was added
# for each additional opset we support.
#
# opset 13
# Abs,Add,ArgMax,ArgMin,Cast,Ceil,Clip,Concat,DepthToSpace,DequantizeLinear,Div,Equal,Erf,Exp,Expand,Flatten,Floor,
# Gather,GatherND,Gemm,Greater,Identity,If,LRN,Less,Log,LogSoftmax,Loop,MatMul,Max,Mean,Min,Mul,Neg,NonZero,Pad,
# Pow,QuantizeLinear,Reciprocal,ReduceMax,ReduceMean,ReduceMin,ReduceProd,ReduceSum,Relu,Reshape,Resize,
# ScatterND,Shape,Sigmoid,Size,Slice,Softmax,SpaceToDepth,Split,Sqrt,Squeeze,Sub,Sum,Tanh,Tile,Transpose,Unsqueeze
# opset 14
# Add,CumSum,Div,Identity,Mul,Relu,Reshape,Sub
# opset 15
# Pow,Shape
# internal ops added by optimizers
# Note: LayerNormalization is an internal op even though it is (incorrectly) registered in the ONNX domain.
ai.onnx;1;LayerNormalization
com.microsoft;1;DynamicQuantizeMatMul,FusedConv,FusedGemm,FusedMatMul,Gelu,MatMulIntegerToFloat,NhwcMaxPool,QLinearAdd,QLinearAveragePool,QLinearConv,QLinearGlobalAveragePool,QLinearMul,QLinearSigmoid
# NHWC transformer also uses this, so assuming it's valuable enough to include
com.microsoft;1;QLinearLeakyRelu
# Quantized contrib ops that are registered but no usage was found. Excluding for now.
# com.microsoft;1;DynamicQuantizeLSTM,QAttention

Просмотреть файл

@ -1,82 +0,0 @@
The required operators config file was generated from a number of models (details below), with optimizations run using 'all', 'extended' and 'basic'.
Following that, some additional operators were added, as per the comments in the config file.
The global types to support were selected to support quantized and float32 models
Additionally there is internal 'required' type support for int32 and int64_t in selected operators that work with the dimensions in a shape or indices so that we don't need to enable those types at a global level.
Models used as input (Converted using tf2onnx in early March 2021):
Models from TF Lite Examples https://www.tensorflow.org/lite/examples
- lite-model_deeplabv3_1_metadata_2.tflite.onnx
- lite-model_esrgan-tf2_1.tflite.onnx
- lite-model_mobilebert_1_metadata_1.tflite.onnx
- mnist.tflite.onnx
- mobilenet_v1_1.0_224_quant.tflite.onnx
- model_history10_top100.tflite.onnx
- posenet_mobilenet_float_075_1_default_1.tflite.onnx
- posenet_mobilenet_v1_100_257x257_multi_kpt_stripped.tflite.onnx
- ssd_mobilenet_v1_1_metadata_1.tflite.onnx
- text_classification_v2.tflite.onnx
Assorted models from TF Hub that were able to be converted with tf2onnx
TFLite v1 https://tfhub.dev/s?deployment-format=lite&tf-version=tf1
- efficientnet_lite1_fp32_2.tflite.onnx
- efficientnet_lite1_int8_2.tflite.onnx
- efficientnet_lite4_fp32_2.tflite.onnx
- efficientnet_lite4_int8_2.tflite.onnx
- lite-model_aiy_vision_classifier_birds_V1_3.tflite.onnx
- lite-model_aiy_vision_classifier_food_V1_1.tflite.onnx
- lite-model_aiy_vision_classifier_plants_V1_3.tflite.onnx
- lite-model_midas_v2_1_small_1_lite_1.tflite.onnx
- lite-model_object_detection_mobile_object_labeler_v1_1.tflite.onnx
- magenta_arbitrary-image-stylization-v1-256_int8_prediction_1.tflite.onnx
- magenta_arbitrary-image-stylization-v1-256_int8_transfer_1.tflite.onnx
- object_detection_mobile_object_localizer_v1_1_default_1.tflite.onnx
TFLite v2 https://tfhub.dev/s?deployment-format=lite&tf-version=tf2
- tf2\albert_lite_base_squadv1_1.tflite.onnx
- tf2\lite-model_disease-classification_1.tflite.onnx
- tf2\lite-model_efficientdet_lite0_detection_default_1.tflite.onnx
- tf2\lite-model_efficientdet_lite0_int8_1.tflite.onnx
- tf2\lite-model_efficientdet_lite1_detection_default_1.tflite.onnx
- tf2\lite-model_efficientdet_lite2_detection_default_1.tflite.onnx
- tf2\lite-model_efficientdet_lite3_detection_default_1.tflite.onnx
- tf2\lite-model_efficientdet_lite4_detection_default_1.tflite.onnx
- tf2\lite-model_esrgan-tf2_1.tflite.onnx
- tf2\lite-model_german-mbmelgan_lite_1.tflite.onnx
- tf2\lite-model_nonsemantic-speech-benchmark_trill-distilled_1.tflite.onnx
- tf2\lite-model_yamnet_tflite_1.tflite.onnx
Models from MLPerf Mobile
(mainly models converted from TFLite and quantized in different ways, but some from TF for completeness as those also have batch handling)
- deeplabv3_mnv2_ade20k_float-int8.onnx
- deeplabv3_mnv2_ade20k_float.onnx
- deeplabv3_mnv2_ade20k-qdq.onnx
- mobilebert-int8.onnx
- mobilebert-qdq.onnx
- mobilebert.onnx
- mobiledet-int8.onnx
- mobiledet-qdq.onnx
- mobiledet.onnx
- mobilenet_edgetpu_224_1.0_float-int8.onnx
- mobilenet_edgetpu_224_1.0_float.onnx
- mobilenet_edgetpu_224_1.0-qdq.onnx
- mobilenet_v1_1.0_224.opset12.onnx
- resnet50_v1-int8.onnx
- resnet50_v1.onnx
- ssd_mobilenet_v2_300_float-int8.onnx
- ssd_mobilenet_v2_300_float.onnx
- ssd_mobilenet_v2_300-qdq.onnx
Other
Mobilenet v2 and v3 from pytorch
- https://pytorch.org/vision/stable/models.html
- pytorch.mobilenet_v2_float.onnx
- pytorch.mobilenet_v2_uint8.onnx
- pytorch.mobilenet_v3_small.onnx
Other assorted pytorch models
- Huggingface mobilebert-uncased (https://huggingface.co/transformers/serialization.html, https://huggingface.co/google/mobilebert-uncased)
- SuperResolution (https://pytorch.org/tutorials/advanced/super_resolution_with_onnxruntime.html)
- DeepLabV3 (https://pytorch.org/tutorials/beginner/deeplabv3_on_android.html)
- EfficientNet (https://github.com/lukemelas/EfficientNet-PyTorch)
- SSD Mobilenet V1 and V2 (https://github.com/qfgaohao/pytorch-ssd)
- Wav2Vec 2.0 (adapted from https://github.com/pytorch/ios-demo-app/blob/f2b9aa196821c136d3299b99c5dd592de1fa1776/SpeechRecognition/create_wav2vec2.py)

Просмотреть файл

@ -13,21 +13,9 @@ resources:
ref: 5eda9aded5462201e6310105728d33016e637ea7
stages:
# checks enabled in all builds
- template: templates/android-binary-size-check-stage.yml
parameters:
Name: MinimalBaseline
BuildConfigFile: "tools/ci_build/github/linux/ort_minimal/build_check_binsize_config/android_minimal_baseline.config"
BinarySizeThresholdInBytes: 1306224
DoBuildWithDebugInfo: ${{ parameters.DoBuildWithDebugInfo }}
# checks excluded from PR builds
- ${{ if ne(variables['Build.Reason'], 'PullRequest') }}:
- template: templates/android-binary-size-check-stage.yml
parameters:
Name: MinimalWithMobilePackageOps
BuildConfigFile: "tools/ci_build/github/linux/ort_minimal/build_check_binsize_config/android_minimal_with_mobile_package_ops.config"
DoBuildWithDebugInfo: ${{ parameters.DoBuildWithDebugInfo }}

Просмотреть файл

@ -1,19 +0,0 @@
{
"type": "minimal-with-mobile-package-ops",
"os": "android",
"arch": "arm64-v8a",
"build_params": [
"--enable_lto",
"--android",
"--android_sdk_path=/android_home",
"--android_ndk_path=/ndk_home",
"--android_abi=arm64-v8a",
"--android_api=29",
"--minimal_build",
"--build_shared_lib",
"--build_java",
"--disable_ml_ops",
"--disable_exceptions",
"--include_ops_by_config=/onnxruntime_src/tools/ci_build/github/android/mobile_package.required_operators.config"
]
}

Просмотреть файл

@ -1,97 +0,0 @@
import argparse
import os
import pathlib
from util import reduced_build_config_parser
from util.ort_format_model.operator_type_usage_processors import GloballyAllowedTypesOpTypeImplFilter
def generate_docs(output_file, required_ops, op_type_impl_filter):
with open(output_file, "w") as out:
out.write("# ONNX Runtime Mobile Pre-Built Package Operator and Type Support\n\n")
# Description
out.write("## Supported operators and types\n\n")
out.write(
"The supported operators and types are based on what is required to support float32 and quantized "
"versions of popular models. The full list of input models used to determine this list is available "
"[here](https://github.com/microsoft/onnxruntime/blob/main/tools/ci_build/github/android/mobile_package"
".required_operators.readme.txt)"
)
out.write("\n\n")
# Globally supported types
out.write("## Supported data input types\n\n")
assert op_type_impl_filter.__class__ is GloballyAllowedTypesOpTypeImplFilter
global_types = op_type_impl_filter.global_type_list()
for type in sorted(global_types):
out.write(f" - {type}\n")
out.write("\n")
out.write("NOTE: Operators used to manipulate dimensions and indices will support int32 and int64.\n\n")
domain_op_opsets = []
for domain in sorted(required_ops.keys()):
op_opsets = {}
domain_op_opsets.append((domain, op_opsets))
for opset in sorted(required_ops[domain].keys()):
str_opset = str(opset)
for op in required_ops[domain][opset]:
op_with_domain = f"{domain}:{op}"
if op_with_domain not in op_opsets:
op_opsets[op_with_domain] = []
op_opsets[op_with_domain].append(str_opset)
out.write("## Supported Operators\n\n")
out.write("|Operator|Opsets|\n")
out.write("|--------|------|\n")
for domain, op_opsets in domain_op_opsets:
out.write(f"|**{domain}**||\n")
for op in sorted(op_opsets.keys()):
out.write("|{}|{}|\n".format(op, ", ".join(op_opsets[op])))
out.write("|||\n")
def main():
script_dir = os.path.dirname(os.path.realpath(__file__))
parser = argparse.ArgumentParser(
description="ONNX Runtime Mobile Pre-Built Package Operator and Type Support Documentation Generator",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
default_config_path = pathlib.Path(
os.path.join(script_dir, "../ci_build/github/android/mobile_package.required_operators.config")
).resolve()
default_output_path = pathlib.Path(
os.path.join(script_dir, "../../docs/ORTMobilePackageOperatorTypeSupport.md")
).resolve()
parser.add_argument(
"--config_path",
help="Path to build configuration used to generate package.",
required=False,
type=pathlib.Path,
default=default_config_path,
)
parser.add_argument(
"--output_path",
help="output markdown file path",
required=False,
type=pathlib.Path,
default=default_output_path,
)
args = parser.parse_args()
config_file = args.config_path.resolve(strict=True) # must exist so strict=True
output_path = args.output_path.resolve()
enable_type_reduction = True
required_ops, op_type_impl_filter = reduced_build_config_parser.parse_config(config_file, enable_type_reduction)
generate_docs(output_path, required_ops, op_type_impl_filter)
if __name__ == "__main__":
main()

Просмотреть файл

@ -1,301 +0,0 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
# Helper script that will check if the types and operators used in an ONNX model
# are supported by the pre-built ORT Mobile package.
import argparse
import logging
import pathlib
import sys
import onnx
from ..onnx_model_utils import ModelProtoWithShapeInfo, get_opsets_imported
from ..reduced_build_config_parser import parse_config
cpp_to_tensorproto_type = {
"float": 1,
"uint8_t": 2,
"int8_t": 3,
"uint16_t": 4,
"int16_t": 5,
"int32_t": 6,
"int64_t": 7,
"std::string": 8,
"bool": 9,
"MLFloat16": 10,
"double": 11,
"uint32_t": 12,
"uint64_t": 13,
"Complex64": 14, # not supported by ORT
"Complex128": 15, # not supported by ORT
"BFloat16": 16,
}
tensorproto_type_to_cpp = {v: k for k, v in cpp_to_tensorproto_type.items()}
def check_graph(graph, opsets, required_ops, global_types, special_types, unsupported_ops, logger):
"""
Check the graph and any subgraphs for usage of types or operators which we know are not supported.
:param graph: Graph to process.
:param opsets: Map of domain to opset version that the model imports.
:param required_ops: Operators that are included in the pre-built package.
:param global_types: Types globally enabled in the pre-built package.
:param special_types: Types that are always enabled for a subset of operators and are _usually_ supported but are
not guaranteed to be. We would need to add a lot of infrastructure to know for sure so
currently we treat them as supported.
:param unsupported_ops: Set of unsupported operators that were found.
:param logger: Logger for diagnostic output.
:return: Returns whether the graph uses unsupported operators or types.
"""
has_unsupported_types = False
value_info_map = {vi.name: vi for vi in graph.value_info}
def _is_type_supported(value_info, description):
is_supported = True
type_name = value_info.type.WhichOneof("value")
if type_name == "tensor_type":
t = value_info.type.tensor_type.elem_type
if t not in global_types and t not in special_types:
cpp_type = tensorproto_type_to_cpp[t]
logger.debug(f"Element type {cpp_type} of {description} is not supported.")
is_supported = False
else:
# we don't support sequences, map, sparse tensors, or optional types in the pre-built package
logger.debug(f"Data type {type_name} of {description} is not supported.")
is_supported = False
return is_supported
def _input_output_is_supported(value_info, input_output):
return _is_type_supported(value_info, f"graph {input_output} {value_info.name}")
# node outputs are simpler to check.
# node inputs have a much wider mix of types, some of which come from initializers and most likely are always
# enabled as we generally do type reduction on the user data input to the operator and not the weights/etc. which
# come from initializers.
def _node_output_is_supported(name):
is_supported = True
if name in value_info_map:
vi = value_info_map[name]
is_supported = _is_type_supported(vi, f"node output {name}")
else:
# we don't have type info so ignore
pass
return is_supported
for i in graph.input:
if not _input_output_is_supported(i, "input"):
has_unsupported_types = True
for o in graph.output:
if not _input_output_is_supported(o, "output"):
has_unsupported_types = True
for node in graph.node:
# required_ops are map of [domain][opset] to set of op_type names. '' == ai.onnx
domain = node.domain or "ai.onnx"
# special case Constant as we will convert to an initializer during model load
if domain == "ai.onnx" and node.op_type == "Constant":
continue
# some models don't have complete imports. use 1 as a default as that's valid for custom domains and should
# result in an error for any others. not sure why ONNX or ORT validation allows this though.
opset = opsets.get(domain, 1)
if (
domain not in required_ops
or opset not in required_ops[domain]
or node.op_type not in required_ops[domain][opset]
):
unsupported_ops.add(f"{domain}:{opset}:{node.op_type}")
for output_name in node.output:
if not _node_output_is_supported(output_name):
has_unsupported_types = True
# recurse into subgraph for control flow nodes (Scan/Loop/If)
for attr in node.attribute:
if attr.HasField("g"):
check_graph(attr.g, opsets, required_ops, global_types, special_types, unsupported_ops, logger)
return has_unsupported_types or unsupported_ops
def _get_global_tensorproto_types(op_type_impl_filter, logger: logging.Logger):
"""
Map the globally supported types (C++) to onnx.TensorProto.DataType values used in the model
See https://github.com/onnx/onnx/blob/1faae95520649c93ae8d0b403816938a190f4fa7/onnx/onnx.proto#L485
Additionally return a set of types we special case as being able to generally be considered as supported.
:param op_type_impl_filter: type filter from reduced build configuration parser
:param logger: Logger
:return: tuple of globally enabled types and special cased types
"""
global_cpp_types = op_type_impl_filter.global_type_list()
global_onnx_tensorproto_types = set()
for t in global_cpp_types:
if t in cpp_to_tensorproto_type:
global_onnx_tensorproto_types.add(cpp_to_tensorproto_type[t])
else:
logger.error(f"Error: Unexpected data type of {t} in package build config's globally enabled types.")
sys.exit(-1)
# a subset of operators require int32 and int64 to always be enabled, as those types are used for dimensions in
# shapes and indices.
# additionally we have a number of operators (e.g. Not, Where) that always require the use of bool.
# this _may_ mean values involving these types can be processed, but without adding a lot more code we don't know
# for sure.
special_types = [
cpp_to_tensorproto_type["int32_t"],
cpp_to_tensorproto_type["int64_t"],
cpp_to_tensorproto_type["bool"],
]
return global_onnx_tensorproto_types, special_types
def get_default_config_path():
# get default path to config that was used to create the pre-built package.
script_dir = pathlib.Path(__file__).parent
local_config = script_dir / "mobile_package.required_operators.config"
# if we're running in the ORT python package the file should be local. otherwise assume we're running from the
# ORT repo
if local_config.exists():
default_config_path = local_config
else:
ort_root = script_dir.parents[3]
default_config_path = (
ort_root / "tools" / "ci_build" / "github" / "android" / "mobile_package.required_operators.config"
)
return default_config_path
def run_check_with_model(
model_with_type_info: onnx.ModelProto, mobile_pkg_build_config: pathlib.Path, logger: logging.Logger
):
"""
Check if an ONNX model can be used with the ORT Mobile pre-built package.
:param model_with_type_info: ONNX model that has had ONNX shape inferencing run on to add type/shape information.
:param mobile_pkg_build_config: Configuration file used to build the ORT Mobile package.
:param logger: Logger for output
:return: True if supported
"""
if not mobile_pkg_build_config:
mobile_pkg_build_config = get_default_config_path()
enable_type_reduction = True
config_path = str(mobile_pkg_build_config.resolve(strict=True))
required_ops, op_type_impl_filter = parse_config(config_path, enable_type_reduction)
global_onnx_tensorproto_types, special_types = _get_global_tensorproto_types(op_type_impl_filter, logger)
# get the opset imports
opsets = get_opsets_imported(model_with_type_info)
# If the ONNX opset of the model is not supported we can recommend using our tools to update that first.
supported_onnx_opsets = set(required_ops["ai.onnx"].keys())
# we have a contrib op that is erroneously in the ai.onnx domain with opset 1. manually remove that incorrect value
supported_onnx_opsets.remove(1)
onnx_opset_model_uses = opsets["ai.onnx"]
if onnx_opset_model_uses not in supported_onnx_opsets:
logger.info(f"Model uses ONNX opset {onnx_opset_model_uses}.")
logger.info(f"The pre-built package only supports ONNX opsets {sorted(supported_onnx_opsets)}.")
logger.info(
"Please try updating the ONNX model opset to a supported version using "
"python -m onnxruntime.tools.onnx_model_utils.update_onnx_opset ..."
)
return False
unsupported_ops = set()
logger.debug(
"Checking if the data types and operators used in the model are supported in the pre-built ORT package..."
)
unsupported = check_graph(
model_with_type_info.graph,
opsets,
required_ops,
global_onnx_tensorproto_types,
special_types,
unsupported_ops,
logger,
)
if unsupported_ops:
logger.info("Unsupported operators:")
for entry in sorted(unsupported_ops):
logger.info(" " + entry) # noqa: G003
if unsupported:
logger.info("\nModel is not supported by the pre-built package due to unsupported types and/or operators.")
logger.info(
"Please see https://onnxruntime.ai/docs/install/#install-on-web-and-mobile for information "
"on what is supported in the pre-built package."
)
logger.info(
"The 'full' ORT package for Android (onnxruntime-android) or iOS (onnxruntime-{objc|c}) could be used, "
"or a custom build of ONNX Runtime will be required if binary size is critical. Please see "
"https://onnxruntime.ai/docs/build/custom.html for details on performing that."
)
else:
logger.info("Model should work with the pre-built package.")
logger.info("---------------\n")
return not unsupported
def run_check(model_path: pathlib.Path, mobile_pkg_build_config: pathlib.Path, logger: logging.Logger):
"""
Check if an ONNX model will be able to be used with the ORT Mobile pre-built package.
:param model_path: Path to ONNX model.
:param mobile_pkg_build_config: Configuration file used to build the ORT Mobile package.
:param logger: Logger for output
:return: True if supported
"""
logger.info(
f"Checking if pre-built ORT Mobile package can be used with {model_path} once model is "
"converted from ONNX to ORT format using onnxruntime.tools.convert_onnx_models_to_ort..."
)
model_file = model_path.resolve(strict=True)
# we need to run shape inferencing to populate that type info for node outputs.
# we will get warnings if the model uses ORT contrib ops (ONNX does not have shape inferencing for those),
# and shape inferencing will be lost downstream of those.
# TODO: add support for checking ORT format model as it will have full type/shape info for all nodes
model_wrapper = ModelProtoWithShapeInfo(model_file)
return run_check_with_model(model_wrapper.model_with_shape_info, mobile_pkg_build_config, logger)
def main():
parser = argparse.ArgumentParser(
description="Check if model can be run using the ONNX Runtime Mobile Pre-Built Package",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument(
"--config_path",
help="Path to required operators and types configuration used to build the pre-built ORT mobile package.",
required=False,
type=pathlib.Path,
default=get_default_config_path(),
)
parser.add_argument("model_path", help="Path to ONNX model to check", type=pathlib.Path)
args = parser.parse_args()
logger = logging.getLogger("default")
logger.setLevel(logging.INFO)
run_check(args.model_path, args.config_path, logger)
if __name__ == "__main__":
main()