15
15
import importlib
16
16
import inspect
17
17
import json
18
+ from enum import Enum
18
19
19
20
from sagemaker .amazon .amazon_estimator import AmazonAlgorithmEstimatorBase , RecordSet
20
21
from sagemaker .amazon .hyperparameter import Hyperparameter as hp # noqa
35
36
'knn' : 'KNN' ,
36
37
'object2vec' : 'Object2Vec' ,
37
38
}
39
+ HYPERPARAMETER_TUNING_JOB_NAME = 'HyperParameterTuningJobName'
40
+ PARENT_HYPERPARAMETER_TUNING_JOBS = 'ParentHyperParameterTuningJobs'
41
+ WARM_START_TYPE = 'WarmStartType'
38
42
39
43
40
44
class _ParameterRange (object ):
@@ -134,6 +138,113 @@ class IntegerParameter(_ParameterRange):
134
138
__name__ = 'Integer'
135
139
136
140
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
+
137
248
class HyperparameterTuner (object ):
138
249
"""A class for creating and interacting with Amazon SageMaker hyperparameter tuning jobs, as well as
139
250
deploying the resulting model(s).
@@ -148,7 +259,7 @@ class HyperparameterTuner(object):
148
259
149
260
def __init__ (self , estimator , objective_metric_name , hyperparameter_ranges , metric_definitions = None ,
150
261
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 ):
152
263
"""Initialize a ``HyperparameterTuner``. It takes an estimator to obtain configuration information
153
264
for training jobs that are created as the result of a hyperparameter tuning job.
154
265
@@ -175,6 +286,8 @@ def __init__(self, estimator, objective_metric_name, hyperparameter_ranges, metr
175
286
base_tuning_job_name (str): Prefix for the hyperparameter tuning job name when the
176
287
:meth:`~sagemaker.tuner.HyperparameterTuner.fit` method launches. If not specified,
177
288
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.
178
291
"""
179
292
self ._hyperparameter_ranges = hyperparameter_ranges
180
293
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
194
307
self .base_tuning_job_name = base_tuning_job_name
195
308
self ._current_job_name = None
196
309
self .latest_tuning_job = None
310
+ self .warm_start_config = warm_start_config
197
311
198
312
def _prepare_for_training (self , job_name = None , include_cls_metadata = True ):
199
313
if job_name is not None :
@@ -419,6 +533,7 @@ def _prepare_init_params_from_job_description(cls, job_details):
419
533
'strategy' : tuning_config ['Strategy' ],
420
534
'max_jobs' : tuning_config ['ResourceLimits' ]['MaxNumberOfTrainingJobs' ],
421
535
'max_parallel_jobs' : tuning_config ['ResourceLimits' ]['MaxParallelTrainingJobs' ],
536
+ 'warm_start_config' : WarmStartConfig .from_job_desc (job_details .get ('WarmStartConfig' , None ))
422
537
}
423
538
424
539
@classmethod
@@ -489,6 +604,82 @@ def _validate_parameter_ranges(self):
489
604
except KeyError :
490
605
pass
491
606
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
+
492
683
493
684
class _TuningJob (_Job ):
494
685
@classmethod
@@ -504,6 +695,10 @@ def start_new(cls, tuner, inputs):
504
695
"""
505
696
config = _Job ._load_config (inputs , tuner .estimator )
506
697
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
+
507
702
tuner .estimator .sagemaker_session .tune (job_name = tuner ._current_job_name , strategy = tuner .strategy ,
508
703
objective_type = tuner .objective_type ,
509
704
objective_metric_name = tuner .objective_metric_name ,
@@ -516,7 +711,8 @@ def start_new(cls, tuner, inputs):
516
711
role = (config ['role' ]), input_config = (config ['input_config' ]),
517
712
output_config = (config ['output_config' ]),
518
713
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 )
520
716
521
717
return cls (tuner .sagemaker_session , tuner ._current_job_name )
522
718
@@ -525,3 +721,50 @@ def stop(self):
525
721
526
722
def wait (self ):
527
723
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