@@ -611,6 +611,9 @@ def test_non_spec_keys_flow_into_train_hyperparameters(
611611 overrides = {"training_config" : {"sequence_length" : 8192 }},
612612 )
613613
614+ # For serverless (ie compute=None): Non-spec keys that aren't overridden don't flow to hyperparams
615+ trainer .compute = MagicMock ()
616+
614617 with patch ("sagemaker.train.sft_trainer.TrainingJob" ) as mock_tj , \
615618 patch ("sagemaker.train.sft_trainer.TrainDefaults" ) as mock_defaults , \
616619 patch ("sagemaker.train.sft_trainer._create_input_data_config" ) as mock_input , \
@@ -640,6 +643,54 @@ def test_non_spec_keys_flow_into_train_hyperparameters(
640643 assert "warmup_ratio" in final_hp
641644 assert final_hp ["warmup_ratio" ] == "0.1"
642645
646+ @patch ("sagemaker.train.sft_trainer._validate_eula_for_gated_model" , return_value = False )
647+ @patch ("sagemaker.train.sft_trainer._get_fine_tuning_options_and_model_arn" )
648+ @patch ("sagemaker.train.sft_trainer._validate_and_resolve_model_package_group" , return_value = "my-group" )
649+ @patch ("sagemaker.train.sft_trainer._resolve_model_and_name" , return_value = ("model_obj" , "nova-lite-v2" ))
650+ def test_serverless_non_spec_keys_dont_flow_into_train_hyperparameters (
651+ self , mock_resolve , mock_validate_group , mock_get_options , mock_eula ,
652+ mock_hyperparams_with_full_template
653+ ):
654+ """Non-spec keys from full template are included in final training hyperparameters."""
655+ mock_get_options .return_value = (mock_hyperparams_with_full_template , "model-arn" , False )
656+
657+ from sagemaker .train .sft_trainer import SFTTrainer
658+
659+ trainer = SFTTrainer (
660+ model = "nova-lite-v2" ,
661+ model_package_group = "my-group" ,
662+ training_dataset = "s3://bucket/train.jsonl" ,
663+ overrides = {"training_config" : {"sequence_length" : 8191 }},
664+ )
665+
666+ with patch ("sagemaker.train.sft_trainer.TrainingJob" ) as mock_tj , \
667+ patch ("sagemaker.train.sft_trainer.TrainDefaults" ) as mock_defaults , \
668+ patch ("sagemaker.train.sft_trainer._create_input_data_config" ) as mock_input , \
669+ patch ("sagemaker.train.sft_trainer._convert_input_data_to_channels" , return_value = []), \
670+ patch ("sagemaker.train.sft_trainer._create_output_config" , return_value = MagicMock ()), \
671+ patch ("sagemaker.train.sft_trainer._create_serverless_config" , return_value = MagicMock ()), \
672+ patch ("sagemaker.train.sft_trainer._create_mlflow_config" , return_value = None ), \
673+ patch ("sagemaker.train.sft_trainer._create_model_package_config" , return_value = None ), \
674+ patch ("sagemaker.train.sft_trainer._validate_hyperparameter_values" ), \
675+ patch ("sagemaker.train.sft_trainer._get_jumpstart_tags" , return_value = []):
676+
677+ mock_session = MagicMock ()
678+ mock_session .boto_session .region_name = "us-west-2"
679+ mock_defaults .get_sagemaker_session .return_value = mock_session
680+ mock_defaults .get_role .return_value = "arn:aws:iam::123:role/Role"
681+ mock_tj .create .return_value = MagicMock ()
682+
683+ trainer .train (wait = False )
684+
685+ call_kwargs = mock_tj .create .call_args [1 ]
686+ final_hp = call_kwargs ["hyper_parameters" ]
687+
688+ # Non-spec key is now in final hyperparameters
689+ assert "sequence_length" in final_hp
690+ assert final_hp ["sequence_length" ] == "8191"
691+ # Other full template keys also present
692+ assert "warmup_ratio" not in final_hp
693+
643694 @patch ("sagemaker.train.sft_trainer._validate_eula_for_gated_model" , return_value = False )
644695 @patch ("sagemaker.train.sft_trainer._get_fine_tuning_options_and_model_arn" )
645696 @patch ("sagemaker.train.sft_trainer._validate_and_resolve_model_package_group" , return_value = "my-group" )
@@ -660,6 +711,9 @@ def test_nested_keys_flow_into_train_hyperparameters(
660711 overrides = {"training_config" : {"lr_scheduler" : {"warmup_steps" : 30 }}},
661712 )
662713
714+ # For serverless (ie compute=None): Non-spec keys that aren't overridden don't flow to hyperparams
715+ trainer .compute = MagicMock ()
716+
663717 with patch ("sagemaker.train.sft_trainer.TrainingJob" ) as mock_tj , \
664718 patch ("sagemaker.train.sft_trainer.TrainDefaults" ) as mock_defaults , \
665719 patch ("sagemaker.train.sft_trainer._create_input_data_config" ) as mock_input , \
@@ -725,6 +779,9 @@ def test_deeply_nested_peft_keys_flow_into_hyperparameters(
725779 overrides = {"training_config" : {"peft" : {"lora_tuning" : {"alpha" : 128 }}}},
726780 )
727781
782+ # For serverless (ie compute=None): Non-spec keys that aren't overridden don't flow to hyperparams
783+ trainer .compute = MagicMock ()
784+
728785 with patch ("sagemaker.train.sft_trainer.TrainingJob" ) as mock_tj , \
729786 patch ("sagemaker.train.sft_trainer.TrainDefaults" ) as mock_defaults , \
730787 patch ("sagemaker.train.sft_trainer._create_input_data_config" ), \
0 commit comments