Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CLI option for min/max number of trials in Optuna Search #884

Merged
merged 1 commit into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 52 additions & 8 deletions model_analyzer/config/generate/optuna_run_config_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,7 @@ def get_configs(self) -> Generator[RunConfig, None, None]:
yield default_run_config
self._default_measurement = self._last_measurement

total_num_of_possible_configs = (
self._search_parameters.number_of_total_possible_configurations()
)
max_configs_to_search = int(
total_num_of_possible_configs
* self._config.max_percentage_of_search_space
/ 100
)
max_configs_to_search = self._determine_maximum_number_of_configs_to_search()

# TODO: TMA-1885: Need an early exit strategy
for _ in range(max_configs_to_search):
Expand All @@ -159,6 +152,57 @@ def get_configs(self) -> Generator[RunConfig, None, None]:
score = self._calculate_score()
self._study.tell(trial, score)

def _determine_maximum_number_of_configs_to_search(self) -> int:
max_trials_based_on_percentage_of_search_space = (
self._determine_trials_based_on_max_percentage_of_search_space()
)

max_configs_to_search = self._decide_between_percentage_and_trial_count(
max_trials_based_on_percentage_of_search_space
)

return max_configs_to_search

def _determine_trials_based_on_max_percentage_of_search_space(self) -> int:
total_num_of_possible_configs = (
self._search_parameters.number_of_total_possible_configurations()
)
max_trials_based_on_percentage_of_search_space = int(
total_num_of_possible_configs
* self._config.max_percentage_of_search_space
/ 100
)

return max_trials_based_on_percentage_of_search_space

def _decide_between_percentage_and_trial_count(
self, max_trials_based_on_percentage_of_search_space: int
) -> int:
# By default we will search based on percentage of search space
# If the user specifies a number of trials we will use that instead
# If both are specified we will use the smaller number
max_trials_set_by_user = self._config.get_config()[
"optuna_max_trials"
].is_set_by_user()
max_percentage_set_by_user = self._config.get_config()[
"max_percentage_of_search_space"
].is_set_by_user()

if max_trials_set_by_user and max_percentage_set_by_user:
if (
self._config.optuna_max_trials
< max_trials_based_on_percentage_of_search_space
):
max_configs_to_search = self._config.optuna_max_trials
else:
max_configs_to_search = max_trials_based_on_percentage_of_search_space
elif max_trials_set_by_user:
max_configs_to_search = self._config.optuna_max_trials
else:
max_configs_to_search = max_trials_based_on_percentage_of_search_space

return max_configs_to_search

def _create_trial_objectives(self, trial: optuna.Trial) -> TrialObjectives:
trial_objectives: TrialObjectives = {}
for parameter_name in OptunaRunConfigGenerator.optuna_parameter_list:
Expand Down
20 changes: 20 additions & 0 deletions model_analyzer/config/input/config_command_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@
DEFAULT_ONLINE_OBJECTIVES,
DEFAULT_ONLINE_PLOTS,
DEFAULT_OPTUNA_MAX_PERCENTAGE_OF_SEARCH_SPACE,
DEFAULT_OPTUNA_MAX_TRIALS,
DEFAULT_OPTUNA_MIN_PERCENTAGE_OF_SEARCH_SPACE,
DEFAULT_OPTUNA_MIN_TRIALS,
DEFAULT_OUTPUT_MODEL_REPOSITORY,
DEFAULT_OVERRIDE_OUTPUT_REPOSITORY_FLAG,
DEFAULT_PERF_ANALYZER_CPU_UTIL,
Expand Down Expand Up @@ -936,6 +938,24 @@ def _add_run_search_configs(self):
description="Maximum percentage of the search space to profile when using Optuna",
)
)
self._add_config(
ConfigField(
"optuna_min_trials",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see support for min trials, but I don't see it used anywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only relevant/used once the code for early exit is added. I've just added the option for it now.

flags=["--optuna_min_trials"],
field_type=ConfigPrimitive(int),
default_value=DEFAULT_OPTUNA_MIN_TRIALS,
description="Minimum number of trials to profile when using Optuna",
)
)
self._add_config(
ConfigField(
"optuna_max_trials",
flags=["--optuna_max_trials"],
field_type=ConfigPrimitive(int),
default_value=DEFAULT_OPTUNA_MAX_TRIALS,
description="Maximum number of trials to profile when using Optuna",
)
)
self._add_config(
ConfigField(
"run_config_search_mode",
Expand Down
2 changes: 2 additions & 0 deletions model_analyzer/config/input/config_defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
DEFAULT_RUN_CONFIG_PROFILE_MODELS_CONCURRENTLY_ENABLE = False
DEFAULT_OPTUNA_MIN_PERCENTAGE_OF_SEARCH_SPACE = 5
DEFAULT_OPTUNA_MAX_PERCENTAGE_OF_SEARCH_SPACE = 10
DEFAULT_OPTUNA_MIN_TRIALS = 20
DEFAULT_OPTUNA_MAX_TRIALS = 200
DEFAULT_REQUEST_RATE_SEARCH_ENABLE = False
DEFAULT_TRITON_LAUNCH_MODE = "local"
DEFAULT_TRITON_DOCKER_IMAGE = "nvcr.io/nvidia/tritonserver:24.04-py3"
Expand Down
2 changes: 2 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ def get_test_options():
OptionStruct("int", "profile", "--run-config-search-max-binary-search-steps", None, "10", "5"),
OptionStruct("int", "profile", "--min_percentage_of_search_space", None, "10", "5"),
OptionStruct("int", "profile", "--max_percentage_of_search_space", None, "5", "10"),
OptionStruct("int", "profile", "--optuna_min_trials", None, "10", "20"),
OptionStruct("int", "profile", "--optuna_max_trials", None, "5", "200"),
OptionStruct("float", "profile", "--monitoring-interval", "-i", "10.0", "1.0"),
OptionStruct("float", "profile", "--perf-analyzer-cpu-util", None, "10.0", str(psutil.cpu_count() * 80.0)),
OptionStruct("int", "profile", "--num-configs-per-model", None, "10", "3"),
Expand Down
48 changes: 48 additions & 0 deletions tests/test_optuna_run_config_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,54 @@ def setUp(self):
seed=100,
)

def test_max_number_of_configs_to_search_percentage(self):
"""
Test percentage based max num of configs to search
"""
max_configs_to_search = (
self._rcg._determine_maximum_number_of_configs_to_search()
)

# Batch sizes (8) * Instance groups (5) * queue delays (3) = 120
# 10% of search space (120) = 12
self.assertEquals(max_configs_to_search, 12)

def test_max_number_of_configs_to_search_count(self):
"""
Test count based max num of configs to search
"""
config = self._create_config(additional_args=["--optuna_max_trials", "6"])

self._rcg._config = config

max_configs_to_search = (
self._rcg._determine_maximum_number_of_configs_to_search()
)

self.assertEquals(max_configs_to_search, 6)

def test_max_number_of_configs_to_search_both(self):
"""
Test count based on specify both a count and percentage
"""
config = self._create_config(
additional_args=[
"--optuna_max_trials",
"6",
"--max_percentage_of_search_space",
"3",
]
)

self._rcg._config = config

max_configs_to_search = (
self._rcg._determine_maximum_number_of_configs_to_search()
)

# Since both are specified we will use the smaller of the two (3% of 120 = 3)
self.assertEquals(max_configs_to_search, 3)

def test_create_default_run_config(self):
"""
Test that a default run config is properly created
Expand Down
Loading