diff --git a/sagemaker-core/src/sagemaker/core/shapes/shapes.py b/sagemaker-core/src/sagemaker/core/shapes/shapes.py index 5da1b83f50..91b1421602 100644 --- a/sagemaker-core/src/sagemaker/core/shapes/shapes.py +++ b/sagemaker-core/src/sagemaker/core/shapes/shapes.py @@ -7438,7 +7438,7 @@ class HyperParameterTuningJobConfig(Base): parameter_ranges: Optional[ParameterRanges] = Unassigned() training_job_early_stopping_type: Optional[StrPipeVar] = Unassigned() tuning_job_completion_criteria: Optional[TuningJobCompletionCriteria] = Unassigned() - random_seed: Optional[int] = Unassigned() + random_seed: Optional[IntPipeVar] = Unassigned() class HyperParameterAlgorithmSpecification(Base): diff --git a/sagemaker-core/src/sagemaker/core/tools/constants.py b/sagemaker-core/src/sagemaker/core/tools/constants.py index 0768664920..f663ebfd7b 100644 --- a/sagemaker-core/src/sagemaker/core/tools/constants.py +++ b/sagemaker-core/src/sagemaker/core/tools/constants.py @@ -147,4 +147,9 @@ "ProcessingInstancePreference": { "InstanceCount": "IntPipeVar", }, + # RandomSeed accepts a pipeline variable (e.g. a ParameterInteger) so tuning pipelines + # can parameterize reproducibility (issue #5614 / #6171). + "HyperParameterTuningJobConfig": { + "RandomSeed": "IntPipeVar", + }, } diff --git a/sagemaker-train/src/sagemaker/train/tuner.py b/sagemaker-train/src/sagemaker/train/tuner.py index ed872dc894..7c3cbd5b2c 100644 --- a/sagemaker-train/src/sagemaker/train/tuner.py +++ b/sagemaker-train/src/sagemaker/train/tuner.py @@ -106,7 +106,7 @@ def __init__( completion_criteria_config: Optional[TuningJobCompletionCriteria] = None, early_stopping_type: Union[str, PipelineVariable] = "Off", model_trainer_name: Optional[str] = None, - random_seed: Optional[int] = None, + random_seed: Optional[Union[int, PipelineVariable]] = None, autotune: bool = False, hyperparameters_to_keep_static: Optional[List[str]] = None, ): @@ -172,7 +172,8 @@ def __init__( model_trainer_name (str): A unique name to identify a model_trainer within the hyperparameter tuning job, when more than one model_trainer is used with the same tuning job (default: None). - random_seed (int): An initial value used to initialize a pseudo-random number generator. + random_seed (int or PipelineVariable): An initial value used to initialize a pseudo-random + number generator. Setting a random seed will make the hyperparameter tuning search strategies to produce more consistent configurations for the same tuning job. autotune (bool): Whether the parameter ranges or other unset settings of a tuning job @@ -1081,7 +1082,8 @@ def create( Can be either 'Auto' or 'Off' (default: 'Off'). If set to 'Off', early stopping will not be attempted. If set to 'Auto', early stopping of some training jobs may happen, but is not guaranteed to. - random_seed (int): An initial value used to initialize a pseudo-random number generator. + random_seed (int or PipelineVariable): An initial value used to initialize a pseudo-random + number generator. Setting a random seed will make the hyperparameter tuning search strategies to produce more consistent configurations for the same tuning job. autotune (bool): Whether the parameter ranges or other unset settings of a tuning job diff --git a/sagemaker-train/tests/unit/train/test_tuner.py b/sagemaker-train/tests/unit/train/test_tuner.py index d8010fa2d0..140eab7a43 100644 --- a/sagemaker-train/tests/unit/train/test_tuner.py +++ b/sagemaker-train/tests/unit/train/test_tuner.py @@ -261,6 +261,30 @@ def test_init_with_random_seed(self, mock_model_trainer, hyperparameter_ranges): assert tuner.random_seed == 42 + def test_random_seed_accepts_pipeline_variable(self, mock_model_trainer, hyperparameter_ranges): + """Regression for #5614 / #6171. + + ``random_seed`` must accept a pipeline variable (e.g. a ParameterInteger). Building the + tuning job config assigns it to ``HyperParameterTuningJobConfig.random_seed`` under + ``validate_assignment=True``; when that field was typed ``Optional[int]`` this raised + ``ValidationError: 1 validation error for HyperParameterTuningJobConfig``. + """ + from sagemaker.core.workflow.parameters import ParameterInteger + + seed = ParameterInteger(name="RandomState", default_value=42) + tuner = HyperparameterTuner( + model_trainer=mock_model_trainer, + objective_metric_name="accuracy", + hyperparameter_ranges=hyperparameter_ranges, + max_jobs=2, + max_parallel_jobs=1, + random_seed=seed, + ) + + assert tuner.random_seed is seed + config = tuner._build_tuning_job_config() + assert config.random_seed is seed + def test_init_with_autotune(self, mock_model_trainer): """Test initialization with autotune enabled.""" tuner = HyperparameterTuner(