Skip to content

Commit f13a4de

Browse files
Tim Songtimyber
Tim Song
authored andcommitted
feature: add RandomSeed to support reproducible HPO
1 parent c5fc93f commit f13a4de

File tree

5 files changed

+38
-0
lines changed

5 files changed

+38
-0
lines changed

src/sagemaker/session.py

+12
Original file line numberDiff line numberDiff line change
@@ -2130,6 +2130,7 @@ def tune( # noqa: C901
21302130
use_spot_instances=False,
21312131
checkpoint_s3_uri=None,
21322132
checkpoint_local_path=None,
2133+
random_seed=None,
21332134
):
21342135
"""Create an Amazon SageMaker hyperparameter tuning job.
21352136
@@ -2208,6 +2209,9 @@ def tune( # noqa: C901
22082209
started. If the path is unset then SageMaker assumes the
22092210
checkpoints will be provided under `/opt/ml/checkpoints/`.
22102211
(default: ``None``).
2212+
random_seed (int): An initial value used to initialize a pseudo-random number generator.
2213+
Setting a random seed will make the hyperparameter tuning search strategies to produce more consistent
2214+
configurations for the same tuning job. (default: ``None``).
22112215
"""
22122216

22132217
tune_request = {
@@ -2220,6 +2224,7 @@ def tune( # noqa: C901
22202224
objective_metric_name=objective_metric_name,
22212225
parameter_ranges=parameter_ranges,
22222226
early_stopping_type=early_stopping_type,
2227+
random_seed=random_seed,
22232228
),
22242229
"TrainingJobDefinition": self._map_training_config(
22252230
static_hyperparameters=static_hyperparameters,
@@ -2375,6 +2380,7 @@ def _map_tuning_config(
23752380
objective_type=None,
23762381
objective_metric_name=None,
23772382
parameter_ranges=None,
2383+
random_seed=None,
23782384
):
23792385
"""Construct tuning job configuration dictionary.
23802386
@@ -2392,6 +2398,9 @@ def _map_tuning_config(
23922398
objective_metric_name (str): Name of the metric for evaluating training jobs.
23932399
parameter_ranges (dict): Dictionary of parameter ranges. These parameter ranges can
23942400
be one of three types: Continuous, Integer, or Categorical.
2401+
random_seed (int): An initial value used to initialize a pseudo-random number generator.
2402+
Setting a random seed will make the hyperparameter tuning search strategies to produce more consistent
2403+
configurations for the same tuning job.
23952404
23962405
Returns:
23972406
A dictionary of tuning job configuration. For format details, please refer to
@@ -2408,6 +2417,9 @@ def _map_tuning_config(
24082417
"TrainingJobEarlyStoppingType": early_stopping_type,
24092418
}
24102419

2420+
if random_seed is not None:
2421+
tuning_config["RandomSeed"] = random_seed
2422+
24112423
tuning_objective = cls._map_tuning_objective(objective_type, objective_metric_name)
24122424
if tuning_objective is not None:
24132425
tuning_config["HyperParameterTuningJobObjective"] = tuning_objective

src/sagemaker/tuner.py

+18
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ def __init__(
413413
strategy_config: Optional[StrategyConfig] = None,
414414
early_stopping_type: Union[str, PipelineVariable] = "Off",
415415
estimator_name: Optional[str] = None,
416+
random_seed: Optional[int] = None,
416417
):
417418
"""Creates a ``HyperparameterTuner`` instance.
418419
@@ -470,6 +471,9 @@ def __init__(
470471
estimator_name (str): A unique name to identify an estimator within the
471472
hyperparameter tuning job, when more than one estimator is used with
472473
the same tuning job (default: None).
474+
random_seed (int): An initial value used to initialize a pseudo-random number generator.
475+
Setting a random seed will make the hyperparameter tuning search strategies to produce more consistent
476+
configurations for the same tuning job.
473477
"""
474478
if hyperparameter_ranges is None or len(hyperparameter_ranges) == 0:
475479
raise ValueError("Need to specify hyperparameter ranges")
@@ -516,6 +520,7 @@ def __init__(
516520
self.latest_tuning_job = None
517521
self.warm_start_config = warm_start_config
518522
self.early_stopping_type = early_stopping_type
523+
self.random_seed = random_seed
519524

520525
def _prepare_for_tuning(self, job_name=None, include_cls_metadata=False):
521526
"""Prepare the tuner instance for tuning (fit)."""
@@ -1222,6 +1227,9 @@ def _prepare_init_params_from_job_description(cls, job_details):
12221227
"base_tuning_job_name": base_from_name(job_details["HyperParameterTuningJobName"]),
12231228
}
12241229

1230+
if "RandomSeed" in tuning_config:
1231+
params["random_seed"] = tuning_config["RandomSeed"]
1232+
12251233
if "HyperParameterTuningJobObjective" in tuning_config:
12261234
params["objective_metric_name"] = tuning_config["HyperParameterTuningJobObjective"][
12271235
"MetricName"
@@ -1483,6 +1491,7 @@ def _create_warm_start_tuner(self, additional_parents, warm_start_type, estimato
14831491
warm_start_type=warm_start_type, parents=all_parents
14841492
),
14851493
early_stopping_type=self.early_stopping_type,
1494+
random_seed=self.random_seed,
14861495
)
14871496

14881497
if len(self.estimator_dict) > 1:
@@ -1508,6 +1517,7 @@ def _create_warm_start_tuner(self, additional_parents, warm_start_type, estimato
15081517
max_parallel_jobs=self.max_parallel_jobs,
15091518
warm_start_config=WarmStartConfig(warm_start_type=warm_start_type, parents=all_parents),
15101519
early_stopping_type=self.early_stopping_type,
1520+
random_seed=self.random_seed,
15111521
)
15121522

15131523
@classmethod
@@ -1526,6 +1536,7 @@ def create(
15261536
tags=None,
15271537
warm_start_config=None,
15281538
early_stopping_type="Off",
1539+
random_seed=None,
15291540
):
15301541
"""Factory method to create a ``HyperparameterTuner`` instance.
15311542
@@ -1586,6 +1597,9 @@ def create(
15861597
Can be either 'Auto' or 'Off' (default: 'Off'). If set to 'Off', early stopping
15871598
will not be attempted. If set to 'Auto', early stopping of some training jobs may
15881599
happen, but is not guaranteed to.
1600+
random_seed (int): An initial value used to initialize a pseudo-random number generator.
1601+
Setting a random seed will make the hyperparameter tuning search strategies to produce more consistent
1602+
configurations for the same tuning job.
15891603
15901604
Returns:
15911605
sagemaker.tuner.HyperparameterTuner: a new ``HyperparameterTuner`` object that can
@@ -1624,6 +1638,7 @@ def create(
16241638
tags=tags,
16251639
warm_start_config=warm_start_config,
16261640
early_stopping_type=early_stopping_type,
1641+
random_seed=random_seed,
16271642
)
16281643

16291644
for estimator_name in estimator_names[1:]:
@@ -1775,6 +1790,9 @@ def _get_tuner_args(cls, tuner, inputs):
17751790
"early_stopping_type": tuner.early_stopping_type,
17761791
}
17771792

1793+
if tuner.random_seed is not None:
1794+
tuning_config["random_seed"] = tuner.random_seed
1795+
17781796
if tuner.strategy_config is not None:
17791797
tuning_config["strategy_config"] = tuner.strategy_config
17801798

tests/unit/test_session.py

+6
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,7 @@ def test_train_pack_to_request(sagemaker_session):
882882
"ResourceLimits": {"MaxNumberOfTrainingJobs": 100, "MaxParallelTrainingJobs": 5},
883883
"ParameterRanges": SAMPLE_PARAM_RANGES,
884884
"TrainingJobEarlyStoppingType": "Off",
885+
"RandomSeed": 0,
885886
},
886887
"TrainingJobDefinition": {
887888
"StaticHyperParameters": STATIC_HPs,
@@ -967,6 +968,7 @@ def assert_create_tuning_job_request(**kwrags):
967968
sagemaker_session.tune(
968969
job_name="dummy-tuning-1",
969970
strategy="Bayesian",
971+
random_seed=0,
970972
objective_type="Maximize",
971973
objective_metric_name="val-score",
972974
max_jobs=100,
@@ -1058,6 +1060,7 @@ def assert_create_tuning_job_request(**kwrags):
10581060
"max_jobs": 100,
10591061
"max_parallel_jobs": 5,
10601062
"parameter_ranges": SAMPLE_PARAM_RANGES,
1063+
"random_seed": 0,
10611064
},
10621065
training_config={
10631066
"static_hyperparameters": STATIC_HPs,
@@ -1148,6 +1151,7 @@ def assert_create_tuning_job_request(**kwrags):
11481151
sagemaker_session.tune(
11491152
job_name="dummy-tuning-1",
11501153
strategy="Bayesian",
1154+
random_seed=0,
11511155
objective_type="Maximize",
11521156
objective_metric_name="val-score",
11531157
max_jobs=100,
@@ -1183,6 +1187,7 @@ def assert_create_tuning_job_request(**kwrags):
11831187
sagemaker_session.tune(
11841188
job_name="dummy-tuning-1",
11851189
strategy="Bayesian",
1190+
random_seed=0,
11861191
objective_type="Maximize",
11871192
objective_metric_name="val-score",
11881193
max_jobs=100,
@@ -1226,6 +1231,7 @@ def assert_create_tuning_job_request(**kwargs):
12261231
sagemaker_session.tune(
12271232
job_name="dummy-tuning-1",
12281233
strategy="Bayesian",
1234+
random_seed=0,
12291235
objective_type="Maximize",
12301236
objective_metric_name="val-score",
12311237
max_jobs=100,

tests/unit/test_tuner.py

+1
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,7 @@ def test_attach_tuning_job_with_estimator_from_hyperparameters(sagemaker_session
545545
assert tuner.strategy == "Bayesian"
546546
assert tuner.objective_type == "Minimize"
547547
assert tuner.early_stopping_type == "Off"
548+
assert tuner.random_seed == 0
548549

549550
assert isinstance(tuner.estimator, PCA)
550551
assert tuner.estimator.role == ROLE

tests/unit/tuner_test_utils.py

+1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
],
113113
},
114114
"TrainingJobEarlyStoppingType": "Off",
115+
"RandomSeed": 0,
115116
},
116117
"HyperParameterTuningJobName": JOB_NAME,
117118
"TrainingJobDefinition": {

0 commit comments

Comments
 (0)