1515import importlib
1616import inspect
1717import json
18+ from enum import Enum
1819
1920from sagemaker .amazon .amazon_estimator import AmazonAlgorithmEstimatorBase , RecordSet
2021from sagemaker .amazon .hyperparameter import Hyperparameter as hp # noqa
3536 'knn' : 'KNN' ,
3637 'object2vec' : 'Object2Vec' ,
3738}
39+ HYPERPARAMETER_TUNING_JOB_NAME = 'HyperParameterTuningJobName'
40+ PARENT_HYPERPARAMETER_TUNING_JOBS = 'ParentHyperParameterTuningJobs'
41+ WARM_START_TYPE = 'WarmStartType'
3842
3943
4044class _ParameterRange (object ):
@@ -134,6 +138,113 @@ class IntegerParameter(_ParameterRange):
134138 __name__ = 'Integer'
135139
136140
141+ class WarmStartTypes (Enum ):
142+ """Warm Start Configuration type. There can be two types of warm start jobs:
143+ * IdenticalDataAndAlgorithm: Type of warm start that allows users to reuse training results from existing
144+ tuning jobs that have the same algorithm code and datasets.
145+ * TransferLearning: Type of warm start that allows users to reuse training results from existing tuning jobs
146+ that have similar algorithm code and datasets.
147+ """
148+ IDENTICAL_DATA_AND_ALGORITHM = "IdenticalDataAndAlgorithm"
149+ TRANSFER_LEARNING = "TransferLearning"
150+
151+
152+ class WarmStartConfig (object ):
153+ """Warm Start Configuration which defines the nature of the warm start ``HyperparameterTuner``, with type and
154+ parents for warm start.
155+
156+ Examples:
157+ >>> warm_start_config = WarmStartConfig(type=WarmStartTypes.TransferLearning, parents={"p1","p2"})
158+ >>> warm_start_config.type
159+ "TransferLearning"
160+ >>> warm_start_config.parents
161+ {"p1","p2"}
162+ """
163+
164+ def __init__ (self , warm_start_type , parents ):
165+ """Initializes the ``WarmStartConfig`` with the provided ``WarmStartTypes`` and parents.
166+
167+ Args:
168+ warm_start_type (sagemaker.tuner.WarmStartTypes): This should be one of the supported warm start types
169+ in WarmStartType
170+ parents (set{str}): Set of parent tuning jobs which will be used to warm start the new tuning job.
171+ """
172+
173+ if warm_start_type not in WarmStartTypes :
174+ raise ValueError (
175+ "Invalid type: {}, valid warm start types are: [{}]" .format (warm_start_type ,
176+ [t for t in WarmStartTypes ]))
177+
178+ if not parents :
179+ raise ValueError ("Invalid parents: {}, parents should not be None/empty" .format (parents ))
180+
181+ self .type = warm_start_type
182+ self .parents = set (parents )
183+
184+ @classmethod
185+ def from_job_desc (cls , warm_start_config ):
186+ """Creates an instance of ``WarmStartConfig`` class, from warm start configuration response from
187+ DescribeTrainingJob.
188+
189+ Args:
190+ warm_start_config (dict): The expected format of the ``warm_start_config`` contains two first-class
191+ fields:
192+ * "type": Type of warm start tuner, currently two supported types - "IdenticalDataAndAlgorithm" and
193+ "TransferLearning".
194+ * "parents": List of tuning job names from which the warm start should be done.
195+
196+ Returns:
197+ sagemaker.tuner.WarmStartConfig: De-serialized instance of WarmStartConfig containing the type and parents
198+ provided as part of ``warm_start_config``.
199+
200+ Examples:
201+ >>> warm_start_config = WarmStartConfig.from_job_desc(warm_start_config={
202+ >>> "WarmStartType":"TransferLearning",
203+ >>> "ParentHyperParameterTuningJobs": [
204+ >>> {'HyperParameterTuningJobName': "p1"},
205+ >>> {'HyperParameterTuningJobName': "p2"},
206+ >>> ]
207+ >>>})
208+ >>> warm_start_config.type
209+ "TransferLearning"
210+ >>> warm_start_config.parents
211+ ["p1","p2"]
212+ """
213+ if not warm_start_config or \
214+ WARM_START_TYPE not in warm_start_config or \
215+ PARENT_HYPERPARAMETER_TUNING_JOBS not in warm_start_config :
216+ return None
217+
218+ parents = []
219+ for parent in warm_start_config [PARENT_HYPERPARAMETER_TUNING_JOBS ]:
220+ parents .append (parent [HYPERPARAMETER_TUNING_JOB_NAME ])
221+
222+ return cls (warm_start_type = WarmStartTypes (warm_start_config [WARM_START_TYPE ]),
223+ parents = parents )
224+
225+ def to_input_req (self ):
226+ """Converts the ``self`` instance to the desired input request format.
227+
228+ Returns:
229+ dict: Containing the "WarmStartType" and "ParentHyperParameterTuningJobs" as the first class fields.
230+
231+ Examples:
232+ >>> warm_start_config = WarmStartConfig(warm_start_type=WarmStartTypes.TransferLearning,parents=["p1,p2"])
233+ >>> warm_start_config.to_input_req()
234+ {
235+ "WarmStartType":"TransferLearning",
236+ "ParentHyperParameterTuningJobs": [
237+ {'HyperParameterTuningJobName': "p1"},
238+ {'HyperParameterTuningJobName': "p2"},
239+ ]
240+ }
241+ """
242+ return {
243+ WARM_START_TYPE : self .type .value ,
244+ PARENT_HYPERPARAMETER_TUNING_JOBS : [{HYPERPARAMETER_TUNING_JOB_NAME : parent } for parent in self .parents ]
245+ }
246+
247+
137248class HyperparameterTuner (object ):
138249 """A class for creating and interacting with Amazon SageMaker hyperparameter tuning jobs, as well as
139250 deploying the resulting model(s).
@@ -148,7 +259,7 @@ class HyperparameterTuner(object):
148259
149260 def __init__ (self , estimator , objective_metric_name , hyperparameter_ranges , metric_definitions = None ,
150261 strategy = 'Bayesian' , objective_type = 'Maximize' , max_jobs = 1 , max_parallel_jobs = 1 ,
151- tags = None , base_tuning_job_name = None ):
262+ tags = None , base_tuning_job_name = None , warm_start_config = None ):
152263 """Initialize a ``HyperparameterTuner``. It takes an estimator to obtain configuration information
153264 for training jobs that are created as the result of a hyperparameter tuning job.
154265
@@ -175,6 +286,8 @@ def __init__(self, estimator, objective_metric_name, hyperparameter_ranges, metr
175286 base_tuning_job_name (str): Prefix for the hyperparameter tuning job name when the
176287 :meth:`~sagemaker.tuner.HyperparameterTuner.fit` method launches. If not specified,
177288 a default job name is generaged, based on the training image name and current timestamp.
289+ warm_start_config (sagemaker.tuner.WarmStartConfig): A ``WarmStartConfig`` object that has been initialized
290+ with the configuration defining the nature of warm start tuning job.
178291 """
179292 self ._hyperparameter_ranges = hyperparameter_ranges
180293 if self ._hyperparameter_ranges is None or len (self ._hyperparameter_ranges ) == 0 :
@@ -194,6 +307,7 @@ def __init__(self, estimator, objective_metric_name, hyperparameter_ranges, metr
194307 self .base_tuning_job_name = base_tuning_job_name
195308 self ._current_job_name = None
196309 self .latest_tuning_job = None
310+ self .warm_start_config = warm_start_config
197311
198312 def _prepare_for_training (self , job_name = None , include_cls_metadata = True ):
199313 if job_name is not None :
@@ -419,6 +533,7 @@ def _prepare_init_params_from_job_description(cls, job_details):
419533 'strategy' : tuning_config ['Strategy' ],
420534 'max_jobs' : tuning_config ['ResourceLimits' ]['MaxNumberOfTrainingJobs' ],
421535 'max_parallel_jobs' : tuning_config ['ResourceLimits' ]['MaxParallelTrainingJobs' ],
536+ 'warm_start_config' : WarmStartConfig .from_job_desc (job_details .get ('WarmStartConfig' , None ))
422537 }
423538
424539 @classmethod
@@ -489,6 +604,82 @@ def _validate_parameter_ranges(self):
489604 except KeyError :
490605 pass
491606
607+ def transfer_learning_tuner (self , additional_parents = None , estimator = None ):
608+ """Creates a new ``HyperparameterTuner`` by copying the request fields from the provided parent to the new
609+ instance of ``HyperparameterTuner``. Followed by addition of warm start configuration with the type as
610+ "TransferLearning" and parents as the union of provided list of ``additional_parents`` and the ``self``.
611+ Also, training image in the new tuner's estimator is updated with the provided ``training_image``.
612+
613+ Args:
614+ additional_parents (set{str}): Set of additional parents along with the self to be used in warm starting
615+ the transfer learning tuner.
616+ estimator (sagemaker.estimator.EstimatorBase): An estimator object that has been initialized with
617+ the desired configuration. There does not need to be a training job associated with this instance.
618+
619+ Returns:
620+ sagemaker.tuner.HyperparameterTuner: ``HyperparameterTuner`` instance which can be used to launch transfer
621+ learning tuning job.
622+
623+ Examples:
624+ >>> parent_tuner = HyperparameterTuner.attach(tuning_job_name="parent-job-1")
625+ >>> transfer_learning_tuner = parent_tuner.transfer_learning_tuner(additional_parents={"parent-job-2"})
626+ Later On:
627+ >>> transfer_learning_tuner.fit(inputs={})
628+ """
629+
630+ return self ._create_warm_start_tuner (additional_parents = additional_parents ,
631+ warm_start_type = WarmStartTypes .TRANSFER_LEARNING ,
632+ estimator = estimator )
633+
634+ def identical_dataset_and_algorithm_tuner (self , additional_parents = None ):
635+ """Creates a new ``HyperparameterTuner`` by copying the request fields from the provided parent to the new
636+ instance of ``HyperparameterTuner``. Followed by addition of warm start configuration with the type as
637+ "IdenticalDataAndAlgorithm" and parents as the union of provided list of ``additional_parents`` and the ``self``
638+
639+ Args:
640+ additional_parents (set{str}): Set of additional parents along with the self to be used in warm starting
641+ the identical dataset and algorithm tuner.
642+
643+ Returns:
644+ sagemaker.tuner.HyperparameterTuner: HyperparameterTuner instance which can be used to launch identical
645+ dataset and algorithm tuning job.
646+
647+ Examples:
648+ >>> parent_tuner = HyperparameterTuner.attach(tuning_job_name="parent-job-1")
649+ >>> identical_dataset_algo_tuner = parent_tuner.identical_dataset_and_algorithm_tuner(
650+ >>> additional_parents={"parent-job-2"})
651+ Later On:
652+ >>> identical_dataset_algo_tuner.fit(inputs={})
653+ """
654+
655+ return self ._create_warm_start_tuner (additional_parents = additional_parents ,
656+ warm_start_type = WarmStartTypes .IDENTICAL_DATA_AND_ALGORITHM )
657+
658+ def _create_warm_start_tuner (self , additional_parents , warm_start_type , estimator = None ):
659+ """Creates a new ``HyperparameterTuner`` with ``WarmStartConfig``, where type will be equal to
660+ ``warm_start_type`` and``parents`` would be equal to union of ``additional_parents`` and self.
661+
662+ Args:
663+ additional_parents (set{str}): Additional parents along with self, to be used for warm starting.
664+ warm_start_type (sagemaker.tuner.WarmStartTypes): Type of warm start job.
665+
666+ Returns:
667+ sagemaker.tuner.HyperparameterTuner: Instance with the request fields copied from self along with the
668+ warm start configuration
669+ """
670+ all_parents = {self .latest_tuning_job .name }
671+ if additional_parents :
672+ all_parents = all_parents .union (additional_parents )
673+
674+ return HyperparameterTuner (estimator = estimator if estimator else self .estimator ,
675+ objective_metric_name = self .objective_metric_name ,
676+ hyperparameter_ranges = self ._hyperparameter_ranges ,
677+ objective_type = self .objective_type ,
678+ max_jobs = self .max_jobs ,
679+ max_parallel_jobs = self .max_parallel_jobs ,
680+ warm_start_config = WarmStartConfig (warm_start_type = warm_start_type ,
681+ parents = all_parents ))
682+
492683
493684class _TuningJob (_Job ):
494685 @classmethod
@@ -504,6 +695,10 @@ def start_new(cls, tuner, inputs):
504695 """
505696 config = _Job ._load_config (inputs , tuner .estimator )
506697
698+ warm_start_config_req = None
699+ if tuner .warm_start_config :
700+ warm_start_config_req = tuner .warm_start_config .to_input_req ()
701+
507702 tuner .estimator .sagemaker_session .tune (job_name = tuner ._current_job_name , strategy = tuner .strategy ,
508703 objective_type = tuner .objective_type ,
509704 objective_metric_name = tuner .objective_metric_name ,
@@ -516,7 +711,8 @@ def start_new(cls, tuner, inputs):
516711 role = (config ['role' ]), input_config = (config ['input_config' ]),
517712 output_config = (config ['output_config' ]),
518713 resource_config = (config ['resource_config' ]),
519- stop_condition = (config ['stop_condition' ]), tags = tuner .tags )
714+ stop_condition = (config ['stop_condition' ]), tags = tuner .tags ,
715+ warm_start_config = warm_start_config_req )
520716
521717 return cls (tuner .sagemaker_session , tuner ._current_job_name )
522718
@@ -525,3 +721,50 @@ def stop(self):
525721
526722 def wait (self ):
527723 self .sagemaker_session .wait_for_tuning_job (self .name )
724+
725+
726+ def create_identical_dataset_and_algorithm_tuner (parent , additional_parents = None , sagemaker_session = None ):
727+ """Creates a new tuner by copying the request fields from the provided parent to the new instance of
728+ ``HyperparameterTuner`` followed by addition of warm start configuration with the type as
729+ "IdenticalDataAndAlgorithm" and ``parents`` as the union of provided list of ``additional_parents`` and the
730+ ``parent``.
731+
732+ Args:
733+ parent (str): Primary parent tuning job's name from which the Tuner and Estimator configuration has to be copied
734+ additional_parents (set{str}): Set of additional parent tuning job's names along with the primary parent tuning
735+ job name to be used in warm starting the transfer learning tuner.
736+ sagemaker_session (sagemaker.session.Session): Session object which manages interactions with
737+ Amazon SageMaker APIs and any other AWS services needed. If not specified, one is created
738+ using the default AWS configuration chain.
739+
740+ Returns:
741+ sagemaker.tuner.HyperparameterTuner: a new ``HyperparameterTuner`` object for the warm-started
742+ hyperparameter tuning job
743+ """
744+
745+ parent_tuner = HyperparameterTuner .attach (tuning_job_name = parent , sagemaker_session = sagemaker_session )
746+ return parent_tuner .identical_dataset_and_algorithm_tuner (additional_parents = additional_parents )
747+
748+
749+ def create_transfer_learning_tuner (parent , additional_parents = None , estimator = None , sagemaker_session = None ):
750+ """Creates a new ``HyperParameterTuner`` by copying the request fields from the provided parent to the new instance
751+ of ``HyperparameterTuner`` followed by addition of warm start configuration with the type as "TransferLearning"
752+ and ``parents`` as the union of provided list of ``additional_parents`` and the ``parent``.
753+
754+ Args:
755+ parent (str): Primary parent tuning job's name from which the Tuner and Estimator configuration has to be copied
756+ additional_parents (set{str}): Set of additional parent tuning job's names along with the primary parent tuning
757+ job name to be used in warm starting the identical dataset and algorithm tuner.
758+ estimator (sagemaker.estimator.EstimatorBase): An estimator object that has been initialized with
759+ the desired configuration. There does not need to be a training job associated with this instance.
760+ sagemaker_session (sagemaker.session.Session): Session object which manages interactions with
761+ Amazon SageMaker APIs and any other AWS services needed. If not specified, one is created
762+ using the default AWS configuration chain.
763+
764+ Returns:
765+ sagemaker.tuner.HyperparameterTuner: New instance of warm started HyperparameterTuner
766+ """
767+
768+ parent_tuner = HyperparameterTuner .attach (tuning_job_name = parent , sagemaker_session = sagemaker_session )
769+ return parent_tuner .transfer_learning_tuner (additional_parents = additional_parents ,
770+ estimator = estimator )
0 commit comments