Skip to content

Commit be65550

Browse files
SemyonBevzukRunningLeonhaofanwangVVssssskgrimoire
authored andcommitted
[Enhancement] Additional arguments support for OpenVINO Model Optimizer (#178)
* Add mo args. * [Docs]: update docs and argument descriptions (#196) * bump version to v0.4.0 * update docs and argument descriptions * revert version change * fix unnecessary change of config for dynamic exportation (#199) * fix mmcls get classes (#215) * fix mmcls get classes * resolve comment * resolve comment * Add ModelOptimizerOptions. * Fix merge bugs. * Update mmpose.md (#224) * [Dostring]add example in apis docstring (#214) * add example in apis docstring * add backend example in docstring * rm blank line * Fixed get_mo_options_from_cfg args * fix l2norm test Co-authored-by: RunningLeon <[email protected]> Co-authored-by: Haofan Wang <[email protected]> Co-authored-by: VVsssssk <[email protected]> Co-authored-by: grimoire <[email protected]>
1 parent f303da3 commit be65550

File tree

9 files changed

+136
-14
lines changed

9 files changed

+136
-14
lines changed

docs/en/backends/openvino.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,28 @@ Notes:
6363
the RoiAlign operation is replaced with the [ExperimentalDetectronROIFeatureExtractor](https://docs.openvinotoolkit.org/latest/openvino_docs_ops_detection_ExperimentalDetectronROIFeatureExtractor_6.html) operation in the ONNX graph.
6464
- Models "VFNet" and "Faster R-CNN + DCN" use the custom "DeformableConv2D" operation.
6565

66+
### Deployment config
67+
68+
With the deployment config, you can specify additional options for the Model Optimizer.
69+
To do this, add the necessary parameters to the `backend_config.mo_options` in the fields `args` (for parameters with values) and `flags` (for flags).
70+
71+
Example:
72+
```python
73+
backend_config = dict(
74+
mo_options=dict(
75+
args=dict({
76+
'--mean_values': [0, 0, 0],
77+
'--scale_values': [255, 255, 255],
78+
'--data_type': 'FP32',
79+
}),
80+
flags=['--disable_fusing'],
81+
)
82+
)
83+
```
84+
85+
Information about the possible parameters for the Model Optimizer can be found in the [documentation](https://docs.openvino.ai/latest/openvino_docs_MO_DG_prepare_model_convert_model_Converting_Model.html).
86+
87+
6688
### FAQs
6789

6890
- None

mmdeploy/apis/openvino/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
if is_available():
77
from mmdeploy.backend.openvino.onnx2openvino import (get_output_model_file,
88
onnx2openvino)
9-
from .utils import get_input_info_from_cfg
9+
from .utils import get_input_info_from_cfg, get_mo_options_from_cfg
1010
__all__ += [
11-
'onnx2openvino', 'get_output_model_file', 'get_input_info_from_cfg'
11+
'onnx2openvino', 'get_output_model_file', 'get_input_info_from_cfg',
12+
'get_mo_options_from_cfg'
1213
]

mmdeploy/apis/openvino/utils.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33

44
import mmcv
55

6+
from mmdeploy.backend.openvino import ModelOptimizerOptions
67
from mmdeploy.utils import get_model_inputs
7-
from mmdeploy.utils.config_utils import get_ir_config
8+
from mmdeploy.utils.config_utils import get_backend_config, get_ir_config
89

910

1011
def update_input_names(input_info: Dict[str, List],
@@ -50,3 +51,19 @@ def get_input_info_from_cfg(deploy_cfg: mmcv.Config) -> Dict[str, List]:
5051
input_info = dict(zip(input_names, input_info))
5152
input_info = update_input_names(input_info, input_names)
5253
return input_info
54+
55+
56+
def get_mo_options_from_cfg(deploy_cfg: mmcv.Config) -> ModelOptimizerOptions:
57+
"""Get additional parameters for the Model Optimizer from the deploy
58+
config.
59+
60+
Args:
61+
deploy_cfg (mmcv.Config): Deployment config.
62+
63+
Returns:
64+
ModelOptimizerOptions: A class that will contain additional arguments.
65+
"""
66+
backend_config = get_backend_config(deploy_cfg)
67+
mo_options = backend_config.get('mo_options', None)
68+
mo_options = ModelOptimizerOptions(mo_options)
69+
return mo_options

mmdeploy/backend/openvino/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,8 @@ def is_available() -> bool:
1313

1414
if is_available():
1515
from .onnx2openvino import get_output_model_file
16+
from .utils import ModelOptimizerOptions
1617
from .wrapper import OpenVINOWrapper
17-
__all__ = ['OpenVINOWrapper', 'get_output_model_file']
18+
__all__ = [
19+
'OpenVINOWrapper', 'get_output_model_file', 'ModelOptimizerOptions'
20+
]

mmdeploy/backend/openvino/onnx2openvino.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
import os.path as osp
33
import subprocess
44
from subprocess import PIPE, CalledProcessError, run
5-
from typing import Dict, List, Union
5+
from typing import Dict, List, Optional, Union
66

77
import mmcv
88
import torch
99

1010
from mmdeploy.utils import get_root_logger
11+
from .utils import ModelOptimizerOptions
1112

1213

1314
def get_mo_command() -> str:
@@ -55,7 +56,10 @@ def get_output_model_file(onnx_path: str, work_dir: str) -> str:
5556

5657

5758
def onnx2openvino(input_info: Dict[str, Union[List[int], torch.Size]],
58-
output_names: List[str], onnx_path: str, work_dir: str):
59+
output_names: List[str],
60+
onnx_path: str,
61+
work_dir: str,
62+
mo_options: Optional[ModelOptimizerOptions] = None):
5963
"""Convert ONNX to OpenVINO.
6064
6165
Examples:
@@ -72,8 +76,9 @@ def onnx2openvino(input_info: Dict[str, Union[List[int], torch.Size]],
7276
output_names (List[str]): Output names. Example: ['dets', 'labels'].
7377
onnx_path (str): The path to the onnx model.
7478
work_dir (str): The path to the directory for saving the results.
79+
mo_options (None | ModelOptimizerOptions): The class with
80+
additional arguments for the Model Optimizer.
7581
"""
76-
7782
input_names = ','.join(input_info.keys())
7883
input_shapes = ','.join(str(list(elem)) for elem in input_info.values())
7984
output = ','.join(output_names)
@@ -88,8 +93,10 @@ def onnx2openvino(input_info: Dict[str, Union[List[int], torch.Size]],
8893
f'--output_dir="{work_dir}" ' \
8994
f'--output="{output}" ' \
9095
f'--input="{input_names}" ' \
91-
f'--input_shape="{input_shapes}" ' \
92-
f'--disable_fusing '
96+
f'--input_shape="{input_shapes}" '
97+
if mo_options is not None:
98+
mo_args += mo_options.get_options()
99+
93100
command = f'{mo_command} {mo_args}'
94101

95102
logger = get_root_logger()

mmdeploy/backend/openvino/utils.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Copyright (c) OpenMMLab. All rights reserved.
2+
from typing import Dict, List, Optional, Union
3+
4+
5+
class ModelOptimizerOptions:
6+
"""A class to make it easier to support additional arguments for the Model
7+
Optimizer that can be passed through the deployment configuration.
8+
9+
Example:
10+
>>> deploy_cfg = load_config(deploy_cfg_path)
11+
>>> mo_options = deploy_cfg.get('mo_options', None)
12+
>>> mo_options = ModelOptimizerOptions(mo_options)
13+
>>> mo_args = mo_options.get_options()
14+
"""
15+
16+
def __init__(self,
17+
mo_options: Optional[Dict[str, Union[Dict, List]]] = None):
18+
self.args = ''
19+
self.flags = ''
20+
if mo_options is not None:
21+
self.args = self.__parse_args(mo_options)
22+
self.flags = self.__parse_flags(mo_options)
23+
24+
def __parse_args(self, mo_options: Dict[str, Union[Dict, List]]) -> str:
25+
"""Parses a dictionary with arguments into a string."""
26+
mo_args_str = ''
27+
if 'args' in mo_options:
28+
for key, value in mo_options['args'].items():
29+
value_str = f'"{value}"' if isinstance(value, list) else value
30+
mo_args_str += f'{key}={value_str} '
31+
return mo_args_str
32+
33+
def __parse_flags(self, mo_options: Dict[str, Union[Dict, List]]) -> str:
34+
"""Parses a list with flags into a string."""
35+
mo_flags_str = ''
36+
if 'flags' in mo_options:
37+
mo_flags_str += ' '.join(mo_options['flags'])
38+
return mo_flags_str
39+
40+
def get_options(self) -> str:
41+
"""Returns a string with additional arguments for the Model Optimizer.
42+
43+
If there are no additional arguments, it will return an empty string.
44+
"""
45+
return self.args + self.flags

mmdeploy/utils/test.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,15 +487,17 @@ def get_backend_outputs(ir_file_path: str,
487487
import mmdeploy.apis.openvino as openvino_apis
488488
if not openvino_apis.is_available():
489489
return None
490+
from mmdeploy.apis.openvino import get_mo_options_from_cfg
490491
openvino_work_dir = tempfile.TemporaryDirectory().name
491492
openvino_file_path = openvino_apis.get_output_model_file(
492493
ir_file_path, openvino_work_dir)
493494
input_info = {
494495
name: value.shape
495496
for name, value in flatten_model_inputs.items()
496497
}
498+
mo_options = get_mo_options_from_cfg(deploy_cfg)
497499
openvino_apis.onnx2openvino(input_info, output_names, ir_file_path,
498-
openvino_work_dir)
500+
openvino_work_dir, mo_options)
499501
backend_files = [openvino_file_path]
500502
backend_feats = flatten_model_inputs
501503
device = 'cpu'

tests/test_apis/test_onnx2openvino.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,28 @@ def get_outputs(pytorch_model, openvino_model_path, input, input_name,
6060
return output_pytorch, openvino_output
6161

6262

63+
def get_base_deploy_cfg():
64+
deploy_cfg = mmcv.Config(dict(backend_config=dict(type='openvino')))
65+
return deploy_cfg
66+
67+
68+
def get_deploy_cfg_with_mo_args():
69+
deploy_cfg = mmcv.Config(
70+
dict(
71+
backend_config=dict(
72+
type='openvino',
73+
mo_options=dict(
74+
args={'--data_type': 'FP32'}, flags=['--disable_fusing'
75+
]))))
76+
return deploy_cfg
77+
78+
79+
@pytest.mark.parametrize('get_deploy_cfg',
80+
[get_base_deploy_cfg, get_deploy_cfg_with_mo_args])
6381
@backend_checker(Backend.OPENVINO)
64-
def test_onnx2openvino():
65-
from mmdeploy.apis.openvino import get_output_model_file, onnx2openvino
82+
def test_onnx2openvino(get_deploy_cfg):
83+
from mmdeploy.apis.openvino import (get_mo_options_from_cfg,
84+
get_output_model_file, onnx2openvino)
6685
pytorch_model = TestModel().eval()
6786
export_img = torch.rand([1, 3, 8, 8])
6887
onnx_file = tempfile.NamedTemporaryFile(suffix='.onnx').name
@@ -74,7 +93,10 @@ def test_onnx2openvino():
7493
input_info = {input_name: export_img.shape}
7594
output_names = [output_name]
7695
openvino_dir = tempfile.TemporaryDirectory().name
77-
onnx2openvino(input_info, output_names, onnx_file, openvino_dir)
96+
deploy_cfg = get_deploy_cfg()
97+
mo_options = get_mo_options_from_cfg(deploy_cfg)
98+
onnx2openvino(input_info, output_names, onnx_file, openvino_dir,
99+
mo_options)
78100
openvino_model_path = get_output_model_file(onnx_file, openvino_dir)
79101
assert osp.exists(openvino_model_path), \
80102
'The file (.xml) for OpenVINO IR has not been created.'

tools/deploy.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,17 +222,20 @@ def main():
222222
'OpenVINO is not available, please install OpenVINO first.'
223223

224224
from mmdeploy.apis.openvino import (get_input_info_from_cfg,
225+
get_mo_options_from_cfg,
225226
get_output_model_file,
226227
onnx2openvino)
227228
openvino_files = []
228229
for onnx_path in ir_files:
229230
model_xml_path = get_output_model_file(onnx_path, args.work_dir)
230231
input_info = get_input_info_from_cfg(deploy_cfg)
231232
output_names = get_ir_config(deploy_cfg).output_names
233+
mo_options = get_mo_options_from_cfg(deploy_cfg)
232234
create_process(
233235
f'onnx2openvino with {onnx_path}',
234236
target=onnx2openvino,
235-
args=(input_info, output_names, onnx_path, args.work_dir),
237+
args=(input_info, output_names, onnx_path, args.work_dir,
238+
mo_options),
236239
kwargs=dict(),
237240
ret_value=ret_value)
238241
openvino_files.append(model_xml_path)

0 commit comments

Comments
 (0)