From a5ce65d87ae0ec18190ebb6ef5ec4170afb187f4 Mon Sep 17 00:00:00 2001 From: Edward Chen <18449977+edgchen1@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:38:20 -0700 Subject: [PATCH] Clean up some mobile package related files and their usages. (#21606) The mobile packages have been removed. --- cmake/onnxruntime_python.cmake | 1 - docs/ORTMobilePackageOperatorTypeSupport.md | 132 -------- .../mobile_package.required_operators.config | 46 --- ...bile_package.required_operators.readme.txt | 82 ----- .../binary-size-checks-pipeline.yml | 12 - ...oid_minimal_with_mobile_package_ops.config | 19 -- tools/python/gen_ort_mobile_pkg_doc.py | 97 ------ .../check_model_can_use_ort_mobile_pkg.py | 301 ------------------ 8 files changed, 690 deletions(-) delete mode 100644 docs/ORTMobilePackageOperatorTypeSupport.md delete mode 100644 tools/ci_build/github/android/mobile_package.required_operators.config delete mode 100644 tools/ci_build/github/android/mobile_package.required_operators.readme.txt delete mode 100644 tools/ci_build/github/linux/ort_minimal/build_check_binsize_config/android_minimal_with_mobile_package_ops.config delete mode 100644 tools/python/gen_ort_mobile_pkg_doc.py delete mode 100644 tools/python/util/mobile_helpers/check_model_can_use_ort_mobile_pkg.py diff --git a/cmake/onnxruntime_python.cmake b/cmake/onnxruntime_python.cmake index 372db15b108fb..b2dbe4b3da5e8 100644 --- a/cmake/onnxruntime_python.cmake +++ b/cmake/onnxruntime_python.cmake @@ -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 diff --git a/docs/ORTMobilePackageOperatorTypeSupport.md b/docs/ORTMobilePackageOperatorTypeSupport.md deleted file mode 100644 index 6a69a2c598823..0000000000000 --- a/docs/ORTMobilePackageOperatorTypeSupport.md +++ /dev/null @@ -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| -||| diff --git a/tools/ci_build/github/android/mobile_package.required_operators.config b/tools/ci_build/github/android/mobile_package.required_operators.config deleted file mode 100644 index 6a6ba8c3c90e7..0000000000000 --- a/tools/ci_build/github/android/mobile_package.required_operators.config +++ /dev/null @@ -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 diff --git a/tools/ci_build/github/android/mobile_package.required_operators.readme.txt b/tools/ci_build/github/android/mobile_package.required_operators.readme.txt deleted file mode 100644 index 9e60cba4a42f1..0000000000000 --- a/tools/ci_build/github/android/mobile_package.required_operators.readme.txt +++ /dev/null @@ -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) diff --git a/tools/ci_build/github/azure-pipelines/binary-size-checks-pipeline.yml b/tools/ci_build/github/azure-pipelines/binary-size-checks-pipeline.yml index e9762bc312455..74866cfd59b52 100644 --- a/tools/ci_build/github/azure-pipelines/binary-size-checks-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/binary-size-checks-pipeline.yml @@ -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 }} diff --git a/tools/ci_build/github/linux/ort_minimal/build_check_binsize_config/android_minimal_with_mobile_package_ops.config b/tools/ci_build/github/linux/ort_minimal/build_check_binsize_config/android_minimal_with_mobile_package_ops.config deleted file mode 100644 index dbebec5788ddb..0000000000000 --- a/tools/ci_build/github/linux/ort_minimal/build_check_binsize_config/android_minimal_with_mobile_package_ops.config +++ /dev/null @@ -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" - ] -} diff --git a/tools/python/gen_ort_mobile_pkg_doc.py b/tools/python/gen_ort_mobile_pkg_doc.py deleted file mode 100644 index 482cb05bb50b9..0000000000000 --- a/tools/python/gen_ort_mobile_pkg_doc.py +++ /dev/null @@ -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() diff --git a/tools/python/util/mobile_helpers/check_model_can_use_ort_mobile_pkg.py b/tools/python/util/mobile_helpers/check_model_can_use_ort_mobile_pkg.py deleted file mode 100644 index 23bfce2e1c64d..0000000000000 --- a/tools/python/util/mobile_helpers/check_model_can_use_ort_mobile_pkg.py +++ /dev/null @@ -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()