Skip to content

Commit 9be6b62

Browse files
authored
Multi-model and Quick Search Config Checking (#540)
* Initial refactor * Fixing type checking error * Checking for illegal combinations. CLI unit test is failing * Patching CLI unit test * Updating copyright date * Updates based on Tim's review comments * Adding check that quick passes * Added test to check for model specific parameters * Checking profile_models for empty condition * Fixing return condition in _check_no_per_model_list_values * Adding check for model config parameters * Making it an error to disable run config from quick search
1 parent 7b2dae6 commit 9be6b62

File tree

3 files changed

+294
-16
lines changed

3 files changed

+294
-16
lines changed

model_analyzer/config/input/config_command.py

Lines changed: 159 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
1+
# Copyright (c) 2021-22, NVIDIA CORPORATION. All rights reserved.
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -12,10 +12,11 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from typing import Dict, List
15+
from typing import Dict, List, Optional, Any
1616
from model_analyzer.model_analyzer_exceptions \
1717
import TritonModelAnalyzerException
1818
import yaml
19+
from argparse import Namespace
1920
from .yaml_config_validator import YamlConfigValidator
2021

2122
from copy import deepcopy
@@ -76,7 +77,7 @@ def _load_config_file(self, file_path):
7677
config = yaml.safe_load(config_file)
7778
return config
7879

79-
def set_config_values(self, args):
80+
def set_config_values(self, args: Namespace) -> None:
8081
"""
8182
Set the config values. This function sets all the values for the
8283
config. CLI arguments have the highest priority, then YAML config
@@ -94,41 +95,183 @@ def set_config_values(self, args):
9495
this exception
9596
"""
9697

97-
# Config file has been specified
98+
yaml_config = self._load_yaml_config(args)
99+
self._check_for_illegal_config_settings(args, yaml_config)
100+
self._set_field_values(args, yaml_config)
101+
self._preprocess_and_verify_arguments()
102+
self._autofill_values()
103+
104+
def _load_yaml_config(self, args: Namespace) -> Optional[Dict[str, List]]:
98105
if 'config_file' in args:
99106
yaml_config = self._load_config_file(args.config_file)
100107
YamlConfigValidator.validate(yaml_config)
101108
else:
102109
yaml_config = None
103110

111+
return yaml_config
112+
113+
def _check_for_illegal_config_settings(
114+
self, args: Namespace, yaml_config: Optional[Dict[str,
115+
List]]) -> None:
116+
self._check_for_duplicate_profile_models_option(args, yaml_config)
117+
self._check_for_multi_model_incompatability(args, yaml_config)
118+
self._check_for_quick_search_incompatability(args, yaml_config)
119+
120+
def _set_field_values(self, args: Namespace,
121+
yaml_config: Optional[Dict[str, List]]) -> None:
104122
for key, value in self._fields.items():
105123
self._fields[key].set_name(key)
106-
if key in args:
107-
self._check_for_duplicate_profile_models_option(
108-
yaml_config, key)
109-
self._fields[key].set_value(getattr(args, key))
110-
elif yaml_config is not None and key in yaml_config:
111-
self._fields[key].set_value(yaml_config[key])
124+
config_value = self._get_config_value(key, args, yaml_config)
125+
126+
if config_value:
127+
self._fields[key].set_value(config_value)
112128
elif value.default_value() is not None:
113129
self._fields[key].set_value(value.default_value())
114130
elif value.required():
115131
flags = ', '.join(value.flags())
116132
raise TritonModelAnalyzerException(
117133
f'Config for {value.name()} is not specified. You need to specify it using the YAML config file or using the {flags} flags in CLI.'
118134
)
119-
self._preprocess_and_verify_arguments()
120-
self._autofill_values()
121135

122-
def _check_for_duplicate_profile_models_option(self,
123-
yaml_config: Dict[str, List],
124-
key: str) -> None:
125-
if yaml_config is not None and key in yaml_config and key == 'profile_models':
136+
def _get_config_value(
137+
self, key: str, args: Namespace,
138+
yaml_config: Optional[Dict[str, List]]) -> Optional[Any]:
139+
if key in args:
140+
return getattr(args, key)
141+
elif yaml_config is not None and key in yaml_config:
142+
return yaml_config[key]
143+
else:
144+
return None
145+
146+
def _check_for_duplicate_profile_models_option(
147+
self, args: Namespace, yaml_config: Optional[Dict[str,
148+
List]]) -> None:
149+
key_in_args = 'profile_models' in args
150+
key_in_yaml = yaml_config is not None and 'profile_models' in yaml_config
151+
152+
if key_in_args and key_in_yaml:
126153
raise TritonModelAnalyzerException(
127154
f'\n The profile model option is specified on both '
128155
'the CLI (--profile-models) and in the YAML config file.'
129156
'\n Please remove the option from one of the locations and try again'
130157
)
131158

159+
def _check_for_multi_model_incompatability(
160+
self, args: Namespace, yaml_config: Optional[Dict[str,
161+
List]]) -> None:
162+
if not self._get_config_value(
163+
'run_config_profile_models_concurrently_enable', args,
164+
yaml_config):
165+
return
166+
167+
self._check_multi_model_search_mode_incompatability(args, yaml_config)
168+
169+
def _check_multi_model_search_mode_incompatability(
170+
self, args: Namespace, yaml_config: Optional[Dict[str,
171+
List]]) -> None:
172+
if self._get_config_value('run_config_search_mode', args,
173+
yaml_config) != 'quick':
174+
raise TritonModelAnalyzerException(
175+
f'\nConcurrent profiling of models is only supported in quick search mode.'
176+
'\nPlease use quick search mode or disable concurrent model profiling.'
177+
)
178+
179+
def _check_for_quick_search_incompatability(
180+
self, args: Namespace, yaml_config: Optional[Dict[str,
181+
List]]) -> None:
182+
if self._get_config_value('run_config_search_mode', args,
183+
yaml_config) != 'quick':
184+
return
185+
186+
self._check_no_search_disable(args, yaml_config)
187+
self._check_no_search_values(args, yaml_config)
188+
self._check_no_global_list_values(args, yaml_config)
189+
self._check_no_per_model_list_values(args, yaml_config)
190+
191+
def _check_no_search_disable(
192+
self, args: Namespace, yaml_config: Optional[Dict[str,
193+
List]]) -> None:
194+
if self._get_config_value('run_config_search_disable', args,
195+
yaml_config):
196+
raise TritonModelAnalyzerException(
197+
f'\nDisabling of run config search is not supported in quick search mode.'
198+
'\nPlease use brute search mode or remove --run-config-search-disable.'
199+
)
200+
201+
def _check_no_search_values(self, args: Namespace,
202+
yaml_config: Optional[Dict[str, List]]) -> None:
203+
max_concurrency = self._get_config_value(
204+
'run_config_search_max_concurrency', args, yaml_config)
205+
min_concurrency = self._get_config_value(
206+
'run_config_search_min_concurrency', args, yaml_config)
207+
max_instance = self._get_config_value(
208+
'run_config_search_max_instance_count', args, yaml_config)
209+
min_instance = self._get_config_value(
210+
'run_config_search_min_instance_count', args, yaml_config)
211+
max_batch_size = self._get_config_value(
212+
'run_config_search_max_model_batch_size', args, yaml_config)
213+
min_batch_size = self._get_config_value(
214+
'run_config_search_min_model_batch_size', args, yaml_config)
215+
216+
if max_concurrency or min_concurrency:
217+
raise TritonModelAnalyzerException(
218+
f'\nProfiling of models in quick search mode is not supported with min/max concurrency search values.'
219+
'\nPlease use brute search mode or remove concurrency search values.'
220+
)
221+
if max_instance or min_instance:
222+
raise TritonModelAnalyzerException(
223+
f'\nProfiling of models in quick search mode is not supported with min/max instance search values.'
224+
'\nPlease use brute search mode or remove instance search values.'
225+
)
226+
if max_batch_size or min_batch_size:
227+
raise TritonModelAnalyzerException(
228+
f'\nProfiling of models in quick search mode is not supported with min/max batch size search values.'
229+
'\nPlease use brute search mode or remove batch size search values.'
230+
)
231+
232+
def _check_no_global_list_values(
233+
self, args: Namespace, yaml_config: Optional[Dict[str,
234+
List]]) -> None:
235+
concurrency = self._get_config_value('concurrency', args, yaml_config)
236+
batch_sizes = self._get_config_value('batch_sizes', args, yaml_config)
237+
238+
if concurrency or batch_sizes:
239+
raise TritonModelAnalyzerException(
240+
f'\nProfiling of models in quick search mode is not supported with lists of concurrencies or batch sizes.'
241+
'\nPlease use brute search mode or remove concurrency/batch sizes list.'
242+
)
243+
244+
def _check_no_per_model_list_values(
245+
self, args: Namespace, yaml_config: Optional[Dict[str,
246+
List]]) -> None:
247+
profile_models = self._get_config_value('profile_models', args,
248+
yaml_config)
249+
250+
if not profile_models or type(profile_models) is str or type(
251+
profile_models) is list:
252+
return
253+
254+
for model in profile_models.values():
255+
if not 'parameters' in model:
256+
continue
257+
258+
if 'concurrency' in model['parameters'] or 'batch size' in model[
259+
'parameters']:
260+
raise TritonModelAnalyzerException(
261+
f'\nProfiling of models in quick search mode is not supported with lists of concurrencies or batch sizes.'
262+
'\nPlease use brute search mode or remove concurrency/batch sizes list.'
263+
)
264+
265+
for model in profile_models.values():
266+
if not 'model_config_parameters' in model:
267+
continue
268+
269+
if 'max_batch_size' in model['model_config_parameters']:
270+
raise TritonModelAnalyzerException(
271+
f'\nProfiling of models in quick search mode is not supported with lists max batch sizes.'
272+
'\nPlease use brute search mode or remov max batch size list.'
273+
)
274+
132275
def _preprocess_and_verify_arguments(self):
133276
"""
134277
Enforces some rules on the config.

tests/test_cli.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,9 @@ def test_basic_cli_config_profile_options(self):
367367
@patch(
368368
'model_analyzer.config.input.config_command_profile.ConfigCommandProfile._load_config_file',
369369
MagicMock())
370+
@patch(
371+
'model_analyzer.config.input.config_command.ConfigCommand._check_for_illegal_config_settings',
372+
MagicMock())
370373
def test_all_options(self):
371374

372375
options = get_test_options()

tests/test_config.py

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
from .mocks.mock_numba import MockNumba
1919
from .mocks.mock_os import MockOSMethods
2020

21+
from typing import Dict, List, Optional
22+
from argparse import Namespace
23+
2124
from .common import test_result_collector as trc
2225

2326
from model_analyzer.model_analyzer_exceptions \
@@ -1755,6 +1758,135 @@ def test_copy(self):
17551758
self.assertNotEqual(configA.run_config_search_mode,
17561759
configB.run_config_search_mode)
17571760

1761+
def test_multi_model_search_mode(self):
1762+
"""
1763+
Test that multi-model is only run in quick
1764+
"""
1765+
args = [
1766+
'model-analzyer', 'profile', '--model-repository', 'cli-repository',
1767+
'--profile-models', 'test_modelA,test_modelB',
1768+
'--run-config-profile-models-concurrently-enable'
1769+
]
1770+
1771+
yaml_content = ''
1772+
1773+
# Tests the case where no search mode is specified (default is brute)
1774+
with self.assertRaises(TritonModelAnalyzerException):
1775+
self._evaluate_config(args, yaml_content, subcommand='profile')
1776+
1777+
# Brute should fail
1778+
new_args = deepcopy(args)
1779+
new_args.append('--run-config-search-mode')
1780+
new_args.append('brute')
1781+
1782+
with self.assertRaises(TritonModelAnalyzerException):
1783+
self._evaluate_config(new_args, yaml_content, subcommand='profile')
1784+
1785+
# Quick should pass
1786+
new_args = deepcopy(args)
1787+
new_args.append('--run-config-search-mode')
1788+
new_args.append('quick')
1789+
1790+
self._evaluate_config(new_args, yaml_content, subcommand='profile')
1791+
1792+
def test_quick_search_mode(self):
1793+
"""
1794+
Test that only legal options are specified in quick search
1795+
"""
1796+
args = [
1797+
'model-analzyer', 'profile', '--model-repository', 'cli-repository',
1798+
'--profile-models', 'test_modelA', '--run-config-search-mode',
1799+
'quick'
1800+
]
1801+
1802+
yaml_content = ''
1803+
1804+
self._evaluate_config(args, yaml_content)
1805+
1806+
self._test_quick_search_with_rcs(args,
1807+
yaml_content,
1808+
'--run-config-search-disable',
1809+
use_value=False,
1810+
use_list=False)
1811+
self._test_quick_search_with_rcs(args, yaml_content,
1812+
'--run-config-search-min-concurrency')
1813+
self._test_quick_search_with_rcs(args, yaml_content,
1814+
'--run-config-search-max-concurrency')
1815+
self._test_quick_search_with_rcs(
1816+
args, yaml_content, '--run-config-search-min-instance-count')
1817+
self._test_quick_search_with_rcs(
1818+
args, yaml_content, '--run-config-search-max-instance-count')
1819+
self._test_quick_search_with_rcs(
1820+
args, yaml_content, '--run-config-search-min-model-batch-size')
1821+
self._test_quick_search_with_rcs(
1822+
args, yaml_content, '--run-config-search-max-model-batch-size')
1823+
self._test_quick_search_with_rcs(args,
1824+
yaml_content,
1825+
'--batch-sizes',
1826+
use_value=False)
1827+
self._test_quick_search_with_rcs(args,
1828+
yaml_content,
1829+
'--concurrency',
1830+
use_value=False)
1831+
1832+
def test_quick_search_model_specific(self):
1833+
"""
1834+
Test for illegal model specific options in the YAML during quick search
1835+
"""
1836+
args = [
1837+
'model-analzyer', 'profile', '--model-repository', 'cli-repository',
1838+
'--run-config-search-mode', 'quick', '-f', 'path-to-config-file'
1839+
]
1840+
1841+
yaml_content = """
1842+
profile_models:
1843+
model_1:
1844+
parameters:
1845+
concurrency: 1,2,4,128
1846+
"""
1847+
1848+
with self.assertRaises(TritonModelAnalyzerException):
1849+
self._evaluate_config(args, yaml_content, subcommand='profile')
1850+
1851+
yaml_content = """
1852+
profile_models:
1853+
model_1:
1854+
parameters:
1855+
batch size: 1,2,4,128
1856+
"""
1857+
1858+
with self.assertRaises(TritonModelAnalyzerException):
1859+
self._evaluate_config(args, yaml_content, subcommand='profile')
1860+
1861+
yaml_content = """
1862+
profile_models:
1863+
model_1:
1864+
model_config_parameters:
1865+
max batch size: 2
1866+
"""
1867+
1868+
with self.assertRaises(TritonModelAnalyzerException):
1869+
self._evaluate_config(args, yaml_content, subcommand='profile')
1870+
1871+
def _test_quick_search_with_rcs(self,
1872+
args: Namespace,
1873+
yaml_content: Optional[Dict[str, List]],
1874+
rcs_string: str,
1875+
use_value: bool = True,
1876+
use_list: bool = True) -> None:
1877+
"""
1878+
Tests that run-config-search options raise exceptions
1879+
in quick search mode
1880+
"""
1881+
new_args = deepcopy(args)
1882+
new_args.append(rcs_string)
1883+
if use_value:
1884+
new_args.append('1')
1885+
elif use_list:
1886+
new_args.append(['1', '2', '4'])
1887+
with self.assertRaises(TritonModelAnalyzerException):
1888+
self._evaluate_config(new_args, yaml_content, subcommand='profile')
1889+
17581890

17591891
if __name__ == '__main__':
17601892
unittest.main()

0 commit comments

Comments
 (0)