Skip to content

Commit 35bca92

Browse files
authored
Adding concurrency sweep after quick search completes (#508)
* Parity with quick run * Concurrency sweep working. Need to refactor * Refactored get_configs() * Refactored * Added flag to brute RCG to skip default config generation * Fixed unit tests and added default skip to quick + concurrency sweep * Removing type * Adding newline * Adding config return to methods * Adding custom __setattr__ to config command * Setting attr correctly in _set_search_mode * Setting value correctly in config command * Using user specified num of top configs * Adding TODO with story * Fixes based on review comments * Fixing type checking issues
1 parent 5054c7a commit 35bca92

10 files changed

+251
-40
lines changed

model_analyzer/config/generate/brute_run_config_generator.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,28 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
from typing import List, Optional
16+
1517
from .config_generator_interface import ConfigGeneratorInterface
1618
from model_analyzer.config.run.run_config import RunConfig
1719
from model_analyzer.model_analyzer_exceptions import TritonModelAnalyzerException
1820
from model_analyzer.config.generate.model_run_config_generator import ModelRunConfigGenerator
1921
from model_analyzer.config.generate.model_variant_name_manager import ModelVariantNameManager
22+
from model_analyzer.result.run_config_measurement import RunConfigMeasurement
2023

2124

2225
class BruteRunConfigGenerator(ConfigGeneratorInterface):
2326
"""
2427
Generates all RunConfigs to execute via brute force given a list of models
2528
"""
2629

27-
def __init__(self, config, gpus, models, client,
28-
model_variant_name_manager):
30+
def __init__(self,
31+
config,
32+
gpus,
33+
models,
34+
client,
35+
model_variant_name_manager,
36+
skip_default_config: bool = False):
2937
"""
3038
Parameters
3139
----------
@@ -39,6 +47,8 @@ def __init__(self, config, gpus, models, client,
3947
client: TritonClient
4048
4149
model_variant_name_manager: ModelVariantNameManager
50+
51+
skip_default_config: bool
4252
"""
4353
self._config = config
4454
self._gpus = gpus
@@ -52,9 +62,11 @@ def __init__(self, config, gpus, models, client,
5262
self._num_models = len(models)
5363

5464
self._curr_model_run_configs = [None for n in range(self._num_models)]
55-
self._curr_results = [[] for n in range(self._num_models)]
65+
self._curr_results: List = [[] for n in range(self._num_models)]
5666
self._curr_generators = [None for n in range(self._num_models)]
5767

68+
self._skip_default_config = skip_default_config
69+
5870
def set_last_results(self, measurements):
5971
for index in range(self._num_models):
6072
self._curr_results[index].extend(measurements)
@@ -70,7 +82,9 @@ def get_configs(self):
7082
yield from self._get_next_config()
7183

7284
def _get_next_config(self):
73-
yield from self._generate_subset(0, default_only=True)
85+
if not self._skip_default_config:
86+
yield from self._generate_subset(0, default_only=True)
87+
7488
if self._should_generate_non_default_configs():
7589
yield from self._generate_subset(0, default_only=False)
7690

model_analyzer/config/generate/model_variant_name_manager.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@ def get_model_variant_name(self, model_name: str, model_config_dict: Dict,
5555

5656
variant_found, model_variant_name = self._find_existing_variant(mcd)
5757

58-
if variant_found:
59-
return (True, model_variant_name)
60-
6158
if self._is_default_config(param_combo):
6259
return (False, model_name + '_config_default')
6360

61+
if variant_found:
62+
return (True, model_variant_name)
63+
6464
model_variant_name = self._create_new_model_variant(model_name, mcd)
6565

6666
return (False, model_variant_name)
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from typing import Dict, List, Union, Optional, Generator
16+
17+
from .config_generator_interface import ConfigGeneratorInterface
18+
19+
from model_analyzer.config.generate.base_model_config_generator import BaseModelConfigGenerator
20+
from model_analyzer.config.generate.search_config import SearchConfig
21+
from model_analyzer.config.generate.coordinate import Coordinate
22+
from model_analyzer.config.generate.coordinate_data import CoordinateData
23+
from model_analyzer.config.generate.neighborhood import Neighborhood
24+
from model_analyzer.config.generate.brute_run_config_generator import BruteRunConfigGenerator
25+
from model_analyzer.config.generate.quick_run_config_generator import QuickRunConfigGenerator
26+
from model_analyzer.config.generate.model_variant_name_manager import ModelVariantNameManager
27+
from model_analyzer.config.run.model_run_config import ModelRunConfig
28+
from model_analyzer.config.run.run_config import RunConfig
29+
from model_analyzer.perf_analyzer.perf_config import PerfAnalyzerConfig
30+
from model_analyzer.triton.model.model_config import ModelConfig
31+
from model_analyzer.triton.client.client import TritonClient
32+
from model_analyzer.device.gpu_device import GPUDevice
33+
from model_analyzer.config.input.config_command_profile import ConfigCommandProfile
34+
from model_analyzer.config.input.objects.config_model_profile_spec import ConfigModelProfileSpec
35+
from model_analyzer.result.result_manager import ResultManager
36+
from model_analyzer.result.run_config_measurement import RunConfigMeasurement
37+
from model_analyzer.record.metrics_manager import MetricsManager
38+
from model_analyzer.result.results import Results
39+
from model_analyzer.result.run_config_result import RunConfigResult
40+
41+
from model_analyzer.constants import LOGGER_NAME, MAGNITUDE_DECAY_RATE
42+
from model_analyzer.config.input.config_defaults import DEFAULT_NUM_CONFIGS_PER_MODEL, \
43+
DEFAULT_RUN_CONFIG_MIN_CONCURRENCY, DEFAULT_RUN_CONFIG_MAX_CONCURRENCY
44+
45+
from copy import deepcopy
46+
47+
import logging
48+
49+
logger = logging.getLogger(LOGGER_NAME)
50+
51+
52+
class QuickPlusConcurrencySweepRunConfigGenerator(ConfigGeneratorInterface):
53+
"""
54+
First run QuickRunConfigGenerator for a hill climbing search, then use
55+
Brute for a concurrency sweep of the default and Top N results
56+
"""
57+
58+
def __init__(self, search_config: SearchConfig,
59+
config: ConfigCommandProfile, gpus: List[GPUDevice],
60+
models: List[ConfigModelProfileSpec], client: TritonClient,
61+
result_manager: ResultManager,
62+
model_variant_name_manager: ModelVariantNameManager):
63+
"""
64+
Parameters
65+
----------
66+
search_config: SearchConfig
67+
Defines parameters and dimensions for the search
68+
config: ConfigCommandProfile
69+
Profile configuration information
70+
gpus: List of GPUDevices
71+
models: List of ConfigModelProfileSpec
72+
List of models to profile
73+
client: TritonClient
74+
result_manager: ResultManager
75+
The object that handles storing and sorting the results from the perf analyzer
76+
model_variant_name_manager: ModelVariantNameManager
77+
Maps model variants to config names
78+
79+
model_variant_name_manager: ModelVariantNameManager
80+
"""
81+
self._search_config = search_config
82+
self._config = config
83+
self._gpus = gpus
84+
self._models = models
85+
self._client = client
86+
self._result_manager = result_manager
87+
self._model_variant_name_manager = model_variant_name_manager
88+
89+
def set_last_results(self,
90+
measurements: List[Optional[RunConfigMeasurement]]):
91+
self._rcg.set_last_results(measurements)
92+
93+
def get_configs(self) -> Generator[RunConfig, None, None]:
94+
"""
95+
Returns
96+
-------
97+
RunConfig
98+
The next RunConfig generated by this class
99+
"""
100+
yield from self._execute_quick_search()
101+
yield from self._sweep_concurrency_over_top_results()
102+
103+
def _execute_quick_search(self):
104+
self._rcg = self._create_quick_run_config_generator()
105+
106+
yield from self._rcg.get_configs()
107+
108+
def _create_quick_run_config_generator(self) -> QuickRunConfigGenerator:
109+
return QuickRunConfigGenerator(
110+
search_config=self._search_config,
111+
config=self._config,
112+
gpus=self._gpus,
113+
models=self._models,
114+
client=self._client,
115+
model_variant_name_manager=self._model_variant_name_manager)
116+
117+
def _sweep_concurrency_over_top_results(self):
118+
top_results = self._result_manager.top_n_results(
119+
n=self._config.num_top_model_configs)
120+
121+
for count, result in enumerate(top_results):
122+
new_config = self._create_new_config_command_profile(result)
123+
self._rcg = self._create_brute_run_config_generator(
124+
new_config, skip_default_config=(count != 0))
125+
126+
yield from self._rcg.get_configs()
127+
128+
def _create_new_config_command_profile(
129+
self, result: RunConfigResult) -> ConfigCommandProfile:
130+
new_config = deepcopy(self._config)
131+
132+
new_config = self._set_search_mode(new_config)
133+
new_config = self._set_parameters(result, new_config)
134+
135+
return new_config
136+
137+
def _create_brute_run_config_generator(
138+
self, new_config: ConfigCommandProfile,
139+
skip_default_config: bool) -> BruteRunConfigGenerator:
140+
return BruteRunConfigGenerator(
141+
config=new_config,
142+
gpus=self._gpus,
143+
models=self._models,
144+
client=self._client,
145+
model_variant_name_manager=self._model_variant_name_manager,
146+
skip_default_config=skip_default_config)
147+
148+
def _set_search_mode(self,
149+
config: ConfigCommandProfile) -> ConfigCommandProfile:
150+
config.run_config_search_mode = 'brute'
151+
config.run_config_search_disable = False
152+
config.early_exit_enable = True
153+
154+
return config
155+
156+
def _set_parameters(self, result: RunConfigResult,
157+
config: ConfigCommandProfile) -> ConfigCommandProfile:
158+
batch_size = self._find_batch_size(result)
159+
config = self._set_batch_size(config, batch_size)
160+
161+
instance_count = self._find_instance_count(result)
162+
config = self._set_instance_count(config, instance_count)
163+
164+
config = self._set_concurrency(config)
165+
166+
return config
167+
168+
# TODO: TMA-879 - This approach isn't going to work for multi-model
169+
# We will need to create a yaml config to set each models
170+
# batch size/instances seperately
171+
def _find_batch_size(self, result: RunConfigResult) -> int:
172+
return result.run_config().model_run_configs()[0].model_config(
173+
).get_config()['max_batch_size']
174+
175+
def _find_instance_count(self, result: RunConfigResult) -> int:
176+
return result.run_config().model_run_configs()[0].model_config(
177+
).get_config()['instance_group'][0]['count']
178+
179+
def _set_batch_size(self, config: ConfigCommandProfile,
180+
batch_size: int) -> ConfigCommandProfile:
181+
config.run_config_search_min_model_batch_size = batch_size
182+
config.run_config_search_max_model_batch_size = batch_size
183+
184+
return config
185+
186+
def _set_instance_count(self, config: ConfigCommandProfile,
187+
instance_count: int) -> ConfigCommandProfile:
188+
config.run_config_search_min_instance_count = instance_count
189+
config.run_config_search_max_instance_count = instance_count
190+
191+
return config
192+
193+
def _set_concurrency(self,
194+
config: ConfigCommandProfile) -> ConfigCommandProfile:
195+
config.run_config_search_min_concurrency = DEFAULT_RUN_CONFIG_MIN_CONCURRENCY
196+
config.run_config_search_max_concurrency = DEFAULT_RUN_CONFIG_MAX_CONCURRENCY
197+
198+
return config

model_analyzer/config/generate/quick_run_config_generator.py

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,9 @@ class QuickRunConfigGenerator(ConfigGeneratorInterface):
4646
Hill climbing algorithm to create RunConfigs
4747
"""
4848

49-
def __init__(self,
50-
search_config: SearchConfig,
51-
config: ConfigCommandProfile,
52-
gpus: List[GPUDevice],
53-
models: List[ConfigModelProfileSpec],
54-
client: TritonClient,
49+
def __init__(self, search_config: SearchConfig,
50+
config: ConfigCommandProfile, gpus: List[GPUDevice],
51+
models: List[ConfigModelProfileSpec], client: TritonClient,
5552
model_variant_name_manager: ModelVariantNameManager):
5653
"""
5754
Parameters
@@ -124,7 +121,8 @@ def _step(self):
124121
Determine self._coordinate_to_measure, which is what is used to
125122
create the next RunConfig
126123
"""
127-
if self._measuring_home_coordinate() and self._get_last_results() is None:
124+
if self._measuring_home_coordinate(
125+
) and self._get_last_results() is None:
128126
self._take_step_back()
129127
elif self._neighborhood.enough_coordinates_initialized():
130128
self._take_step()
@@ -206,8 +204,7 @@ def _take_step_back(self):
206204
coordinate_in=self._best_coordinate)
207205

208206
logger.debug(
209-
f"Stepping back: {self._home_coordinate}->{new_coordinate}"
210-
)
207+
f"Stepping back: {self._home_coordinate}->{new_coordinate}")
211208
self._home_coordinate = new_coordinate
212209
self._coordinate_to_measure = new_coordinate
213210
self._recreate_neighborhood()
@@ -242,8 +239,7 @@ def _get_starting_coordinate(self) -> Coordinate:
242239
min_indexes = self._search_config.get_min_indexes()
243240
return Coordinate(min_indexes)
244241

245-
def _get_coordinate_values(self,
246-
coordinate: Coordinate,
242+
def _get_coordinate_values(self, coordinate: Coordinate,
247243
key: int) -> Dict[str, Union[int, float]]:
248244
dims = self._search_config.get_dimensions()
249245
values = dims.get_values_for_coordinate(coordinate)
@@ -282,9 +278,6 @@ def _get_next_model_config(self, model_num: int) -> ModelConfig:
282278
'instance_group': [{
283279
'count': dimension_values['instance_count'],
284280
'kind': "KIND_GPU",
285-
'rate_limiter': {
286-
'priority': 1
287-
}
288281
}]
289282
}
290283

@@ -298,8 +291,7 @@ def _get_next_model_config(self, model_num: int) -> ModelConfig:
298291
model_variant_name_manager=self._model_variant_name_manager)
299292
return model_config
300293

301-
def _get_next_perf_analyzer_config(self,
302-
model_variant_name: str,
294+
def _get_next_perf_analyzer_config(self, model_variant_name: str,
303295
model_num: int) -> PerfAnalyzerConfig:
304296
dimension_values = self._get_coordinate_values(
305297
self._coordinate_to_measure, model_num)
@@ -338,8 +330,8 @@ def _print_debug_logs(self, measurements: List[Union[RunConfigMeasurement,
338330
best_latency = self._best_measurement.get_non_gpu_metric_value(
339331
"perf_latency_p99")
340332
else:
341-
best_throughput = None
342-
best_latency = None
333+
best_throughput = 0
334+
best_latency = 0
343335

344336
logger.debug(
345337
f"Measurement for {self._coordinate_to_measure}: "
@@ -348,5 +340,4 @@ def _print_debug_logs(self, measurements: List[Union[RunConfigMeasurement,
348340
)
349341
else:
350342
logger.debug(
351-
f"Measurement for {self._coordinate_to_measure}: None."
352-
)
343+
f"Measurement for {self._coordinate_to_measure}: None.")

0 commit comments

Comments
 (0)