Skip to content

Commit 002e75a

Browse files
authored
Merge branch 'master' into doc-xgboost-byom
2 parents c32de01 + 6b0e009 commit 002e75a

File tree

10 files changed

+215
-10
lines changed

10 files changed

+215
-10
lines changed

CHANGELOG.md

+31
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,36 @@
11
# Changelog
22

3+
## v1.70.2 (2020-07-22)
4+
5+
### Bug Fixes and Other Changes
6+
7+
* convert network_config in processing_config to dict
8+
9+
### Documentation Changes
10+
11+
* Add ECR URI Estimator example
12+
13+
## v1.70.1 (2020-07-21)
14+
15+
### Bug Fixes and Other Changes
16+
17+
* Nullable fields in processing_config
18+
19+
## v1.70.0 (2020-07-20)
20+
21+
### Features
22+
23+
* Add model monitor support for us-gov-west-1
24+
* support TFS 2.2
25+
26+
### Bug Fixes and Other Changes
27+
28+
* reshape Artifacts into data frame in ExperimentsAnalytics
29+
30+
### Documentation Changes
31+
32+
* fix MXNet version info for requirements.txt support
33+
334
## v1.69.0 (2020-07-09)
435

536
### Features

VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.69.1.dev0
1+
1.70.3.dev0

doc/frameworks/mxnet/using_mxnet.rst

+4-3
Original file line numberDiff line numberDiff line change
@@ -321,13 +321,14 @@ If there are other packages you want to use with your script, you can include a
321321
Both ``requirements.txt`` and your training script should be put in the same folder.
322322
You must specify this folder in ``source_dir`` argument when creating an MXNet estimator.
323323

324-
The function of installing packages using ``requirements.txt`` is supported for all MXNet versions during training.
324+
The function of installing packages using ``requirements.txt`` is supported for MXNet versions 1.3.0 and higher during training.
325+
325326
When serving an MXNet model, support for this function varies with MXNet versions.
326327
For MXNet 1.6.0 or newer, ``requirements.txt`` must be under folder ``code``.
327328
The SageMaker MXNet Estimator automatically saves ``code`` in ``model.tar.gz`` after training (assuming you set up your script and ``requirements.txt`` correctly as stipulated in the previous paragraph).
328329
In the case of bringing your own trained model for deployment, you must save ``requirements.txt`` under folder ``code`` in ``model.tar.gz`` yourself or specify it through ``dependencies``.
329-
For MXNet 1.4.1, ``requirements.txt`` is not supported for inference.
330-
For MXNet 0.12.1-1.3.0, ``requirements.txt`` must be in ``source_dir``.
330+
For MXNet 0.12.1-1.2.1, 1.4.0-1.4.1, ``requirements.txt`` is not supported for inference.
331+
For MXNet 1.3.0, ``requirements.txt`` must be in ``source_dir``.
331332

332333
A ``requirements.txt`` file is a text file that contains a list of items that are installed by using ``pip install``.
333334
You can also specify the version of an item to install.

doc/frameworks/tensorflow/using_tf.rst

+22
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,28 @@ The following args are not permitted when using Script Mode:
197197
Where the S3 url is a path to your training data within Amazon S3.
198198
The constructor keyword arguments define how SageMaker runs your training script.
199199

200+
Specify a Docker image using an Estimator
201+
-----------------------------------------
202+
203+
There are use cases, such as extending an existing pre-built Amazon SageMaker images, that require specifing a Docker image when creating an Estimator by directly specifying the ECR URI instead of the Python and framework version. For a full list of available container URIs, see `Available Deep Learning Containers Images <https://github.com/aws/deep-learning-containers/blob/master/available_images.md>`__ For more information on using Docker containers, see `Use Your Own Algorithms or Models with Amazon SageMaker <https://docs.aws.amazon.com/sagemaker/latest/dg/your-algorithms.html>`__.
204+
205+
When specifying the image, you must use the ``image_name=''`` arg to replace the following arg:
206+
207+
- ``py_version=''``
208+
209+
You should still specify the ``framework_version=''`` arg because the SageMaker Python SDK accomodates for differences in the images based on the version.
210+
211+
The following example uses the ``image_name=''`` arg to specify the container image, Python version, and framework version.
212+
213+
.. code:: python
214+
215+
tf_estimator = TensorFlow(entry_point='tf-train.py',
216+
role='SageMakerRole',
217+
train_instance_count=1,
218+
train_instance_type='ml.p2.xlarge',
219+
image_name='763104351884.dkr.ecr.<region>.amazonaws.com/<framework>-<job type>:<framework version>-<cpu/gpu>-<python version>-ubuntu18.04',
220+
script_mode=True)
221+
200222
For more information about the sagemaker.tensorflow.TensorFlow estimator, see `SageMaker TensorFlow Classes`_.
201223

202224
Call the fit Method

src/sagemaker/analytics.py

+34
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,8 @@ def __init__(
431431
metric_names=None,
432432
parameter_names=None,
433433
sagemaker_session=None,
434+
input_artifact_names=None,
435+
output_artifact_names=None,
434436
):
435437
"""Initialize a ``ExperimentAnalytics`` instance.
436438
@@ -450,6 +452,11 @@ def __init__(
450452
sagemaker_session (sagemaker.session.Session): Session object which manages interactions
451453
with Amazon SageMaker APIs and any other AWS services needed. If not specified,
452454
one is created using the default AWS configuration chain.
455+
input_artifact_names(dict optional):The input artifacts for the experiment. Examples of
456+
input artifacts are datasets, algorithms, hyperparameters, source code, and instance
457+
types.
458+
output_artifact_names(dict optional): The output artifacts for the experiment. Examples
459+
of output artifacts are metrics, snapshots, logs, and images.
453460
"""
454461
sagemaker_session = sagemaker_session or Session()
455462
self._sage_client = sagemaker_session.sagemaker_client
@@ -463,6 +470,8 @@ def __init__(
463470
self._sort_order = sort_order
464471
self._metric_names = metric_names
465472
self._parameter_names = parameter_names
473+
self._input_artifact_names = input_artifact_names
474+
self._output_artifact_names = output_artifact_names
466475
self._trial_components = None
467476
super(ExperimentAnalytics, self).__init__()
468477
self.clear_cache()
@@ -516,6 +525,21 @@ def _reshape_metrics(self, metrics):
516525
out["{} - {}".format(metric_name, stat_type)] = stat_value
517526
return out
518527

528+
def _reshape_artifacts(self, artifacts, _artifact_names):
529+
"""Reshape trial component input/output artifacts to a pandas column
530+
Args:
531+
artifacts: trial component input/output artifacts
532+
Returns:
533+
dict: Key: artifacts name, Value: artifacts value
534+
"""
535+
out = OrderedDict()
536+
for name, value in sorted(artifacts.items()):
537+
if _artifact_names and (name not in _artifact_names):
538+
continue
539+
out["{} - {}".format(name, "MediaType")] = value.get("MediaType")
540+
out["{} - {}".format(name, "Value")] = value.get("Value")
541+
return out
542+
519543
def _reshape(self, trial_component):
520544
"""Reshape trial component data to pandas columns
521545
Args:
@@ -533,6 +557,16 @@ def _reshape(self, trial_component):
533557

534558
out.update(self._reshape_parameters(trial_component.get("Parameters", [])))
535559
out.update(self._reshape_metrics(trial_component.get("Metrics", [])))
560+
out.update(
561+
self._reshape_artifacts(
562+
trial_component.get("InputArtifacts", []), self._input_artifact_names
563+
)
564+
)
565+
out.update(
566+
self._reshape_artifacts(
567+
trial_component.get("OutputArtifacts", []), self._output_artifact_names
568+
)
569+
)
536570
return out
537571

538572
def _fetch_dataframe(self):

src/sagemaker/model_monitor/model_monitoring.py

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"ca-central-1": "536280801234",
5858
"cn-north-1": "453000072557",
5959
"cn-northwest-1": "453252182341",
60+
"us-gov-west-1": "362178532790",
6061
}
6162

6263
STATISTICS_JSON_DEFAULT_FILE_NAME = "statistics.json"

src/sagemaker/workflow/airflow.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -1144,7 +1144,7 @@ def processing_config(
11441144
config["Environment"] = processor.env
11451145

11461146
if processor.network_config is not None:
1147-
config["NetworkConfig"] = processor.network_config
1147+
config["NetworkConfig"] = processor.network_config._to_request_dict()
11481148

11491149
processing_resources = sagemaker.processing.ProcessingJob.prepare_processing_resources(
11501150
instance_count=processor.instance_count,
@@ -1154,10 +1154,11 @@ def processing_config(
11541154
)
11551155
config["ProcessingResources"] = processing_resources
11561156

1157-
stopping_condition = sagemaker.processing.ProcessingJob.prepare_stopping_condition(
1158-
processor.max_runtime_in_seconds
1159-
)
1160-
config["StoppingCondition"] = stopping_condition
1157+
if processor.max_runtime_in_seconds is not None:
1158+
stopping_condition = sagemaker.processing.ProcessingJob.prepare_stopping_condition(
1159+
processor.max_runtime_in_seconds
1160+
)
1161+
config["StoppingCondition"] = stopping_condition
11611162

11621163
if processor.tags is not None:
11631164
config["Tags"] = processor.tags
@@ -1174,4 +1175,6 @@ def input_output_list_converter(object_list):
11741175
Returns:
11751176
List of dicts
11761177
"""
1177-
return [obj._to_request_dict() for obj in object_list]
1178+
if object_list:
1179+
return [obj._to_request_dict() for obj in object_list]
1180+
return object_list

tests/integ/test_experiments_analytics.py

+59
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,65 @@ def experiment(sagemaker_session):
4343
_delete_resources(sm, experiment_name, trials)
4444

4545

46+
@contextmanager
47+
def experiment_with_artifacts(sagemaker_session):
48+
sm = sagemaker_session.sagemaker_client
49+
trials = {} # for resource cleanup
50+
51+
experiment_name = "experiment-" + str(uuid.uuid4())
52+
try:
53+
sm.create_experiment(ExperimentName=experiment_name)
54+
55+
# Search returns 10 results by default. Add 20 trials to verify pagination.
56+
for i in range(20):
57+
trial_name = "trial-" + str(uuid.uuid4())
58+
sm.create_trial(TrialName=trial_name, ExperimentName=experiment_name)
59+
60+
trial_component_name = "tc-" + str(uuid.uuid4())
61+
trials[trial_name] = trial_component_name
62+
63+
sm.create_trial_component(
64+
TrialComponentName=trial_component_name, DisplayName="Training"
65+
)
66+
sm.update_trial_component(
67+
TrialComponentName=trial_component_name,
68+
Parameters={"hp1": {"NumberValue": i}},
69+
InputArtifacts={
70+
"inputArtifacts1": {"MediaType": "text/csv", "Value": "s3:/foo/bar1"}
71+
},
72+
OutputArtifacts={
73+
"outputArtifacts1": {"MediaType": "text/plain", "Value": "s3:/foo/bar2"}
74+
},
75+
)
76+
sm.associate_trial_component(
77+
TrialComponentName=trial_component_name, TrialName=trial_name
78+
)
79+
80+
time.sleep(15) # wait for search to get updated
81+
82+
yield experiment_name
83+
finally:
84+
_delete_resources(sm, experiment_name, trials)
85+
86+
87+
@pytest.mark.canary_quick
88+
def test_experiment_analytics_artifacts(sagemaker_session):
89+
with experiment_with_artifacts(sagemaker_session) as experiment_name:
90+
analytics = ExperimentAnalytics(
91+
experiment_name=experiment_name, sagemaker_session=sagemaker_session
92+
)
93+
94+
assert list(analytics.dataframe().columns) == [
95+
"TrialComponentName",
96+
"DisplayName",
97+
"hp1",
98+
"inputArtifacts1 - MediaType",
99+
"inputArtifacts1 - Value",
100+
"outputArtifacts1 - MediaType",
101+
"outputArtifacts1 - Value",
102+
]
103+
104+
46105
@pytest.mark.canary_quick
47106
def test_experiment_analytics(sagemaker_session):
48107
with experiment(sagemaker_session) as experiment_name:

tests/unit/test_airflow.py

+14
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from mock import Mock, MagicMock, patch
1717

1818
from sagemaker import chainer, estimator, model, mxnet, tensorflow, transformer, tuner, processing
19+
from sagemaker.network import NetworkConfig
1920
from sagemaker.processing import ProcessingInput, ProcessingOutput
2021
from sagemaker.workflow import airflow
2122
from sagemaker.amazon import amazon_estimator
@@ -1598,6 +1599,13 @@ def test_deploy_config_from_amazon_alg_estimator(sagemaker_session):
15981599
@patch("sagemaker.utils.sagemaker_timestamp", MagicMock(return_value=TIME_STAMP))
15991600
def test_processing_config(sagemaker_session):
16001601

1602+
network_config = NetworkConfig(
1603+
encrypt_inter_container_traffic=False,
1604+
enable_network_isolation=True,
1605+
security_group_ids=["sg1"],
1606+
subnets=["subnet1"],
1607+
)
1608+
16011609
processor = processing.Processor(
16021610
role="arn:aws:iam::0122345678910:role/SageMakerPowerUser",
16031611
image_uri="{{ image_uri }}",
@@ -1612,6 +1620,7 @@ def test_processing_config(sagemaker_session):
16121620
sagemaker_session=sagemaker_session,
16131621
tags=[{"{{ key }}": "{{ value }}"}],
16141622
env={"{{ key }}": "{{ value }}"},
1623+
network_config=network_config,
16151624
)
16161625

16171626
outputs = [
@@ -1699,5 +1708,10 @@ def test_processing_config(sagemaker_session):
16991708
"RoleArn": "arn:aws:iam::0122345678910:role/SageMakerPowerUser",
17001709
"StoppingCondition": {"MaxRuntimeInSeconds": 3600},
17011710
"Tags": [{"{{ key }}": "{{ value }}"}],
1711+
"NetworkConfig": {
1712+
"EnableInterContainerTrafficEncryption": False,
1713+
"EnableNetworkIsolation": True,
1714+
"VpcConfig": {"SecurityGroupIds": ["sg1"], "Subnets": ["subnet1"]},
1715+
},
17021716
}
17031717
assert config == expected_config

tests/unit/test_experiments_analytics.py

+40
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ def trial_component(trial_component_name):
4040
"Count": 2.0,
4141
},
4242
],
43+
"InputArtifacts": {
44+
"inputArtifacts1": {"MediaType": "text/plain", "Value": "s3:/foo/bar1"},
45+
"inputArtifacts2": {"MediaType": "text/plain", "Value": "s3:/foo/bar2"},
46+
},
47+
"OutputArtifacts": {
48+
"outputArtifacts1": {"MediaType": "text/csv", "Value": "s3:/sky/far1"},
49+
"outputArtifacts2": {"MediaType": "text/csv", "Value": "s3:/sky/far2"},
50+
},
4351
}
4452

4553

@@ -72,6 +80,14 @@ def test_trial_analytics_dataframe_all_metrics_hyperparams(mock_session):
7280
("metric2 - StdDev", [0.05, 0.05]),
7381
("metric2 - Last", [7.0, 7.0]),
7482
("metric2 - Count", [2.0, 2.0]),
83+
("inputArtifacts1 - MediaType", ["text/plain", "text/plain"]),
84+
("inputArtifacts1 - Value", ["s3:/foo/bar1", "s3:/foo/bar1"]),
85+
("inputArtifacts2 - MediaType", ["text/plain", "text/plain"]),
86+
("inputArtifacts2 - Value", ["s3:/foo/bar2", "s3:/foo/bar2"]),
87+
("outputArtifacts1 - MediaType", ["text/csv", "text/csv"]),
88+
("outputArtifacts1 - Value", ["s3:/sky/far1", "s3:/sky/far1"]),
89+
("outputArtifacts2 - MediaType", ["text/csv", "text/csv"]),
90+
("outputArtifacts2 - Value", ["s3:/sky/far2", "s3:/sky/far2"]),
7591
]
7692
)
7793
)
@@ -117,6 +133,14 @@ def test_trial_analytics_dataframe_selected_hyperparams(mock_session):
117133
("metric2 - StdDev", [0.05, 0.05]),
118134
("metric2 - Last", [7.0, 7.0]),
119135
("metric2 - Count", [2.0, 2.0]),
136+
("inputArtifacts1 - MediaType", ["text/plain", "text/plain"]),
137+
("inputArtifacts1 - Value", ["s3:/foo/bar1", "s3:/foo/bar1"]),
138+
("inputArtifacts2 - MediaType", ["text/plain", "text/plain"]),
139+
("inputArtifacts2 - Value", ["s3:/foo/bar2", "s3:/foo/bar2"]),
140+
("outputArtifacts1 - MediaType", ["text/csv", "text/csv"]),
141+
("outputArtifacts1 - Value", ["s3:/sky/far1", "s3:/sky/far1"]),
142+
("outputArtifacts2 - MediaType", ["text/csv", "text/csv"]),
143+
("outputArtifacts2 - Value", ["s3:/sky/far2", "s3:/sky/far2"]),
120144
]
121145
)
122146
)
@@ -157,6 +181,14 @@ def test_trial_analytics_dataframe_selected_metrics(mock_session):
157181
("metric1 - StdDev", [1.0, 1.0]),
158182
("metric1 - Last", [2.0, 2.0]),
159183
("metric1 - Count", [2.0, 2.0]),
184+
("inputArtifacts1 - MediaType", ["text/plain", "text/plain"]),
185+
("inputArtifacts1 - Value", ["s3:/foo/bar1", "s3:/foo/bar1"]),
186+
("inputArtifacts2 - MediaType", ["text/plain", "text/plain"]),
187+
("inputArtifacts2 - Value", ["s3:/foo/bar2", "s3:/foo/bar2"]),
188+
("outputArtifacts1 - MediaType", ["text/csv", "text/csv"]),
189+
("outputArtifacts1 - Value", ["s3:/sky/far1", "s3:/sky/far1"]),
190+
("outputArtifacts2 - MediaType", ["text/csv", "text/csv"]),
191+
("outputArtifacts2 - Value", ["s3:/sky/far2", "s3:/sky/far2"]),
160192
]
161193
)
162194
)
@@ -203,6 +235,14 @@ def test_trial_analytics_dataframe_search_pagination(mock_session):
203235
("metric2 - StdDev", [0.05, 0.05]),
204236
("metric2 - Last", [7.0, 7.0]),
205237
("metric2 - Count", [2.0, 2.0]),
238+
("inputArtifacts1 - MediaType", ["text/plain", "text/plain"]),
239+
("inputArtifacts1 - Value", ["s3:/foo/bar1", "s3:/foo/bar1"]),
240+
("inputArtifacts2 - MediaType", ["text/plain", "text/plain"]),
241+
("inputArtifacts2 - Value", ["s3:/foo/bar2", "s3:/foo/bar2"]),
242+
("outputArtifacts1 - MediaType", ["text/csv", "text/csv"]),
243+
("outputArtifacts1 - Value", ["s3:/sky/far1", "s3:/sky/far1"]),
244+
("outputArtifacts2 - MediaType", ["text/csv", "text/csv"]),
245+
("outputArtifacts2 - Value", ["s3:/sky/far2", "s3:/sky/far2"]),
206246
]
207247
)
208248
)

0 commit comments

Comments
 (0)