Skip to content

Commit a27bb5d

Browse files
author
Mohamed Zeidan
committed
fix: keep job name in pipeline request for ModelTrainer and HyperparameterTuner
Both unconditionally popped training_job_name / hyper_parameter_tuning_job_name from the request for a PipelineSession. The TrainingStep/TuningStep already strip it via trim_request_dict (dropped by default, prefix preserved when PipelineDefinitionConfig(use_custom_job_prefix=True)), so popping upstream left use_custom_job_prefix nothing to preserve and made base_job_name have no effect in pipelines. Stop popping; let trim_request_dict handle it. Fixes #5776, #6299
1 parent 7ac2708 commit a27bb5d

4 files changed

Lines changed: 68 additions & 4 deletions

File tree

‎sagemaker-train/src/sagemaker/train/model_trainer.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -814,8 +814,10 @@ def _create_training_job_args(
814814
training_request["model_package_config"] = self.model_package_config
815815

816816
if boto3 or isinstance(self.sagemaker_session, PipelineSession):
817-
if isinstance(self.sagemaker_session, PipelineSession):
818-
training_request.pop("training_job_name", None)
817+
# Keep training_job_name in the request. The TrainingStep strips it via
818+
# trim_request_dict, which drops it by default but preserves the base_job_name
819+
# prefix when PipelineDefinitionConfig(use_custom_job_prefix=True). Popping it here
820+
# unconditionally left use_custom_job_prefix nothing to preserve (issue #5776, #6299).
819821
# Convert snake_case to PascalCase for AWS API
820822
pipeline_request = {to_pascal_case(k): v for k, v in training_request.items()}
821823
serialized_request = serialize(pipeline_request)

‎sagemaker-train/src/sagemaker/train/tuner.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,8 +1290,10 @@ def _start_tuning_job(self, inputs):
12901290
from sagemaker.core.utils.utils import serialize
12911291
from sagemaker.core.apiutils._boto_functions import to_pascal_case
12921292

1293-
# Remove job name for pipeline as it's auto-generated at execution time
1294-
tuning_request.pop("hyper_parameter_tuning_job_name", None)
1293+
# Keep hyper_parameter_tuning_job_name in the request. The TuningStep strips it via
1294+
# trim_request_dict, which drops it by default but preserves the base_tuning_job_name
1295+
# prefix when PipelineDefinitionConfig(use_custom_job_prefix=True). Popping it here
1296+
# unconditionally left use_custom_job_prefix nothing to preserve (issue #6299, #5776).
12951297
# Convert snake_case to PascalCase for AWS API
12961298
pipeline_request = {to_pascal_case(k): v for k, v in tuning_request.items()}
12971299
serialized_request = serialize(pipeline_request)

‎sagemaker-train/tests/unit/train/test_model_trainer.py‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,38 @@ def test_model_trainer_param_validation(test_case, modules_session):
254254
assert trainer.base_job_name == DEFAULT_BASE_NAME
255255

256256

257+
def test_pipeline_session_request_keeps_training_job_name(modules_session):
258+
"""Regression for #5776 / #6299.
259+
260+
Under a PipelineSession the request must KEEP TrainingJobName. The TrainingStep strips it via
261+
trim_request_dict (dropped by default, prefix preserved when use_custom_job_prefix=True);
262+
popping it here left use_custom_job_prefix nothing to preserve.
263+
"""
264+
from unittest.mock import Mock
265+
from sagemaker.core.workflow.pipeline_context import PipelineSession
266+
267+
session = Mock(spec=PipelineSession)
268+
session.default_bucket.return_value = DEFAULT_BUCKET
269+
session.default_bucket_prefix = DEFAULT_BUCKET_PREFIX
270+
session.boto_region_name = DEFAULT_REGION
271+
session.sagemaker_config = {}
272+
273+
trainer = ModelTrainer(
274+
training_image=DEFAULT_IMAGE,
275+
role=DEFAULT_ROLE,
276+
compute=DEFAULT_COMPUTE_CONFIG,
277+
stopping_condition=DEFAULT_STOPPING_CONDITION,
278+
output_data_config=DEFAULT_OUTPUT_DATA_CONFIG,
279+
base_job_name="my-prefix",
280+
sagemaker_session=session,
281+
)
282+
283+
args = trainer._create_training_job_args(input_data_config=[])
284+
285+
assert "TrainingJobName" in args, "TrainingJobName must survive into the pipeline request"
286+
assert args["TrainingJobName"].startswith("my-prefix")
287+
288+
257289
@patch("sagemaker.train.model_trainer.TrainingJob")
258290
def test_train_with_default_params(mock_training_job, model_trainer):
259291
model_trainer.train()

‎sagemaker-train/tests/unit/train/test_tuner.py‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,34 @@ def test_build_training_job_definition_includes_spot_params(self):
598598
definition.stopping_condition.max_wait_time_in_seconds, int
599599
), "Max wait time should be set"
600600

601+
def test_pipeline_session_request_keeps_tuning_job_name(self):
602+
"""Regression for #6299 / #5776.
603+
604+
Under a PipelineSession the tuning request must KEEP HyperParameterTuningJobName. The
605+
TuningStep strips it via trim_request_dict (dropped by default, prefix preserved when
606+
use_custom_job_prefix=True); popping it here left use_custom_job_prefix nothing to preserve.
607+
"""
608+
from unittest.mock import Mock
609+
from sagemaker.core.workflow.pipeline_context import PipelineSession
610+
611+
pipeline_session = Mock(spec=PipelineSession)
612+
mock_trainer = _create_mock_model_trainer()
613+
mock_trainer.sagemaker_session = pipeline_session
614+
615+
tuner = HyperparameterTuner(
616+
model_trainer=mock_trainer,
617+
objective_metric_name="accuracy",
618+
hyperparameter_ranges=_create_single_hp_range(),
619+
)
620+
tuner._current_job_name = "my-prefix-2026-01-01-00-00-00-000"
621+
622+
tuner._start_tuning_job(inputs=None)
623+
624+
pipeline_session._intercept_create_request.assert_called_once()
625+
serialized_request = pipeline_session._intercept_create_request.call_args.args[0]
626+
assert "HyperParameterTuningJobName" in serialized_request
627+
assert serialized_request["HyperParameterTuningJobName"].startswith("my-prefix")
628+
601629
def test_build_training_job_definition_includes_environment_variables(self):
602630
"""Test that _build_training_job_definition includes environment variables.
603631

0 commit comments

Comments
 (0)