From 9545b1bd9ec7ed60156a95aa2052335804b43370 Mon Sep 17 00:00:00 2001 From: chenyx113 Date: Thu, 6 Feb 2025 21:47:27 +0800 Subject: [PATCH 1/3] onnx-subgraph step by step PR, split the onnx with existing parse result --- tools/onnx-subgraph/CMakeLists.txt | 30 ++++++++++ tools/onnx-subgraph/Readme.md | 56 +++++++++++++++++++ tools/onnx-subgraph/extract_onnx.py | 65 ++++++++++++++++++++++ tools/onnx-subgraph/subgraphs_ios.txt | 4 ++ tools/onnx-subgraph/test_model_download.sh | 16 ++++++ 5 files changed, 171 insertions(+) create mode 100644 tools/onnx-subgraph/CMakeLists.txt create mode 100644 tools/onnx-subgraph/Readme.md create mode 100644 tools/onnx-subgraph/extract_onnx.py create mode 100644 tools/onnx-subgraph/subgraphs_ios.txt create mode 100644 tools/onnx-subgraph/test_model_download.sh diff --git a/tools/onnx-subgraph/CMakeLists.txt b/tools/onnx-subgraph/CMakeLists.txt new file mode 100644 index 00000000000..730f2485d2e --- /dev/null +++ b/tools/onnx-subgraph/CMakeLists.txt @@ -0,0 +1,30 @@ +# cmake version dependency +cmake_minimum_required(VERSION 3.10) + +set(ONNX_SUGRAPH_FILES + extract_onnx.py + test_model_download.sh + subgraphs_ios.txt + ) + + foreach(ONNX_SUGRAPH IN ITEMS ${ONNX_SUGRAPH_FILES}) + set(ONNX_SUGRAPH_FILE ${ONNX_SUGRAPH}) + set(ONNX_SUGRAPH_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${ONNX_SUGRAPH_FILE}") + set(ONNX_SUGRAPH_BIN "${CMAKE_CURRENT_BINARY_DIR}/scripts/${ONNX_SUGRAPH_FILE}") + set(ONNX_SUGRAPH_TARGET "${ONNX_SUGRAPH}_target") + + add_custom_command(OUTPUT ${ONNX_SUGRAPH_BIN} + COMMAND ${CMAKE_COMMAND} -E copy "${ONNX_SUGRAPH_SRC}" "${ONNX_SUGRAPH_BIN}" + DEPENDS ${ONNX_SUGRAPH_SRC} + COMMENT "Generate ${ONNX_SUGRAPH_BIN}" + ) + + add_custom_target(${ONNX_SUGRAPH_TARGET} ALL DEPENDS ${ONNX_SUGRAPH_BIN}) + + install(FILES ${ONNX_SUGRAPH_BIN} + PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE + DESTINATION bin) + + endforeach(ONNX_SUGRAPH) diff --git a/tools/onnx-subgraph/Readme.md b/tools/onnx-subgraph/Readme.md new file mode 100644 index 00000000000..44a054d3c11 --- /dev/null +++ b/tools/onnx-subgraph/Readme.md @@ -0,0 +1,56 @@ +# onnx_autosubgraph +onnx-subgraph tool provides model auto partitionioning of onnx model to several sub models by +operator, performance and model size limitations,with the order and input / output names of +sub models + +# How to build the onnx-subgraph +## OS environment dependence + 1. ubuntu >=20.04 + 2. GCC >= 9.4.0 + 3. cmake >= 3.10 + 4. python >= 3.8 + 5. apt-get install libprotobuf-dev protobuf-compiler libjsoncpp-dev + +## Python packages dependence + onnx 1.16.0 + onnxruntime 1.18.1 + onnxsim 0.4.36 + torch 2.3.1 + scikit-image + scikit-learn + pandas + tqdm + +## building the onnx-subgraph + 1. cd onnx-subgraph + 2. mkdir build & cd build + 3. cmake .. & make + 4. we can get following output at ./build + └── scripts + ├── extract_onnx.py + └── test_model_download.sh + └── subgraphs_ios.txt + +# How to use the onnx-subgraph +## Pre-steps +### Download the test AI models + 1. bash scripts/test_model_download.sh, then "resnet-test.onnx" will be got in ./build + 2. you can change to any other onnx files as your needs, or edit the download link in + "scripts/test_model_download.sh" + +## Parse the onnx model + note: subgraphs_ios.txt will be generated in future code, suppose we already have it as + the example file now + +## Split the onnx model to subgraphs + 1. edit the config path and model file path at ./scripts/extract_onnx.py + e.g.: extract_onnx_lib.split_onnx_ios('./scripts/subgraphs_ios.txt','./resnet-test.onnx') + 2. python scripts/extract_onnx.py, after extraction done, the subgraphs will be saved + at './subgraphs' + subgraphs + ├── CPU + │   ├── CPUsubgraph0.onnx + │   └── CPUsubgraph1.onnx + └── NPU + ├── NPUsubgraph0.onnx + └── NPUsubgraph1.onnx diff --git a/tools/onnx-subgraph/extract_onnx.py b/tools/onnx-subgraph/extract_onnx.py new file mode 100644 index 00000000000..8b45f6ccb0f --- /dev/null +++ b/tools/onnx-subgraph/extract_onnx.py @@ -0,0 +1,65 @@ +# Copyright (c) 2025 Samsung Electronics Co., Ltd. All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import onnx +import re +import os + +def splitsubgraph_ios(iofile): + iolist = re.split('--input-name |;--output-name ', iofile) + in_ = iolist[1].split(';') + out_ = iolist[2].split(';') + del out_[-1] + type = iolist[0].split('subgraph')[0] + return in_, out_, type + +def split_onnx_ios(instrfile, + input_path='net/generation_model_simplify.onnx', + out_folder='subgraphs/'): + if not os.path.exists(input_path): + print(input_path + " not exist") + return + + model = onnx.load(input_path) + onnx.checker.check_model(input_path) + for output in model.graph.output: + model.graph.value_info.append(output) + onnx.save(model, input_path) + f1 = open(instrfile, "r") + lines = f1.readlines() + cpu_count = 0 + npu_count = 0 + count = 0 + if not os.path.exists(out_folder): + os.makedirs(out_folder) + for line in lines: + input_names, output_names, type = splitsubgraph_ios(line) + if (type == 'CPU'): + count = cpu_count + cpu_count = cpu_count + 1 + else: + count = npu_count + npu_count = npu_count + 1 + output_path_folder = out_folder + if not os.path.exists(output_path_folder): + os.makedirs(output_path_folder) + output_path = output_path_folder + type + 'subgraph' + str(count) + '.onnx' + if ((input_names != ['']) and (output_names != [''])): + onnx.utils.extract_model(input_path, output_path, input_names, output_names) + print("succeed", count) + count = count + 1 + f1.close() + +if __name__ == "__main__": + split_onnx_ios('./scripts/subgraphs_ios.txt', './resnet-test.onnx') diff --git a/tools/onnx-subgraph/subgraphs_ios.txt b/tools/onnx-subgraph/subgraphs_ios.txt new file mode 100644 index 00000000000..9dfdc95e32e --- /dev/null +++ b/tools/onnx-subgraph/subgraphs_ios.txt @@ -0,0 +1,4 @@ +NPUsubgraph0: order0--input-name x;--output-name /stem/conv3/bn/act/Mul_output_0; +NPUsubgraph1: order2--input-name /stem/pool/MaxPool_output_0;--output-name /stages/stages.3/stages.3.1/act/Mul_output_0; +CPUsubgraph0: order1--input-name /stem/conv3/bn/act/Mul_output_0;--output-name /stem/pool/MaxPool_output_0; +CPUsubgraph1: order3--input-name /stages/stages.3/stages.3.1/act/Mul_output_0;--output-name 316; diff --git a/tools/onnx-subgraph/test_model_download.sh b/tools/onnx-subgraph/test_model_download.sh new file mode 100644 index 00000000000..d6597d2dd79 --- /dev/null +++ b/tools/onnx-subgraph/test_model_download.sh @@ -0,0 +1,16 @@ +pip install onnx onnxsim + +if [ ! -d "./models/" ];then + mkdir ./models/ + else + echo "./models path existing" +fi + +cd ./models +wget https://media.githubusercontent.com/media/onnx/models/refs/heads/main/Computer_Vision/resnext26ts_Opset16_timm/resnext26ts_Opset16.onnx --no-check-certificate +#wget https://media.githubusercontent.com/media/onnx/models/refs/heads/main/Natural_Language_Processing/xmod_Opset16_transformers/xmod_Opset16.onnx --no-check-certificate + +onnxsim resnext26ts_Opset16.onnx ../resnet-test.onnx +#onnxsim xmod_Opset16.onnx ../xmod-transformer-test.onnx + +cd .. From b41d4e9fec285f298a72cd77e1d32eb95a15dbd7 Mon Sep 17 00:00:00 2001 From: chenyx113 Date: Thu, 6 Feb 2025 21:48:27 +0800 Subject: [PATCH 2/3] correct the format issue --- tools/onnx-subgraph/extract_onnx.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/onnx-subgraph/extract_onnx.py b/tools/onnx-subgraph/extract_onnx.py index 8b45f6ccb0f..ba51b35a269 100644 --- a/tools/onnx-subgraph/extract_onnx.py +++ b/tools/onnx-subgraph/extract_onnx.py @@ -16,6 +16,7 @@ import re import os + def splitsubgraph_ios(iofile): iolist = re.split('--input-name |;--output-name ', iofile) in_ = iolist[1].split(';') @@ -24,6 +25,7 @@ def splitsubgraph_ios(iofile): type = iolist[0].split('subgraph')[0] return in_, out_, type + def split_onnx_ios(instrfile, input_path='net/generation_model_simplify.onnx', out_folder='subgraphs/'): @@ -61,5 +63,6 @@ def split_onnx_ios(instrfile, count = count + 1 f1.close() + if __name__ == "__main__": split_onnx_ios('./scripts/subgraphs_ios.txt', './resnet-test.onnx') From dc6931a7f6f933ec1d64fc2e82eb072b174acfb5 Mon Sep 17 00:00:00 2001 From: chenyx113 Date: Fri, 7 Feb 2025 09:52:12 +0800 Subject: [PATCH 3/3] Update extract_onnx.py remove empty lines --- tools/onnx-subgraph/extract_onnx.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tools/onnx-subgraph/extract_onnx.py b/tools/onnx-subgraph/extract_onnx.py index ba51b35a269..6c97e564e46 100644 --- a/tools/onnx-subgraph/extract_onnx.py +++ b/tools/onnx-subgraph/extract_onnx.py @@ -16,7 +16,6 @@ import re import os - def splitsubgraph_ios(iofile): iolist = re.split('--input-name |;--output-name ', iofile) in_ = iolist[1].split(';') @@ -25,9 +24,8 @@ def splitsubgraph_ios(iofile): type = iolist[0].split('subgraph')[0] return in_, out_, type - def split_onnx_ios(instrfile, - input_path='net/generation_model_simplify.onnx', + input_path='./resnet-test.onnx', out_folder='subgraphs/'): if not os.path.exists(input_path): print(input_path + " not exist") @@ -63,6 +61,5 @@ def split_onnx_ios(instrfile, count = count + 1 f1.close() - if __name__ == "__main__": split_onnx_ios('./scripts/subgraphs_ios.txt', './resnet-test.onnx')