Skip to content

Commit a1f6595

Browse files
authored
Merge branch 'master' into lm_fix_s3_download
2 parents 9c605e7 + e9ed907 commit a1f6595

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+5575
-2478
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ doc/_templates
2424
venv/
2525
*~
2626
.pytest_cache/
27+
*.swp

CHANGELOG.rst

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,29 @@
22
CHANGELOG
33
=========
44

5-
1.3.dev1
5+
1.4.2dev
66
========
77

8+
* bug-fix: Unit Tests: Improve unit test runtime
9+
* bug-fix: Estimators: Fix attach for LDA
10+
* bug-fix: Estimators: allow code_location to have no key prefix
11+
12+
1.4.1
13+
=====
14+
15+
* bug-fix: Local Mode: Fix for non Framework containers
16+
17+
1.4.0
18+
=====
19+
20+
* bug-fix: Remove __all__ and add noqa in __init__
821
* bug-fix: Estimators: Change max_iterations hyperparameter key for KMeans
22+
* bug-fix: Estimators: Remove unused argument job_details for ``EstimatorBase.attach()``
23+
* bug-fix: Local Mode: Show logs in Jupyter notebooks
24+
* feature: HyperparameterTuner: Add support for hyperparameter tuning jobs
25+
* feature: Analytics: Add functions for metrics in Training and Hyperparameter Tuning jobs
26+
* feature: Estimators: add support for tagging training jobs
27+
928

1029
1.3.0
1130
=====

README.rst

Lines changed: 80 additions & 2037 deletions
Large diffs are not rendered by default.

doc/analytics.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
Analytics
2+
---------
3+
4+
.. autoclass:: sagemaker.analytics.AnalyticsMetricsBase
5+
:members:
6+
:undoc-members:
7+
:show-inheritance:
8+
9+
.. autoclass:: sagemaker.analytics.HyperparameterTuningJobAnalytics
10+
:members:
11+
:undoc-members:
12+
:show-inheritance:
13+
14+
.. autoclass:: sagemaker.analytics.TrainingJobAnalytics
15+
:members:
16+
:undoc-members:
17+
:show-inheritance:

doc/index.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Amazon SageMaker Python SDK is an open source library for training and deploying
44

55
With the SDK, you can train and deploy models using popular deep learning frameworks: **Apache MXNet** and **TensorFlow**. You can also train and deploy models with **algorithms provided by Amazon**, these are scalable implementations of core machine learning algorithms that are optimized for SageMaker and GPU training. If you have **your own algorithms** built into SageMaker-compatible Docker containers, you can train and host models using these as well.
66

7-
Here you'll find API docs for SageMaker Python SDK. The project home-page is in Github: https://github.com/aws/sagemaker-python-sdk, there you can find the SDK source, installation instructions and a general overview of the library there.
7+
Here you'll find API docs for SageMaker Python SDK. The project home-page is in Github: https://github.com/aws/sagemaker-python-sdk, there you can find the SDK source, installation instructions and a general overview of the library there.
88

99
Overview
1010
----------
@@ -14,9 +14,11 @@ The SageMaker Python SDK consists of a few primary interfaces:
1414
:maxdepth: 2
1515

1616
estimators
17+
tuner
1718
predictors
1819
session
1920
model
21+
analytics
2022

2123
MXNet
2224
----------

doc/tuner.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
HyperparameterTuner
2+
-------------------
3+
4+
.. autoclass:: sagemaker.tuner.HyperparameterTuner
5+
:members:
6+
:undoc-members:
7+
:show-inheritance:
8+
9+
.. autoclass:: sagemaker.tuner.ContinuousParameter
10+
:members:
11+
:undoc-members:
12+
:show-inheritance:
13+
14+
.. autoclass:: sagemaker.tuner.IntegerParameter
15+
:members:
16+
:undoc-members:
17+
:show-inheritance:
18+
19+
.. autoclass:: sagemaker.tuner.CategoricalParameter
20+
:members:
21+
:undoc-members:
22+
:show-inheritance:

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def read(fname):
2323

2424

2525
setup(name="sagemaker",
26-
version="1.3.0",
26+
version="1.4.1",
2727
description="Open source library for training and deploying models on Amazon SageMaker.",
2828
packages=find_packages('src'),
2929
package_dir={'': 'src'},
@@ -49,7 +49,7 @@ def read(fname):
4949

5050
extras_require={
5151
'test': ['tox', 'flake8', 'pytest', 'pytest-cov', 'pytest-xdist',
52-
'mock', 'tensorflow>=1.3.0', 'contextlib2', 'awslogs']},
52+
'mock', 'tensorflow>=1.3.0', 'contextlib2', 'awslogs', 'pandas']},
5353

5454
entry_points={
5555
'console_scripts': ['sagemaker=sagemaker.cli.main:main'],

src/sagemaker/__init__.py

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,24 @@
1212
# language governing permissions and limitations under the License.
1313
from __future__ import absolute_import
1414

15-
from sagemaker import estimator
16-
from sagemaker.amazon.kmeans import KMeans, KMeansModel, KMeansPredictor
17-
from sagemaker.amazon.pca import PCA, PCAModel, PCAPredictor
18-
from sagemaker.amazon.lda import LDA, LDAModel, LDAPredictor
19-
from sagemaker.amazon.linear_learner import LinearLearner, LinearLearnerModel, LinearLearnerPredictor
20-
from sagemaker.amazon.factorization_machines import FactorizationMachines, FactorizationMachinesModel
21-
from sagemaker.amazon.factorization_machines import FactorizationMachinesPredictor
22-
from sagemaker.amazon.ntm import NTM, NTMModel, NTMPredictor
23-
from sagemaker.amazon.randomcutforest import RandomCutForest, RandomCutForestModel, RandomCutForestPredictor
15+
from sagemaker import estimator # noqa: F401
16+
from sagemaker.amazon.kmeans import KMeans, KMeansModel, KMeansPredictor # noqa: F401
17+
from sagemaker.amazon.pca import PCA, PCAModel, PCAPredictor # noqa: F401
18+
from sagemaker.amazon.lda import LDA, LDAModel, LDAPredictor # noqa: F401
19+
from sagemaker.amazon.linear_learner import LinearLearner, LinearLearnerModel, LinearLearnerPredictor # noqa: F401
20+
from sagemaker.amazon.factorization_machines import FactorizationMachines, FactorizationMachinesModel # noqa: F401
21+
from sagemaker.amazon.factorization_machines import FactorizationMachinesPredictor # noqa: F401
22+
from sagemaker.amazon.ntm import NTM, NTMModel, NTMPredictor # noqa: F401
23+
from sagemaker.amazon.randomcutforest import (RandomCutForest, RandomCutForestModel, # noqa: F401
24+
RandomCutForestPredictor)
2425

25-
from sagemaker.local.local_session import LocalSession
26+
from sagemaker.analytics import TrainingJobAnalytics, HyperparameterTuningJobAnalytics # noqa: F401
27+
from sagemaker.local.local_session import LocalSession # noqa: F401
2628

27-
from sagemaker.model import Model
28-
from sagemaker.predictor import RealTimePredictor
29-
from sagemaker.session import Session
30-
from sagemaker.session import container_def
31-
from sagemaker.session import production_variant
32-
from sagemaker.session import s3_input
33-
from sagemaker.session import get_execution_role
34-
35-
36-
__all__ = ['estimator', 'KMeans', 'KMeansModel', 'KMeansPredictor', 'PCA', 'PCAModel', 'PCAPredictor', 'LinearLearner',
37-
'LinearLearnerModel', 'LinearLearnerPredictor',
38-
'LDA', 'LDAModel', 'LDAPredictor',
39-
'FactorizationMachines', 'FactorizationMachinesModel', 'FactorizationMachinesPredictor',
40-
'RandomCutForest', 'RandomCutForestModel', 'RandomCutForestPredictor',
41-
'Model', 'NTM', 'NTMModel', 'NTMPredictor', 'RealTimePredictor', 'Session', 'LocalSession',
42-
'container_def', 's3_input', 'production_variant', 'get_execution_role']
29+
from sagemaker.model import Model # noqa: F401
30+
from sagemaker.predictor import RealTimePredictor # noqa: F401
31+
from sagemaker.session import Session # noqa: F401
32+
from sagemaker.session import container_def # noqa: F401
33+
from sagemaker.session import production_variant # noqa: F401
34+
from sagemaker.session import s3_input # noqa: F401
35+
from sagemaker.session import get_execution_role # noqa: F401

src/sagemaker/amazon/README.rst

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
2+
===================================
3+
AWS SageMaker Estimators and Models
4+
===================================
5+
6+
Amazon SageMaker provides several built-in machine learning algorithms that you can use for a variety of problem types.
7+
8+
The full list of algorithms is available on the AWS website: https://docs.aws.amazon.com/sagemaker/latest/dg/algos.html
9+
10+
SageMaker Python SDK includes Estimator wrappers for the AWS K-means, Principal Components Analysis(PCA), Linear Learner, Factorization Machines, Latent Dirichlet Allocation(LDA), Neural Topic Model(NTM) and Random Cut Forest algorithms.
11+
12+
Definition and usage
13+
~~~~~~~~~~~~~~~~~~~~
14+
Estimators that wrap Amazon's built-in algorithms define algorithm's hyperparameters with defaults. When a default is not possible you need to provide the value during construction, e.g.:
15+
16+
- ``KMeans`` Estimator requires parameter ``k`` to define number of clusters
17+
- ``PCA`` Estimator requires parameter ``num_components`` to define number of principal components
18+
19+
Interaction is identical as any other Estimators. There are additional details about how data is specified.
20+
21+
Input data format
22+
^^^^^^^^^^^^^^^^^
23+
Please note that Amazon's built-in algorithms are working best with protobuf ``recordIO`` format.
24+
The data is expected to be available in S3 location and depending on algorithm it can handle dat in multiple data channels.
25+
26+
This package offers support to prepare data into required fomrat and upload data to S3.
27+
Provided class ``RecordSet`` captures necessary details like S3 location, number of records, data channel and is expected as input parameter when calling ``fit()``.
28+
29+
Function ``record_set`` is available on algorithms objects to make it simple to achieve the above.
30+
It takes 2D numpy array as input, uploads data to S3 and returns ``RecordSet`` objects. By default it uses ``train`` data channel and no labels but can be specified when called.
31+
32+
Please find an example code snippet for illustration:
33+
34+
.. code:: python
35+
36+
from sagemaker import PCA
37+
pca_estimator = PCA(role='SageMakerRole', train_instance_count=1, train_instance_type='ml.m4.xlarge', num_components=3)
38+
39+
import numpy as np
40+
records = pca_estimator.record_set(np.arange(10).reshape(2,5))
41+
42+
pca_estimator.fit(records)
43+
44+
45+
Predictions support
46+
~~~~~~~~~~~~~~~~~~~
47+
Calling inference on deployed Amazon's built-in algorithms requires specific input format. By default, this library creates a predictor that allows to use just numpy data.
48+
Data is converted so that ``application/x-recordio-protobuf`` input format is used. Received response is deserialized from the protobuf and provided as result from the ``predict`` call.

src/sagemaker/amazon/amazon_estimator.py

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from sagemaker.amazon import validation
2020
from sagemaker.amazon.hyperparameter import Hyperparameter as hp # noqa
2121
from sagemaker.amazon.common import write_numpy_to_dense_tensor
22-
from sagemaker.estimator import EstimatorBase
22+
from sagemaker.estimator import EstimatorBase, _TrainingJob
2323
from sagemaker.session import s3_input
2424
from sagemaker.utils import sagemaker_timestamp
2525

@@ -92,11 +92,38 @@ def _prepare_init_params_from_job_description(cls, job_details):
9292
del init_params['image']
9393
return init_params
9494

95-
def fit(self, records, mini_batch_size=None, **kwargs):
95+
def _prepare_for_training(self, records, mini_batch_size=None, job_name=None):
96+
"""Set hyperparameters needed for training.
97+
98+
Args:
99+
* records (:class:`~RecordSet`): The records to train this ``Estimator`` on.
100+
* mini_batch_size (int or None): The size of each mini-batch to use when training. If ``None``, a
101+
default value will be used.
102+
* job_name (str): Name of the training job to be created. If not specified, one is generated,
103+
using the base name given to the constructor if applicable.
104+
"""
105+
super(AmazonAlgorithmEstimatorBase, self)._prepare_for_training(job_name=job_name)
106+
107+
feature_dim = None
108+
109+
if isinstance(records, list):
110+
for record in records:
111+
if record.channel == 'train':
112+
feature_dim = record.feature_dim
113+
break
114+
if feature_dim is None:
115+
raise ValueError('Must provide train channel.')
116+
else:
117+
feature_dim = records.feature_dim
118+
119+
self.feature_dim = feature_dim
120+
self.mini_batch_size = mini_batch_size
121+
122+
def fit(self, records, mini_batch_size=None, wait=True, logs=True, job_name=None):
96123
"""Fit this Estimator on serialized Record objects, stored in S3.
97124
98125
``records`` should be an instance of :class:`~RecordSet`. This defines a collection of
99-
s3 data files to train this ``Estimator`` on.
126+
S3 data files to train this ``Estimator`` on.
100127
101128
Training data is expected to be encoded as dense or sparse vectors in the "values" feature
102129
on each Record. If the data is labeled, the label is expected to be encoded as a list of
@@ -110,15 +137,19 @@ def fit(self, records, mini_batch_size=None, **kwargs):
110137
111138
Args:
112139
records (:class:`~RecordSet`): The records to train this ``Estimator`` on
113-
mini_batch_size (int or None): The size of each mini-batch to use when training. If None, a
140+
mini_batch_size (int or None): The size of each mini-batch to use when training. If ``None``, a
114141
default value will be used.
142+
wait (bool): Whether the call should wait until the job completes (default: True).
143+
logs (bool): Whether to show the logs produced by the job.
144+
Only meaningful when wait is True (default: True).
145+
job_name (str): Training job name. If not specified, the estimator generates a default job name,
146+
based on the training image name and current timestamp.
115147
"""
116-
self.feature_dim = records.feature_dim
117-
self.mini_batch_size = mini_batch_size
148+
self._prepare_for_training(records, job_name=job_name, mini_batch_size=mini_batch_size)
118149

119-
data = {records.channel: s3_input(records.s3_data, distribution='ShardedByS3Key',
120-
s3_data_type=records.s3_data_type)}
121-
super(AmazonAlgorithmEstimatorBase, self).fit(data, **kwargs)
150+
self.latest_training_job = _TrainingJob.start_new(self, records)
151+
if wait:
152+
self.latest_training_job.wait(logs=logs)
122153

123154
def record_set(self, train, labels=None, channel="train"):
124155
"""Build a :class:`~RecordSet` from a numpy :class:`~ndarray` matrix and label vector.
@@ -180,6 +211,14 @@ def __repr__(self):
180211
"""Return an unambiguous representation of this RecordSet"""
181212
return str((RecordSet, self.__dict__))
182213

214+
def data_channel(self):
215+
"""Return a dictionary to represent the training data in a channel for use with ``fit()``"""
216+
return {self.channel: self.records_s3_input()}
217+
218+
def records_s3_input(self):
219+
"""Return a s3_input to represent the training data"""
220+
return s3_input(self.s3_data, distribution='ShardedByS3Key', s3_data_type=self.s3_data_type)
221+
183222

184223
def _build_shards(num_shards, array):
185224
if num_shards < 1:

src/sagemaker/amazon/hyperparameter.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ def validate(self, value):
4646
raise ValueError(error_message)
4747

4848
def __get__(self, obj, objtype):
49-
"""Return the value of this hyperparameter"""
5049
if '_hyperparameters' not in dir(obj) or self.name not in obj._hyperparameters:
5150
raise AttributeError()
5251
return obj._hyperparameters[self.name]

src/sagemaker/amazon/kmeans.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ def create_model(self):
108108
s3 model data produced by this Estimator."""
109109
return KMeansModel(self.model_data, self.role, self.sagemaker_session)
110110

111-
def fit(self, records, mini_batch_size=5000, **kwargs):
112-
super(KMeans, self).fit(records, mini_batch_size, **kwargs)
111+
def _prepare_for_training(self, records, mini_batch_size=5000, job_name=None):
112+
super(KMeans, self)._prepare_for_training(records, mini_batch_size=mini_batch_size, job_name=job_name)
113113

114114
def hyperparameters(self):
115115
"""Return the SageMaker hyperparameters for training this KMeans Estimator"""

src/sagemaker/amazon/lda.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,10 @@ def __init__(self, role, train_instance_type, num_topics,
7878
tol (float): Optional. Target error tolerance for the ALS phase of the algorithm.
7979
**kwargs: base class keyword argument values.
8080
"""
81-
8281
# this algorithm only supports single instance training
82+
if kwargs.pop('train_instance_count', 1) != 1:
83+
print('LDA only supports single instance training. Defaulting to 1 {}.'.format(train_instance_type))
84+
8385
super(LDA, self).__init__(role, 1, train_instance_type, **kwargs)
8486
self.num_topics = num_topics
8587
self.alpha0 = alpha0
@@ -93,11 +95,12 @@ def create_model(self):
9395

9496
return LDAModel(self.model_data, self.role, sagemaker_session=self.sagemaker_session)
9597

96-
def fit(self, records, mini_batch_size, **kwargs):
98+
def _prepare_for_training(self, records, mini_batch_size, job_name=None):
9799
# mini_batch_size is required, prevent explicit calls with None
98100
if mini_batch_size is None:
99101
raise ValueError("mini_batch_size must be set")
100-
super(LDA, self).fit(records, mini_batch_size, **kwargs)
102+
103+
super(LDA, self)._prepare_for_training(records, mini_batch_size=mini_batch_size, job_name=job_name)
101104

102105

103106
class LDAPredictor(RealTimePredictor):

src/sagemaker/amazon/linear_learner.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,12 +228,23 @@ def create_model(self):
228228

229229
return LinearLearnerModel(self.model_data, self.role, self.sagemaker_session)
230230

231-
def fit(self, records, mini_batch_size=None, **kwargs):
231+
def _prepare_for_training(self, records, mini_batch_size=None, job_name=None):
232+
num_records = None
233+
if isinstance(records, list):
234+
for record in records:
235+
if record.channel == 'train':
236+
num_records = record.num_records
237+
break
238+
if num_records is None:
239+
raise ValueError('Must provide train channel.')
240+
else:
241+
num_records = records.num_records
242+
232243
# mini_batch_size can't be greater than number of records or training job fails
233244
default_mini_batch_size = min(self.DEFAULT_MINI_BATCH_SIZE,
234-
max(1, int(records.num_records / self.train_instance_count)))
235-
use_mini_batch_size = mini_batch_size or default_mini_batch_size
236-
super(LinearLearner, self).fit(records, use_mini_batch_size, **kwargs)
245+
max(1, int(num_records / self.train_instance_count)))
246+
mini_batch_size = mini_batch_size or default_mini_batch_size
247+
super(LinearLearner, self)._prepare_for_training(records, mini_batch_size=mini_batch_size, job_name=job_name)
237248

238249

239250
class LinearLearnerPredictor(RealTimePredictor):

src/sagemaker/amazon/ntm.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,10 @@ def create_model(self):
113113

114114
return NTMModel(self.model_data, self.role, sagemaker_session=self.sagemaker_session)
115115

116-
def fit(self, records, mini_batch_size=None, **kwargs):
116+
def _prepare_for_training(self, records, mini_batch_size, job_name=None):
117117
if mini_batch_size is not None and (mini_batch_size < 1 or mini_batch_size > 10000):
118118
raise ValueError("mini_batch_size must be in [1, 10000]")
119-
super(NTM, self).fit(records, mini_batch_size, **kwargs)
119+
super(NTM, self)._prepare_for_training(records, mini_batch_size=mini_batch_size, job_name=job_name)
120120

121121

122122
class NTMPredictor(RealTimePredictor):

0 commit comments

Comments
 (0)