Skip to content

Commit

Permalink
Add automatic model conversion to onnx, ncnn and ave-tracker bundle (i…
Browse files Browse the repository at this point in the history
…sarandi#43)

This PR brings the functionality for model conversion inspired by the avelab model conversion pipeline used in face tracking.

The converter takes as input the model folder with pb files and variable folder from a training and converts it into several onnx files. If ave-tracker path is given then the models are converted into ncnn files (optimized and binarized), a bundle file to be used in ave-tracker containing a settings.json and the ncnn file is also generated. The settings.json file is automatically created. Furthermore a info.txt file is created with md5 checksum of the relevant files used as inputs.
  • Loading branch information
inakinavarro authored and GitHub Enterprise committed Aug 31, 2023
1 parent 8578142 commit d12e02c
Show file tree
Hide file tree
Showing 4 changed files with 1,048 additions and 16 deletions.
42 changes: 26 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,32 @@ You can incorporate 3D datasets by following these steps:
2. Include the offline data processing function within the `data/sway.py` file.
3. To evaluate models using the new data, develop the evaluation script within the `eval_scripts/eval_sway.py` file.

6. TF Model conversion to ONNX and NCNN
1. Convert TF model to ONNX model
`PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python python3 -m tf2onnx.convert --saved-model model_path --output output_path --opset 15`
example: `PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python python3 -m tf2onnx.convert --saved-model ./runs/metrabs-exp/sway_ncnn/256in_ms_w1_up_pv05_abs0_scratch_2d/model/ --output ./output/256in_ms_w1_up_pv05_abs0_scratch_2d.onnx --opset 15`

2. Dynamic input to fixed input
`python3 -m onnxruntime.tools.make_dynamic_shape_fixed input_onnx_path output_onnx_path --input_name input_2 --input_shape N,C,H,W`
example: `python3 -m onnxruntime.tools.make_dynamic_shape_fixed output/256in_ms_w1_up_pv05_abs0_scratch_2d.onnx 256in_ms_w1_up_pv05_abs0_scratch_2d.onnx --input_name input_2 --input_shape 1,3,256,256`

3. Simplify ONNX model
https://convertmodel.com/#input=onnx&output=onnx
Visit this link and choose the input format :onnx , and the out format: onnx. Check all the options and click the convert button. You can download simplified onnx model.

4. Convert simplified ONNX model to NCNN model
https://convertmodel.com/#input=onnx&output=onnx
Choose output format : ncnn, and the input format : onnx. Uncheck all the options and click the convert button. You can download bin and param files.
6. TF Model conversion to ONNX and NCNN, and bundle for loom-sdk
You can convert from a TF model with a single command all the way to bundled NCNN:
```
python tools/metrabs_converter.py \
--output-models-folder ~/git/ave-models/body/ \
--version 2 1 1 4 \
--model-path ~/Downloads/160in_ms_w1_up_pv05_abs0_scratch/model \
--model-kind Metrabs \
--ave-tracker-path /Users/inavarro/git/ave-tracker/build/client/release \
--keep-intermediate-files \
--input-resolution-hw 160 160 \
--model-input-name input_2
```
This requires having ave-tracker tools installed in your system. You can install ave-tracker tools following the README in https://github.rbx.com/GameEngine/ave-tracker
In case you would like to convert just to ONNX you can do it without ave-tracker with the following command (avoiding the `--ave-tracker-path` argument):
```
python tools/metrabs_converter.py \
--output-models-folder ~/git/ave-models/body/ \
--version 2 1 1 4 \
--model-path ~/Downloads/160in_ms_w1_up_pv05_abs0_scratch/model \
--model-kind Metrabs \
--keep-intermediate-files \
--input-resolution-hw 160 160 \
--model-input-name input_2
```



# MeTRAbs Absolute 3D Human Pose Estimator
Expand Down
141 changes: 141 additions & 0 deletions tools/metrabs_converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
"""metrabs_converter
====================
Converts a metrabs model for use in ave-tracker.
example command:
python tools/metrabs_converter.py \
--output-models-folder ~/git/ave-models/body/ \
--version 2 1 1 4 \
--model-path ~/Downloads/160in_ms_w1_up_pv05_abs0_scratch/model \
--model-kind Metrabs \
--ave-tracker-path /Users/inavarro/git/ave-tracker/build/client/release \
--keep-intermediate-files \
--input-resolution-hw 160 160 \
--model-input-name input_2
This has been tested with tensorflow=2.11.0, onnx=1.12.0, tf2onnx=1.14.0/8f8d49, and onnxsim==0.4.13
Note that other onnxsim version has given problems.
"""

from pathlib import Path
from enum import Enum
from model_converter import (
ModelConverter,
get_general_model_converter_parser,
)


# Metrabs model kind enum to identify which kind of model is being converted
MetrabsModelKind = Enum("MetrabsModelKind", "Metrabs")


def parse_arguments():
"""
Parse command line arguments and provide help.
"""

parser = get_general_model_converter_parser("Metrabs")
parser.add_argument(
"--model-kind",
type=str,
required=True,
choices=[i.name for i in MetrabsModelKind],
help="Kind of Metrabs model to be converted.",
)
args = parser.parse_args()

return args


class MetrabsModelConverter(ModelConverter):
def __init__(
self,
version,
version_schema,
out_models_folder,
model_dir,
input_blob_name,
input_resolution_h_w,
ave_tracker_path,
optimize,
fp16,
model_kind,
binarize_params,
comment=None,
keep_intermediate_files=False,
):
super().__init__(
version,
version_schema,
out_models_folder,
model_dir,
input_blob_name,
input_resolution_h_w,
ave_tracker_path,
optimize,
fp16,
keep_intermediate_files,
binarize_params=binarize_params,
aes_encrypt=True, # all metrabs models should be aes encrypted
)
self.model_kind = model_kind

self.ncnn_file_name = "metrabs"
self.onnx_file_name = "metrabs"
self.bundle_name = "bodypose_bundle.deploy"
self.native_model_kind = "Bodypose"

self.conversion_from_pb = True
self.raw_folder = str(Path(self.conversion_out_folder) / "raw")

self.comment = " ".join(comment) if comment is not None else None

def generate_blob_mapping_settings(self):
"""generates minimal settings dict with blob mappings which is used for models with binarized param"""

blobs_map = self.parse_ncnn_header_map()

# some of the settings hardcoded now should be read from onnx
effective_stride = 32
settings = {
"kInputSize": f"{self.input_model_width}",
"kOutHW": f"{round(self.input_model_width/effective_stride)}",
"kOutC": "72",
"kNKeypoints": "8",
"kNJoints": "8",
"kInputLayer": f"{blobs_map[self.input_blob_name]}",
"kOutputLayer": f"{blobs_map['output_1']}",
}
return settings


def main():
# parse cmd line arguments
args = parse_arguments()

# create ModelConverter object
model_converter = MetrabsModelConverter(
version=args.version,
version_schema=args.version_schema,
out_models_folder=args.output_models_folder,
model_dir=args.model_path,
input_blob_name=args.model_input_name,
input_resolution_h_w=args.input_resolution_hw,
ave_tracker_path=args.ave_tracker_path,
optimize=not args.unoptimized_ncnn,
fp16=args.fp16,
model_kind=MetrabsModelKind[args.model_kind],
binarize_params=not args.string_params,
comment=args.comment,
keep_intermediate_files=args.keep_intermediate_files,
)

# convert Model
model_converter.convert()


if __name__ == "__main__":
main()
Loading

0 comments on commit d12e02c

Please sign in to comment.