diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7ea6ec3914..78e900a61b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,13 +2,13 @@ CHANGELOG ========= - -1.18.5.dev -========== +1.18.5 +====== * bug-fix: pass kms id as parameter for uploading code with Server side encryption * feature: ``PipelineModel``: Create a Transformer from a PipelineModel * bug-fix: ``AlgorithmEstimator``: Make SupportedHyperParameters optional +* feature: ``Hyperparameter``: Support scaling hyperparameters * doc-fix: Remove duplicate content from main README.rst, /tensorflow/README.rst, and /sklearn/README.rst and add links to readthedocs content 1.18.4 diff --git a/setup.py b/setup.py index 3ce73d4038..53d295b9a7 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,7 @@ def read(fname): required_packages.append('enum34>=1.1.6') setup(name="sagemaker", - version='1.18.4', + version='1.18.5', description="Open source library for training and deploying models on Amazon SageMaker.", packages=find_packages('src'), package_dir={'': 'src'}, diff --git a/src/sagemaker/parameter.py b/src/sagemaker/parameter.py index f3c69ab013..69e74941f3 100644 --- a/src/sagemaker/parameter.py +++ b/src/sagemaker/parameter.py @@ -25,15 +25,18 @@ class ParameterRange(object): __all_types__ = ('Continuous', 'Categorical', 'Integer') - def __init__(self, min_value, max_value): + def __init__(self, min_value, max_value, scaling_type='Auto'): """Initialize a parameter range. Args: min_value (float or int): The minimum value for the range. max_value (float or int): The maximum value for the range. + scaling_type (str): The scale used for searching the range during tuning (default: 'Auto'). + Valid values: 'Auto', 'Linear', 'Logarithmic' and 'ReverseLogarithmic'. """ self.min_value = min_value self.max_value = max_value + self.scaling_type = scaling_type def is_valid(self, value): """Determine if a value is valid within this ParameterRange. @@ -62,7 +65,8 @@ def as_tuning_range(self, name): """ return {'Name': name, 'MinValue': to_str(self.min_value), - 'MaxValue': to_str(self.max_value)} + 'MaxValue': to_str(self.max_value), + 'ScalingType': self.scaling_type} class ContinuousParameter(ParameterRange): diff --git a/src/sagemaker/tuner.py b/src/sagemaker/tuner.py index 29d3d092b1..bfbd566e81 100644 --- a/src/sagemaker/tuner.py +++ b/src/sagemaker/tuner.py @@ -512,17 +512,23 @@ def _validate_parameter_ranges(self): parameter_range = self._hyperparameter_ranges[value.name] if isinstance(parameter_range, ParameterRange): - for _, parameter_range_value in parameter_range.__dict__.items(): - # Categorical ranges - if isinstance(parameter_range_value, list): - for categorical_value in parameter_range_value: - value.validate(categorical_value) - # Continuous, Integer ranges - else: - value.validate(parameter_range_value) + self._validate_parameter_range(value, parameter_range) except KeyError: pass + def _validate_parameter_range(self, value_hp, parameter_range): + for parameter_range_key, parameter_range_value in parameter_range.__dict__.items(): + if parameter_range_key == 'scaling_type': + continue + + # Categorical ranges + if isinstance(parameter_range_value, list): + for categorical_value in parameter_range_value: + value_hp.validate(categorical_value) + # Continuous, Integer ranges + else: + value_hp.validate(parameter_range_value) + def transfer_learning_tuner(self, additional_parents=None, estimator=None): """Creates a new ``HyperparameterTuner`` by copying the request fields from the provided parent to the new instance of ``HyperparameterTuner``. Followed by addition of warm start configuration with the type as diff --git a/tests/unit/test_airflow.py b/tests/unit/test_airflow.py index 9610c55357..d038415f4a 100644 --- a/tests/unit/test_airflow.py +++ b/tests/unit/test_airflow.py @@ -502,7 +502,8 @@ def test_framework_tuning_config(sagemaker_session): 'ContinuousParameterRanges': [{ 'Name': 'learning_rate', 'MinValue': '0.01', - 'MaxValue': '0.2'}], + 'MaxValue': '0.2', + 'ScalingType': 'Auto'}], 'CategoricalParameterRanges': [{ 'Name': 'optimizer', 'Values': ['"sgd"', '"Adam"'] @@ -510,7 +511,8 @@ def test_framework_tuning_config(sagemaker_session): 'IntegerParameterRanges': [{ 'Name': 'num_epoch', 'MinValue': '10', - 'MaxValue': '50' + 'MaxValue': '50', + 'ScalingType': 'Auto' }] }}, 'TrainingJobDefinition': { diff --git a/tests/unit/test_tuner.py b/tests/unit/test_tuner.py index 4fec84965e..58e19e8d32 100644 --- a/tests/unit/test_tuner.py +++ b/tests/unit/test_tuner.py @@ -71,6 +71,7 @@ 'MaxValue': '100', 'Name': 'mini_batch_size', 'MinValue': '10', + 'ScalingType': 'Auto' }, ] }, @@ -631,10 +632,17 @@ def test_continuous_parameter(): def test_continuous_parameter_ranges(): cont_param = ContinuousParameter(0.1, 1e-2) ranges = cont_param.as_tuning_range('some') - assert len(ranges.keys()) == 3 + assert len(ranges.keys()) == 4 assert ranges['Name'] == 'some' assert ranges['MinValue'] == '0.1' assert ranges['MaxValue'] == '0.01' + assert ranges['ScalingType'] == 'Auto' + + +def test_continuous_parameter_scaling_type(): + cont_param = ContinuousParameter(0.1, 2, scaling_type='ReverseLogarithmic') + cont_range = cont_param.as_tuning_range('range') + assert cont_range['ScalingType'] == 'ReverseLogarithmic' def test_integer_parameter(): @@ -646,10 +654,17 @@ def test_integer_parameter(): def test_integer_parameter_ranges(): int_param = IntegerParameter(1, 2) ranges = int_param.as_tuning_range('some') - assert len(ranges.keys()) == 3 + assert len(ranges.keys()) == 4 assert ranges['Name'] == 'some' assert ranges['MinValue'] == '1' assert ranges['MaxValue'] == '2' + assert ranges['ScalingType'] == 'Auto' + + +def test_integer_parameter_scaling_type(): + int_param = IntegerParameter(2, 3, scaling_type='Linear') + int_range = int_param.as_tuning_range('range') + assert int_range['ScalingType'] == 'Linear' def test_categorical_parameter_list():