Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
249e0d6
Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 24, 2018
8401afa
Addressing comments for Bug fix for getting dataframes in TrainingJob…
Oct 25, 2018
42d2741
Unit tests for Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 25, 2018
1640264
Merge branch 'master' into TrainingJobAnalytics
laurenyu Oct 26, 2018
d43047d
updating change log for Bug fix for getting dataframes in TrainingJob…
Nov 4, 2018
c55e7ca
Add model parameters to Estimator, and bump library version to 1.13.0…
RodrigoAtAWS Nov 1, 2018
5bdb50a
local mode: improve training input/output (#449)
iquintero Nov 2, 2018
3d103b4
Add image URIs for built-in Algorithms for SIN/LHR/BOM/SFO/YUL (#456)
pdasamzn Nov 5, 2018
23851b1
Support MXNet 1.3 with its training script format changes (#446)
laurenyu Nov 5, 2018
bd1f43b
Make InputDataConfig optional for training. (#459)
nadiaya Nov 6, 2018
2edcc3a
add tfs container support (#460)
jesterhazy Nov 7, 2018
10b7e42
simplify create_image_uri function (#462)
jesterhazy Nov 7, 2018
e8bf717
bump version to 1.14.0 (#463)
jesterhazy Nov 7, 2018
eea2ad5
Skip gpu tests in regions without ml.p2.xlarge (#461)
yangaws Nov 7, 2018
c8147a9
Adding Object2Vec support to SageMaker Python SDK (#467)
pnpnpn Nov 8, 2018
52d1ec4
fix readme rendering (#464)
jesterhazy Nov 8, 2018
3a69cf6
Add Pylint (#465)
iquintero Nov 8, 2018
9a997a5
Support optional input channels in local mode. (#466)
nadiaya Nov 9, 2018
6a1d93c
build: upgrade docker-compose to 1.23 (#470)
iquintero Nov 9, 2018
876287e
add tensorflow serving docs (#468)
jesterhazy Nov 10, 2018
0c4ad9c
Very minor: Better documentation comment on DeferredError. (#469)
leopd Nov 11, 2018
1df9317
Update empty framework_version warning (#472)
laurenyu Nov 13, 2018
a9ed02e
Remove hardcoded 'training' in error message for checking job status …
laurenyu Nov 13, 2018
3fd5d9a
Bump version to 1.14.2 (#477)
iquintero Nov 13, 2018
ce1de18
Add missing changelog entry for 1.14.2 (#479)
iquintero Nov 14, 2018
aaf59b9
Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 24, 2018
25038d1
Resolving conflits in analytics
Nov 14, 2018
2f425ab
Merge branch 'master' into TrainingJobAnalytics
laurenyu Nov 14, 2018
93e3e48
Updating change log for version 1.14.2
Nov 14, 2018
c88611b
Merge branch 'master' into TrainingJobAnalytics
laurenyu Nov 14, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,6 +15,7 @@ CHANGELOG
* enhancement: Frameworks: update warning for not setting framework_version as we aren't planning a breaking change anymore
* enhancement: Session: remove hardcoded 'training' from job status error message
* bug-fix: Updated Cloudwatch namespace for metrics in TrainingJobsAnalytics
* bug-fix: Changes to use correct s3 bucket and time range for dataframes in TrainingJobAnalytics.


1.14.1
Expand Down
7 changes: 6 additions & 1 deletion src/sagemaker/analytics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -246,7 +246,12 @@ def _determine_timeinterval(self):
"""
description = self._sage_client.describe_training_job(TrainingJobName=self.name)
start_time = description[u'TrainingStartTime'] # datetime object
end_time = description.get(u'TrainingEndTime', datetime.datetime.utcnow())
# Incrementing end time by 1 min since CloudWatch drops seconds before finding the logs.
# This results in logs being searched in the time range in which the correct log line was not present.
# Example - Log time - 2018-10-22 08:25:55
# Here calculated end time would also be 2018-10-22 08:25:55 (without 1 min addition)
# CW will consider end time as 2018-10-22 08:25 and will not be able to search the correct log.
end_time = description.get(u'TrainingEndTime', datetime.datetime.utcnow()) + datetime.timedelta(minutes=1)
Comment thread
laurenyu marked this conversation as resolved.
return {
'start_time': start_time,
'end_time': end_time,
Expand Down
57 changes: 50 additions & 7 deletions tests/unit/test_analytics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,12 +47,49 @@ def create_sagemaker_session(describe_training_result=None, list_training_result
cwm_mock = Mock(name='cloudwatch_client')
boto_mock.client = Mock(return_value=cwm_mock)
cwm_mock.get_metric_statistics = Mock(
name='get_metric_statistics',
return_value=metric_stats_results,
name='get_metric_statistics'
)
cwm_mock.get_metric_statistics.side_effect = cw_request_side_effect
return sms


def cw_request_side_effect(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
if _is_valid_request(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
return _metric_stats_results()


def _is_valid_request(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
could_watch_request = {
'Namespace': Namespace,
'MetricName': MetricName,
'Dimensions': Dimensions,
'StartTime': StartTime,
'EndTime': EndTime,
'Period': Period,
'Statistics': Statistics,
}
print(could_watch_request)
return could_watch_request == cw_request()


def cw_request():
describe_training_result = _describe_training_result()
return {
'Namespace': '/aws/sagemaker/TrainingJobs',
'MetricName': 'train:acc',
'Dimensions': [
{
'Name': 'TrainingJobName',
'Value': 'my-training-job'
}
],
'StartTime': describe_training_result['TrainingStartTime'],
'EndTime': describe_training_result['TrainingEndTime'] + datetime.timedelta(minutes=1),
'Period': 60,
'Statistics': ['Average'],
}


def test_abstract_base_class():
# confirm that the abstract base class can't be instantiated directly
with pytest.raises(TypeError) as _: # noqa: F841
Expand DownExpand Up@@ -165,12 +202,15 @@ def test_trainer_name():
assert str(trainer).find("my-training-job") != -1


def test_trainer_dataframe():
describe_training_result = {
def _describe_training_result():
return {
'TrainingStartTime': datetime.datetime(2018, 5, 16, 1, 2, 3),
'TrainingEndTime': datetime.datetime(2018, 5, 16, 5, 6, 7),
}
metric_stats_results = {


def _metric_stats_results():
return {
'Datapoints': [
{
'Average': 77.1,
Expand All@@ -186,8 +226,11 @@ def test_trainer_dataframe():
},
]
}
session = create_sagemaker_session(describe_training_result=describe_training_result,
metric_stats_results=metric_stats_results)


def test_trainer_dataframe():
session = create_sagemaker_session(describe_training_result=_describe_training_result(),
metric_stats_results=_metric_stats_results())
trainer = TrainingJobAnalytics("my-training-job", ["train:acc"], sagemaker_session=session)

df = trainer.dataframe()
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
249e0d6
Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 24, 2018
8401afa
Addressing comments for Bug fix for getting dataframes in TrainingJob…
Oct 25, 2018
42d2741
Unit tests for Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 25, 2018
1640264
Merge branch 'master' into TrainingJobAnalytics
laurenyu Oct 26, 2018
d43047d
updating change log for Bug fix for getting dataframes in TrainingJob…
Nov 4, 2018
c55e7ca
Add model parameters to Estimator, and bump library version to 1.13.0…
RodrigoAtAWS Nov 1, 2018
5bdb50a
local mode: improve training input/output (#449)
iquintero Nov 2, 2018
3d103b4
Add image URIs for built-in Algorithms for SIN/LHR/BOM/SFO/YUL (#456)
pdasamzn Nov 5, 2018
23851b1
Support MXNet 1.3 with its training script format changes (#446)
laurenyu Nov 5, 2018
bd1f43b
Make InputDataConfig optional for training. (#459)
nadiaya Nov 6, 2018
2edcc3a
add tfs container support (#460)
jesterhazy Nov 7, 2018
10b7e42
simplify create_image_uri function (#462)
jesterhazy Nov 7, 2018
e8bf717
bump version to 1.14.0 (#463)
jesterhazy Nov 7, 2018
eea2ad5
Skip gpu tests in regions without ml.p2.xlarge (#461)
yangaws Nov 7, 2018
c8147a9
Adding Object2Vec support to SageMaker Python SDK (#467)
pnpnpn Nov 8, 2018
52d1ec4
fix readme rendering (#464)
jesterhazy Nov 8, 2018
3a69cf6
Add Pylint (#465)
iquintero Nov 8, 2018
9a997a5
Support optional input channels in local mode. (#466)
nadiaya Nov 9, 2018
6a1d93c
build: upgrade docker-compose to 1.23 (#470)
iquintero Nov 9, 2018
876287e
add tensorflow serving docs (#468)
jesterhazy Nov 10, 2018
0c4ad9c
Very minor: Better documentation comment on DeferredError. (#469)
leopd Nov 11, 2018
1df9317
Update empty framework_version warning (#472)
laurenyu Nov 13, 2018
a9ed02e
Remove hardcoded 'training' in error message for checking job status …
laurenyu Nov 13, 2018
3fd5d9a
Bump version to 1.14.2 (#477)
iquintero Nov 13, 2018
ce1de18
Add missing changelog entry for 1.14.2 (#479)
iquintero Nov 14, 2018
aaf59b9
Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 24, 2018
25038d1
Resolving conflits in analytics
Nov 14, 2018
2f425ab
Merge branch 'master' into TrainingJobAnalytics
laurenyu Nov 14, 2018
93e3e48
Updating change log for version 1.14.2
Nov 14, 2018
c88611b
Merge branch 'master' into TrainingJobAnalytics
laurenyu Nov 14, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,6 +15,7 @@ CHANGELOG
* enhancement: Frameworks: update warning for not setting framework_version as we aren't planning a breaking change anymore
* enhancement: Session: remove hardcoded 'training' from job status error message
* bug-fix: Updated Cloudwatch namespace for metrics in TrainingJobsAnalytics
* bug-fix: Changes to use correct s3 bucket and time range for dataframes in TrainingJobAnalytics.


1.14.1
Expand Down
7 changes: 6 additions & 1 deletion src/sagemaker/analytics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -246,7 +246,12 @@ def _determine_timeinterval(self):
"""
description = self._sage_client.describe_training_job(TrainingJobName=self.name)
start_time = description[u'TrainingStartTime'] # datetime object
end_time = description.get(u'TrainingEndTime', datetime.datetime.utcnow())
# Incrementing end time by 1 min since CloudWatch drops seconds before finding the logs.
# This results in logs being searched in the time range in which the correct log line was not present.
# Example - Log time - 2018-10-22 08:25:55
# Here calculated end time would also be 2018-10-22 08:25:55 (without 1 min addition)
# CW will consider end time as 2018-10-22 08:25 and will not be able to search the correct log.
end_time = description.get(u'TrainingEndTime', datetime.datetime.utcnow()) + datetime.timedelta(minutes=1)
Comment thread
laurenyu marked this conversation as resolved.
return {
'start_time': start_time,
'end_time': end_time,
Expand Down
57 changes: 50 additions & 7 deletions tests/unit/test_analytics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,12 +47,49 @@ def create_sagemaker_session(describe_training_result=None, list_training_result
cwm_mock = Mock(name='cloudwatch_client')
boto_mock.client = Mock(return_value=cwm_mock)
cwm_mock.get_metric_statistics = Mock(
name='get_metric_statistics',
return_value=metric_stats_results,
name='get_metric_statistics'
)
cwm_mock.get_metric_statistics.side_effect = cw_request_side_effect
return sms


def cw_request_side_effect(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
if _is_valid_request(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
return _metric_stats_results()


def _is_valid_request(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
could_watch_request = {
'Namespace': Namespace,
'MetricName': MetricName,
'Dimensions': Dimensions,
'StartTime': StartTime,
'EndTime': EndTime,
'Period': Period,
'Statistics': Statistics,
}
print(could_watch_request)
return could_watch_request == cw_request()


def cw_request():
describe_training_result = _describe_training_result()
return {
'Namespace': '/aws/sagemaker/TrainingJobs',
'MetricName': 'train:acc',
'Dimensions': [
{
'Name': 'TrainingJobName',
'Value': 'my-training-job'
}
],
'StartTime': describe_training_result['TrainingStartTime'],
'EndTime': describe_training_result['TrainingEndTime'] + datetime.timedelta(minutes=1),
'Period': 60,
'Statistics': ['Average'],
}


def test_abstract_base_class():
# confirm that the abstract base class can't be instantiated directly
with pytest.raises(TypeError) as _: # noqa: F841
Expand DownExpand Up@@ -165,12 +202,15 @@ def test_trainer_name():
assert str(trainer).find("my-training-job") != -1


def test_trainer_dataframe():
describe_training_result = {
def _describe_training_result():
return {
'TrainingStartTime': datetime.datetime(2018, 5, 16, 1, 2, 3),
'TrainingEndTime': datetime.datetime(2018, 5, 16, 5, 6, 7),
}
metric_stats_results = {


def _metric_stats_results():
return {
'Datapoints': [
{
'Average': 77.1,
Expand All@@ -186,8 +226,11 @@ def test_trainer_dataframe():
},
]
}
session = create_sagemaker_session(describe_training_result=describe_training_result,
metric_stats_results=metric_stats_results)


def test_trainer_dataframe():
session = create_sagemaker_session(describe_training_result=_describe_training_result(),
metric_stats_results=_metric_stats_results())
trainer = TrainingJobAnalytics("my-training-job", ["train:acc"], sagemaker_session=session)

df = trainer.dataframe()
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
249e0d6
Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 24, 2018
8401afa
Addressing comments for Bug fix for getting dataframes in TrainingJob…
Oct 25, 2018
42d2741
Unit tests for Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 25, 2018
1640264
Merge branch 'master' into TrainingJobAnalytics
laurenyu Oct 26, 2018
d43047d
updating change log for Bug fix for getting dataframes in TrainingJob…
Nov 4, 2018
c55e7ca
Add model parameters to Estimator, and bump library version to 1.13.0…
RodrigoAtAWS Nov 1, 2018
5bdb50a
local mode: improve training input/output (#449)
iquintero Nov 2, 2018
3d103b4
Add image URIs for built-in Algorithms for SIN/LHR/BOM/SFO/YUL (#456)
pdasamzn Nov 5, 2018
23851b1
Support MXNet 1.3 with its training script format changes (#446)
laurenyu Nov 5, 2018
bd1f43b
Make InputDataConfig optional for training. (#459)
nadiaya Nov 6, 2018
2edcc3a
add tfs container support (#460)
jesterhazy Nov 7, 2018
10b7e42
simplify create_image_uri function (#462)
jesterhazy Nov 7, 2018
e8bf717
bump version to 1.14.0 (#463)
jesterhazy Nov 7, 2018
eea2ad5
Skip gpu tests in regions without ml.p2.xlarge (#461)
yangaws Nov 7, 2018
c8147a9
Adding Object2Vec support to SageMaker Python SDK (#467)
pnpnpn Nov 8, 2018
52d1ec4
fix readme rendering (#464)
jesterhazy Nov 8, 2018
3a69cf6
Add Pylint (#465)
iquintero Nov 8, 2018
9a997a5
Support optional input channels in local mode. (#466)
nadiaya Nov 9, 2018
6a1d93c
build: upgrade docker-compose to 1.23 (#470)
iquintero Nov 9, 2018
876287e
add tensorflow serving docs (#468)
jesterhazy Nov 10, 2018
0c4ad9c
Very minor: Better documentation comment on DeferredError. (#469)
leopd Nov 11, 2018
1df9317
Update empty framework_version warning (#472)
laurenyu Nov 13, 2018
a9ed02e
Remove hardcoded 'training' in error message for checking job status …
laurenyu Nov 13, 2018
3fd5d9a
Bump version to 1.14.2 (#477)
iquintero Nov 13, 2018
ce1de18
Add missing changelog entry for 1.14.2 (#479)
iquintero Nov 14, 2018
aaf59b9
Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 24, 2018
25038d1
Resolving conflits in analytics
Nov 14, 2018
2f425ab
Merge branch 'master' into TrainingJobAnalytics
laurenyu Nov 14, 2018
93e3e48
Updating change log for version 1.14.2
Nov 14, 2018
c88611b
Merge branch 'master' into TrainingJobAnalytics
laurenyu Nov 14, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,6 +15,7 @@ CHANGELOG
* enhancement: Frameworks: update warning for not setting framework_version as we aren't planning a breaking change anymore
* enhancement: Session: remove hardcoded 'training' from job status error message
* bug-fix: Updated Cloudwatch namespace for metrics in TrainingJobsAnalytics
* bug-fix: Changes to use correct s3 bucket and time range for dataframes in TrainingJobAnalytics.


1.14.1
Expand Down
7 changes: 6 additions & 1 deletion src/sagemaker/analytics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -246,7 +246,12 @@ def _determine_timeinterval(self):
"""
description = self._sage_client.describe_training_job(TrainingJobName=self.name)
start_time = description[u'TrainingStartTime'] # datetime object
end_time = description.get(u'TrainingEndTime', datetime.datetime.utcnow())
# Incrementing end time by 1 min since CloudWatch drops seconds before finding the logs.
# This results in logs being searched in the time range in which the correct log line was not present.
# Example - Log time - 2018-10-22 08:25:55
# Here calculated end time would also be 2018-10-22 08:25:55 (without 1 min addition)
# CW will consider end time as 2018-10-22 08:25 and will not be able to search the correct log.
end_time = description.get(u'TrainingEndTime', datetime.datetime.utcnow()) + datetime.timedelta(minutes=1)
Comment thread
laurenyu marked this conversation as resolved.
return {
'start_time': start_time,
'end_time': end_time,
Expand Down
57 changes: 50 additions & 7 deletions tests/unit/test_analytics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,12 +47,49 @@ def create_sagemaker_session(describe_training_result=None, list_training_result
cwm_mock = Mock(name='cloudwatch_client')
boto_mock.client = Mock(return_value=cwm_mock)
cwm_mock.get_metric_statistics = Mock(
name='get_metric_statistics',
return_value=metric_stats_results,
name='get_metric_statistics'
)
cwm_mock.get_metric_statistics.side_effect = cw_request_side_effect
return sms


def cw_request_side_effect(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
if _is_valid_request(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
return _metric_stats_results()


def _is_valid_request(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
could_watch_request = {
'Namespace': Namespace,
'MetricName': MetricName,
'Dimensions': Dimensions,
'StartTime': StartTime,
'EndTime': EndTime,
'Period': Period,
'Statistics': Statistics,
}
print(could_watch_request)
return could_watch_request == cw_request()


def cw_request():
describe_training_result = _describe_training_result()
return {
'Namespace': '/aws/sagemaker/TrainingJobs',
'MetricName': 'train:acc',
'Dimensions': [
{
'Name': 'TrainingJobName',
'Value': 'my-training-job'
}
],
'StartTime': describe_training_result['TrainingStartTime'],
'EndTime': describe_training_result['TrainingEndTime'] + datetime.timedelta(minutes=1),
'Period': 60,
'Statistics': ['Average'],
}


def test_abstract_base_class():
# confirm that the abstract base class can't be instantiated directly
with pytest.raises(TypeError) as _: # noqa: F841
Expand DownExpand Up@@ -165,12 +202,15 @@ def test_trainer_name():
assert str(trainer).find("my-training-job") != -1


def test_trainer_dataframe():
describe_training_result = {
def _describe_training_result():
return {
'TrainingStartTime': datetime.datetime(2018, 5, 16, 1, 2, 3),
'TrainingEndTime': datetime.datetime(2018, 5, 16, 5, 6, 7),
}
metric_stats_results = {


def _metric_stats_results():
return {
'Datapoints': [
{
'Average': 77.1,
Expand All@@ -186,8 +226,11 @@ def test_trainer_dataframe():
},
]
}
session = create_sagemaker_session(describe_training_result=describe_training_result,
metric_stats_results=metric_stats_results)


def test_trainer_dataframe():
session = create_sagemaker_session(describe_training_result=_describe_training_result(),
metric_stats_results=_metric_stats_results())
trainer = TrainingJobAnalytics("my-training-job", ["train:acc"], sagemaker_session=session)

df = trainer.dataframe()
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
249e0d6
Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 24, 2018
8401afa
Addressing comments for Bug fix for getting dataframes in TrainingJob…
Oct 25, 2018
42d2741
Unit tests for Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 25, 2018
1640264
Merge branch 'master' into TrainingJobAnalytics
laurenyu Oct 26, 2018
d43047d
updating change log for Bug fix for getting dataframes in TrainingJob…
Nov 4, 2018
c55e7ca
Add model parameters to Estimator, and bump library version to 1.13.0…
RodrigoAtAWS Nov 1, 2018
5bdb50a
local mode: improve training input/output (#449)
iquintero Nov 2, 2018
3d103b4
Add image URIs for built-in Algorithms for SIN/LHR/BOM/SFO/YUL (#456)
pdasamzn Nov 5, 2018
23851b1
Support MXNet 1.3 with its training script format changes (#446)
laurenyu Nov 5, 2018
bd1f43b
Make InputDataConfig optional for training. (#459)
nadiaya Nov 6, 2018
2edcc3a
add tfs container support (#460)
jesterhazy Nov 7, 2018
10b7e42
simplify create_image_uri function (#462)
jesterhazy Nov 7, 2018
e8bf717
bump version to 1.14.0 (#463)
jesterhazy Nov 7, 2018
eea2ad5
Skip gpu tests in regions without ml.p2.xlarge (#461)
yangaws Nov 7, 2018
c8147a9
Adding Object2Vec support to SageMaker Python SDK (#467)
pnpnpn Nov 8, 2018
52d1ec4
fix readme rendering (#464)
jesterhazy Nov 8, 2018
3a69cf6
Add Pylint (#465)
iquintero Nov 8, 2018
9a997a5
Support optional input channels in local mode. (#466)
nadiaya Nov 9, 2018
6a1d93c
build: upgrade docker-compose to 1.23 (#470)
iquintero Nov 9, 2018
876287e
add tensorflow serving docs (#468)
jesterhazy Nov 10, 2018
0c4ad9c
Very minor: Better documentation comment on DeferredError. (#469)
leopd Nov 11, 2018
1df9317
Update empty framework_version warning (#472)
laurenyu Nov 13, 2018
a9ed02e
Remove hardcoded 'training' in error message for checking job status …
laurenyu Nov 13, 2018
3fd5d9a
Bump version to 1.14.2 (#477)
iquintero Nov 13, 2018
ce1de18
Add missing changelog entry for 1.14.2 (#479)
iquintero Nov 14, 2018
aaf59b9
Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 24, 2018
25038d1
Resolving conflits in analytics
Nov 14, 2018
2f425ab
Merge branch 'master' into TrainingJobAnalytics
laurenyu Nov 14, 2018
93e3e48
Updating change log for version 1.14.2
Nov 14, 2018
c88611b
Merge branch 'master' into TrainingJobAnalytics
laurenyu Nov 14, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,6 +15,7 @@ CHANGELOG
* enhancement: Frameworks: update warning for not setting framework_version as we aren't planning a breaking change anymore
* enhancement: Session: remove hardcoded 'training' from job status error message
* bug-fix: Updated Cloudwatch namespace for metrics in TrainingJobsAnalytics
* bug-fix: Changes to use correct s3 bucket and time range for dataframes in TrainingJobAnalytics.


1.14.1
Expand Down
7 changes: 6 additions & 1 deletion src/sagemaker/analytics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -246,7 +246,12 @@ def _determine_timeinterval(self):
"""
description = self._sage_client.describe_training_job(TrainingJobName=self.name)
start_time = description[u'TrainingStartTime'] # datetime object
end_time = description.get(u'TrainingEndTime', datetime.datetime.utcnow())
# Incrementing end time by 1 min since CloudWatch drops seconds before finding the logs.
# This results in logs being searched in the time range in which the correct log line was not present.
# Example - Log time - 2018-10-22 08:25:55
# Here calculated end time would also be 2018-10-22 08:25:55 (without 1 min addition)
# CW will consider end time as 2018-10-22 08:25 and will not be able to search the correct log.
end_time = description.get(u'TrainingEndTime', datetime.datetime.utcnow()) + datetime.timedelta(minutes=1)
Comment thread
laurenyu marked this conversation as resolved.
return {
'start_time': start_time,
'end_time': end_time,
Expand Down
57 changes: 50 additions & 7 deletions tests/unit/test_analytics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,12 +47,49 @@ def create_sagemaker_session(describe_training_result=None, list_training_result
cwm_mock = Mock(name='cloudwatch_client')
boto_mock.client = Mock(return_value=cwm_mock)
cwm_mock.get_metric_statistics = Mock(
name='get_metric_statistics',
return_value=metric_stats_results,
name='get_metric_statistics'
)
cwm_mock.get_metric_statistics.side_effect = cw_request_side_effect
return sms


def cw_request_side_effect(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
if _is_valid_request(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
return _metric_stats_results()


def _is_valid_request(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
could_watch_request = {
'Namespace': Namespace,
'MetricName': MetricName,
'Dimensions': Dimensions,
'StartTime': StartTime,
'EndTime': EndTime,
'Period': Period,
'Statistics': Statistics,
}
print(could_watch_request)
return could_watch_request == cw_request()


def cw_request():
describe_training_result = _describe_training_result()
return {
'Namespace': '/aws/sagemaker/TrainingJobs',
'MetricName': 'train:acc',
'Dimensions': [
{
'Name': 'TrainingJobName',
'Value': 'my-training-job'
}
],
'StartTime': describe_training_result['TrainingStartTime'],
'EndTime': describe_training_result['TrainingEndTime'] + datetime.timedelta(minutes=1),
'Period': 60,
'Statistics': ['Average'],
}


def test_abstract_base_class():
# confirm that the abstract base class can't be instantiated directly
with pytest.raises(TypeError) as _: # noqa: F841
Expand DownExpand Up@@ -165,12 +202,15 @@ def test_trainer_name():
assert str(trainer).find("my-training-job") != -1


def test_trainer_dataframe():
describe_training_result = {
def _describe_training_result():
return {
'TrainingStartTime': datetime.datetime(2018, 5, 16, 1, 2, 3),
'TrainingEndTime': datetime.datetime(2018, 5, 16, 5, 6, 7),
}
metric_stats_results = {


def _metric_stats_results():
return {
'Datapoints': [
{
'Average': 77.1,
Expand All@@ -186,8 +226,11 @@ def test_trainer_dataframe():
},
]
}
session = create_sagemaker_session(describe_training_result=describe_training_result,
metric_stats_results=metric_stats_results)


def test_trainer_dataframe():
session = create_sagemaker_session(describe_training_result=_describe_training_result(),
metric_stats_results=_metric_stats_results())
trainer = TrainingJobAnalytics("my-training-job", ["train:acc"], sagemaker_session=session)

df = trainer.dataframe()
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
249e0d6
Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 24, 2018
8401afa
Addressing comments for Bug fix for getting dataframes in TrainingJob…
Oct 25, 2018
42d2741
Unit tests for Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 25, 2018
1640264
Merge branch 'master' into TrainingJobAnalytics
laurenyu Oct 26, 2018
d43047d
updating change log for Bug fix for getting dataframes in TrainingJob…
Nov 4, 2018
c55e7ca
Add model parameters to Estimator, and bump library version to 1.13.0…
RodrigoAtAWS Nov 1, 2018
5bdb50a
local mode: improve training input/output (#449)
iquintero Nov 2, 2018
3d103b4
Add image URIs for built-in Algorithms for SIN/LHR/BOM/SFO/YUL (#456)
pdasamzn Nov 5, 2018
23851b1
Support MXNet 1.3 with its training script format changes (#446)
laurenyu Nov 5, 2018
bd1f43b
Make InputDataConfig optional for training. (#459)
nadiaya Nov 6, 2018
2edcc3a
add tfs container support (#460)
jesterhazy Nov 7, 2018
10b7e42
simplify create_image_uri function (#462)
jesterhazy Nov 7, 2018
e8bf717
bump version to 1.14.0 (#463)
jesterhazy Nov 7, 2018
eea2ad5
Skip gpu tests in regions without ml.p2.xlarge (#461)
yangaws Nov 7, 2018
c8147a9
Adding Object2Vec support to SageMaker Python SDK (#467)
pnpnpn Nov 8, 2018
52d1ec4
fix readme rendering (#464)
jesterhazy Nov 8, 2018
3a69cf6
Add Pylint (#465)
iquintero Nov 8, 2018
9a997a5
Support optional input channels in local mode. (#466)
nadiaya Nov 9, 2018
6a1d93c
build: upgrade docker-compose to 1.23 (#470)
iquintero Nov 9, 2018
876287e
add tensorflow serving docs (#468)
jesterhazy Nov 10, 2018
0c4ad9c
Very minor: Better documentation comment on DeferredError. (#469)
leopd Nov 11, 2018
1df9317
Update empty framework_version warning (#472)
laurenyu Nov 13, 2018
a9ed02e
Remove hardcoded 'training' in error message for checking job status …
laurenyu Nov 13, 2018
3fd5d9a
Bump version to 1.14.2 (#477)
iquintero Nov 13, 2018
ce1de18
Add missing changelog entry for 1.14.2 (#479)
iquintero Nov 14, 2018
aaf59b9
Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 24, 2018
25038d1
Resolving conflits in analytics
Nov 14, 2018
2f425ab
Merge branch 'master' into TrainingJobAnalytics
laurenyu Nov 14, 2018
93e3e48
Updating change log for version 1.14.2
Nov 14, 2018
c88611b
Merge branch 'master' into TrainingJobAnalytics
laurenyu Nov 14, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,6 +15,7 @@ CHANGELOG
* enhancement: Frameworks: update warning for not setting framework_version as we aren't planning a breaking change anymore
* enhancement: Session: remove hardcoded 'training' from job status error message
* bug-fix: Updated Cloudwatch namespace for metrics in TrainingJobsAnalytics
* bug-fix: Changes to use correct s3 bucket and time range for dataframes in TrainingJobAnalytics.


1.14.1
Expand Down
7 changes: 6 additions & 1 deletion src/sagemaker/analytics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -246,7 +246,12 @@ def _determine_timeinterval(self):
"""
description = self._sage_client.describe_training_job(TrainingJobName=self.name)
start_time = description[u'TrainingStartTime'] # datetime object
end_time = description.get(u'TrainingEndTime', datetime.datetime.utcnow())
# Incrementing end time by 1 min since CloudWatch drops seconds before finding the logs.
# This results in logs being searched in the time range in which the correct log line was not present.
# Example - Log time - 2018-10-22 08:25:55
# Here calculated end time would also be 2018-10-22 08:25:55 (without 1 min addition)
# CW will consider end time as 2018-10-22 08:25 and will not be able to search the correct log.
end_time = description.get(u'TrainingEndTime', datetime.datetime.utcnow()) + datetime.timedelta(minutes=1)
Comment thread
laurenyu marked this conversation as resolved.
return {
'start_time': start_time,
'end_time': end_time,
Expand Down
57 changes: 50 additions & 7 deletions tests/unit/test_analytics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,12 +47,49 @@ def create_sagemaker_session(describe_training_result=None, list_training_result
cwm_mock = Mock(name='cloudwatch_client')
boto_mock.client = Mock(return_value=cwm_mock)
cwm_mock.get_metric_statistics = Mock(
name='get_metric_statistics',
return_value=metric_stats_results,
name='get_metric_statistics'
)
cwm_mock.get_metric_statistics.side_effect = cw_request_side_effect
return sms


def cw_request_side_effect(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
if _is_valid_request(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
return _metric_stats_results()


def _is_valid_request(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
could_watch_request = {
'Namespace': Namespace,
'MetricName': MetricName,
'Dimensions': Dimensions,
'StartTime': StartTime,
'EndTime': EndTime,
'Period': Period,
'Statistics': Statistics,
}
print(could_watch_request)
return could_watch_request == cw_request()


def cw_request():
describe_training_result = _describe_training_result()
return {
'Namespace': '/aws/sagemaker/TrainingJobs',
'MetricName': 'train:acc',
'Dimensions': [
{
'Name': 'TrainingJobName',
'Value': 'my-training-job'
}
],
'StartTime': describe_training_result['TrainingStartTime'],
'EndTime': describe_training_result['TrainingEndTime'] + datetime.timedelta(minutes=1),
'Period': 60,
'Statistics': ['Average'],
}


def test_abstract_base_class():
# confirm that the abstract base class can't be instantiated directly
with pytest.raises(TypeError) as _: # noqa: F841
Expand DownExpand Up@@ -165,12 +202,15 @@ def test_trainer_name():
assert str(trainer).find("my-training-job") != -1


def test_trainer_dataframe():
describe_training_result = {
def _describe_training_result():
return {
'TrainingStartTime': datetime.datetime(2018, 5, 16, 1, 2, 3),
'TrainingEndTime': datetime.datetime(2018, 5, 16, 5, 6, 7),
}
metric_stats_results = {


def _metric_stats_results():
return {
'Datapoints': [
{
'Average': 77.1,
Expand All@@ -186,8 +226,11 @@ def test_trainer_dataframe():
},
]
}
session = create_sagemaker_session(describe_training_result=describe_training_result,
metric_stats_results=metric_stats_results)


def test_trainer_dataframe():
session = create_sagemaker_session(describe_training_result=_describe_training_result(),
metric_stats_results=_metric_stats_results())
trainer = TrainingJobAnalytics("my-training-job", ["train:acc"], sagemaker_session=session)

df = trainer.dataframe()
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
249e0d6
Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 24, 2018
8401afa
Addressing comments for Bug fix for getting dataframes in TrainingJob…
Oct 25, 2018
42d2741
Unit tests for Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 25, 2018
1640264
Merge branch 'master' into TrainingJobAnalytics
laurenyu Oct 26, 2018
d43047d
updating change log for Bug fix for getting dataframes in TrainingJob…
Nov 4, 2018
c55e7ca
Add model parameters to Estimator, and bump library version to 1.13.0…
RodrigoAtAWS Nov 1, 2018
5bdb50a
local mode: improve training input/output (#449)
iquintero Nov 2, 2018
3d103b4
Add image URIs for built-in Algorithms for SIN/LHR/BOM/SFO/YUL (#456)
pdasamzn Nov 5, 2018
23851b1
Support MXNet 1.3 with its training script format changes (#446)
laurenyu Nov 5, 2018
bd1f43b
Make InputDataConfig optional for training. (#459)
nadiaya Nov 6, 2018
2edcc3a
add tfs container support (#460)
jesterhazy Nov 7, 2018
10b7e42
simplify create_image_uri function (#462)
jesterhazy Nov 7, 2018
e8bf717
bump version to 1.14.0 (#463)
jesterhazy Nov 7, 2018
eea2ad5
Skip gpu tests in regions without ml.p2.xlarge (#461)
yangaws Nov 7, 2018
c8147a9
Adding Object2Vec support to SageMaker Python SDK (#467)
pnpnpn Nov 8, 2018
52d1ec4
fix readme rendering (#464)
jesterhazy Nov 8, 2018
3a69cf6
Add Pylint (#465)
iquintero Nov 8, 2018
9a997a5
Support optional input channels in local mode. (#466)
nadiaya Nov 9, 2018
6a1d93c
build: upgrade docker-compose to 1.23 (#470)
iquintero Nov 9, 2018
876287e
add tensorflow serving docs (#468)
jesterhazy Nov 10, 2018
0c4ad9c
Very minor: Better documentation comment on DeferredError. (#469)
leopd Nov 11, 2018
1df9317
Update empty framework_version warning (#472)
laurenyu Nov 13, 2018
a9ed02e
Remove hardcoded 'training' in error message for checking job status …
laurenyu Nov 13, 2018
3fd5d9a
Bump version to 1.14.2 (#477)
iquintero Nov 13, 2018
ce1de18
Add missing changelog entry for 1.14.2 (#479)
iquintero Nov 14, 2018
aaf59b9
Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 24, 2018
25038d1
Resolving conflits in analytics
Nov 14, 2018
2f425ab
Merge branch 'master' into TrainingJobAnalytics
laurenyu Nov 14, 2018
93e3e48
Updating change log for version 1.14.2
Nov 14, 2018
c88611b
Merge branch 'master' into TrainingJobAnalytics
laurenyu Nov 14, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,6 +15,7 @@ CHANGELOG
* enhancement: Frameworks: update warning for not setting framework_version as we aren't planning a breaking change anymore
* enhancement: Session: remove hardcoded 'training' from job status error message
* bug-fix: Updated Cloudwatch namespace for metrics in TrainingJobsAnalytics
* bug-fix: Changes to use correct s3 bucket and time range for dataframes in TrainingJobAnalytics.


1.14.1
Expand Down
7 changes: 6 additions & 1 deletion src/sagemaker/analytics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -246,7 +246,12 @@ def _determine_timeinterval(self):
"""
description = self._sage_client.describe_training_job(TrainingJobName=self.name)
start_time = description[u'TrainingStartTime'] # datetime object
end_time = description.get(u'TrainingEndTime', datetime.datetime.utcnow())
# Incrementing end time by 1 min since CloudWatch drops seconds before finding the logs.
# This results in logs being searched in the time range in which the correct log line was not present.
# Example - Log time - 2018-10-22 08:25:55
# Here calculated end time would also be 2018-10-22 08:25:55 (without 1 min addition)
# CW will consider end time as 2018-10-22 08:25 and will not be able to search the correct log.
end_time = description.get(u'TrainingEndTime', datetime.datetime.utcnow()) + datetime.timedelta(minutes=1)
Comment thread
laurenyu marked this conversation as resolved.
return {
'start_time': start_time,
'end_time': end_time,
Expand Down
57 changes: 50 additions & 7 deletions tests/unit/test_analytics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,12 +47,49 @@ def create_sagemaker_session(describe_training_result=None, list_training_result
cwm_mock = Mock(name='cloudwatch_client')
boto_mock.client = Mock(return_value=cwm_mock)
cwm_mock.get_metric_statistics = Mock(
name='get_metric_statistics',
return_value=metric_stats_results,
name='get_metric_statistics'
)
cwm_mock.get_metric_statistics.side_effect = cw_request_side_effect
return sms


def cw_request_side_effect(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
if _is_valid_request(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
return _metric_stats_results()


def _is_valid_request(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
could_watch_request = {
'Namespace': Namespace,
'MetricName': MetricName,
'Dimensions': Dimensions,
'StartTime': StartTime,
'EndTime': EndTime,
'Period': Period,
'Statistics': Statistics,
}
print(could_watch_request)
return could_watch_request == cw_request()


def cw_request():
describe_training_result = _describe_training_result()
return {
'Namespace': '/aws/sagemaker/TrainingJobs',
'MetricName': 'train:acc',
'Dimensions': [
{
'Name': 'TrainingJobName',
'Value': 'my-training-job'
}
],
'StartTime': describe_training_result['TrainingStartTime'],
'EndTime': describe_training_result['TrainingEndTime'] + datetime.timedelta(minutes=1),
'Period': 60,
'Statistics': ['Average'],
}


def test_abstract_base_class():
# confirm that the abstract base class can't be instantiated directly
with pytest.raises(TypeError) as _: # noqa: F841
Expand DownExpand Up@@ -165,12 +202,15 @@ def test_trainer_name():
assert str(trainer).find("my-training-job") != -1


def test_trainer_dataframe():
describe_training_result = {
def _describe_training_result():
return {
'TrainingStartTime': datetime.datetime(2018, 5, 16, 1, 2, 3),
'TrainingEndTime': datetime.datetime(2018, 5, 16, 5, 6, 7),
}
metric_stats_results = {


def _metric_stats_results():
return {
'Datapoints': [
{
'Average': 77.1,
Expand All@@ -186,8 +226,11 @@ def test_trainer_dataframe():
},
]
}
session = create_sagemaker_session(describe_training_result=describe_training_result,
metric_stats_results=metric_stats_results)


def test_trainer_dataframe():
session = create_sagemaker_session(describe_training_result=_describe_training_result(),
metric_stats_results=_metric_stats_results())
trainer = TrainingJobAnalytics("my-training-job", ["train:acc"], sagemaker_session=session)

df = trainer.dataframe()
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
249e0d6
Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 24, 2018
8401afa
Addressing comments for Bug fix for getting dataframes in TrainingJob…
Oct 25, 2018
42d2741
Unit tests for Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 25, 2018
1640264
Merge branch 'master' into TrainingJobAnalytics
laurenyu Oct 26, 2018
d43047d
updating change log for Bug fix for getting dataframes in TrainingJob…
Nov 4, 2018
c55e7ca
Add model parameters to Estimator, and bump library version to 1.13.0…
RodrigoAtAWS Nov 1, 2018
5bdb50a
local mode: improve training input/output (#449)
iquintero Nov 2, 2018
3d103b4
Add image URIs for built-in Algorithms for SIN/LHR/BOM/SFO/YUL (#456)
pdasamzn Nov 5, 2018
23851b1
Support MXNet 1.3 with its training script format changes (#446)
laurenyu Nov 5, 2018
bd1f43b
Make InputDataConfig optional for training. (#459)
nadiaya Nov 6, 2018
2edcc3a
add tfs container support (#460)
jesterhazy Nov 7, 2018
10b7e42
simplify create_image_uri function (#462)
jesterhazy Nov 7, 2018
e8bf717
bump version to 1.14.0 (#463)
jesterhazy Nov 7, 2018
eea2ad5
Skip gpu tests in regions without ml.p2.xlarge (#461)
yangaws Nov 7, 2018
c8147a9
Adding Object2Vec support to SageMaker Python SDK (#467)
pnpnpn Nov 8, 2018
52d1ec4
fix readme rendering (#464)
jesterhazy Nov 8, 2018
3a69cf6
Add Pylint (#465)
iquintero Nov 8, 2018
9a997a5
Support optional input channels in local mode. (#466)
nadiaya Nov 9, 2018
6a1d93c
build: upgrade docker-compose to 1.23 (#470)
iquintero Nov 9, 2018
876287e
add tensorflow serving docs (#468)
jesterhazy Nov 10, 2018
0c4ad9c
Very minor: Better documentation comment on DeferredError. (#469)
leopd Nov 11, 2018
1df9317
Update empty framework_version warning (#472)
laurenyu Nov 13, 2018
a9ed02e
Remove hardcoded 'training' in error message for checking job status …
laurenyu Nov 13, 2018
3fd5d9a
Bump version to 1.14.2 (#477)
iquintero Nov 13, 2018
ce1de18
Add missing changelog entry for 1.14.2 (#479)
iquintero Nov 14, 2018
aaf59b9
Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 24, 2018
25038d1
Resolving conflits in analytics
Nov 14, 2018
2f425ab
Merge branch 'master' into TrainingJobAnalytics
laurenyu Nov 14, 2018
93e3e48
Updating change log for version 1.14.2
Nov 14, 2018
c88611b
Merge branch 'master' into TrainingJobAnalytics
laurenyu Nov 14, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,6 +15,7 @@ CHANGELOG
* enhancement: Frameworks: update warning for not setting framework_version as we aren't planning a breaking change anymore
* enhancement: Session: remove hardcoded 'training' from job status error message
* bug-fix: Updated Cloudwatch namespace for metrics in TrainingJobsAnalytics
* bug-fix: Changes to use correct s3 bucket and time range for dataframes in TrainingJobAnalytics.


1.14.1
Expand Down
7 changes: 6 additions & 1 deletion src/sagemaker/analytics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -246,7 +246,12 @@ def _determine_timeinterval(self):
"""
description = self._sage_client.describe_training_job(TrainingJobName=self.name)
start_time = description[u'TrainingStartTime'] # datetime object
end_time = description.get(u'TrainingEndTime', datetime.datetime.utcnow())
# Incrementing end time by 1 min since CloudWatch drops seconds before finding the logs.
# This results in logs being searched in the time range in which the correct log line was not present.
# Example - Log time - 2018-10-22 08:25:55
# Here calculated end time would also be 2018-10-22 08:25:55 (without 1 min addition)
# CW will consider end time as 2018-10-22 08:25 and will not be able to search the correct log.
end_time = description.get(u'TrainingEndTime', datetime.datetime.utcnow()) + datetime.timedelta(minutes=1)
Comment thread
laurenyu marked this conversation as resolved.
return {
'start_time': start_time,
'end_time': end_time,
Expand Down
57 changes: 50 additions & 7 deletions tests/unit/test_analytics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,12 +47,49 @@ def create_sagemaker_session(describe_training_result=None, list_training_result
cwm_mock = Mock(name='cloudwatch_client')
boto_mock.client = Mock(return_value=cwm_mock)
cwm_mock.get_metric_statistics = Mock(
name='get_metric_statistics',
return_value=metric_stats_results,
name='get_metric_statistics'
)
cwm_mock.get_metric_statistics.side_effect = cw_request_side_effect
return sms


def cw_request_side_effect(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
if _is_valid_request(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
return _metric_stats_results()


def _is_valid_request(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
could_watch_request = {
'Namespace': Namespace,
'MetricName': MetricName,
'Dimensions': Dimensions,
'StartTime': StartTime,
'EndTime': EndTime,
'Period': Period,
'Statistics': Statistics,
}
print(could_watch_request)
return could_watch_request == cw_request()


def cw_request():
describe_training_result = _describe_training_result()
return {
'Namespace': '/aws/sagemaker/TrainingJobs',
'MetricName': 'train:acc',
'Dimensions': [
{
'Name': 'TrainingJobName',
'Value': 'my-training-job'
}
],
'StartTime': describe_training_result['TrainingStartTime'],
'EndTime': describe_training_result['TrainingEndTime'] + datetime.timedelta(minutes=1),
'Period': 60,
'Statistics': ['Average'],
}


def test_abstract_base_class():
# confirm that the abstract base class can't be instantiated directly
with pytest.raises(TypeError) as _: # noqa: F841
Expand DownExpand Up@@ -165,12 +202,15 @@ def test_trainer_name():
assert str(trainer).find("my-training-job") != -1


def test_trainer_dataframe():
describe_training_result = {
def _describe_training_result():
return {
'TrainingStartTime': datetime.datetime(2018, 5, 16, 1, 2, 3),
'TrainingEndTime': datetime.datetime(2018, 5, 16, 5, 6, 7),
}
metric_stats_results = {


def _metric_stats_results():
return {
'Datapoints': [
{
'Average': 77.1,
Expand All@@ -186,8 +226,11 @@ def test_trainer_dataframe():
},
]
}
session = create_sagemaker_session(describe_training_result=describe_training_result,
metric_stats_results=metric_stats_results)


def test_trainer_dataframe():
session = create_sagemaker_session(describe_training_result=_describe_training_result(),
metric_stats_results=_metric_stats_results())
trainer = TrainingJobAnalytics("my-training-job", ["train:acc"], sagemaker_session=session)

df = trainer.dataframe()
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
249e0d6
Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 24, 2018
8401afa
Addressing comments for Bug fix for getting dataframes in TrainingJob…
Oct 25, 2018
42d2741
Unit tests for Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 25, 2018
1640264
Merge branch 'master' into TrainingJobAnalytics
laurenyu Oct 26, 2018
d43047d
updating change log for Bug fix for getting dataframes in TrainingJob…
Nov 4, 2018
c55e7ca
Add model parameters to Estimator, and bump library version to 1.13.0…
RodrigoAtAWS Nov 1, 2018
5bdb50a
local mode: improve training input/output (#449)
iquintero Nov 2, 2018
3d103b4
Add image URIs for built-in Algorithms for SIN/LHR/BOM/SFO/YUL (#456)
pdasamzn Nov 5, 2018
23851b1
Support MXNet 1.3 with its training script format changes (#446)
laurenyu Nov 5, 2018
bd1f43b
Make InputDataConfig optional for training. (#459)
nadiaya Nov 6, 2018
2edcc3a
add tfs container support (#460)
jesterhazy Nov 7, 2018
10b7e42
simplify create_image_uri function (#462)
jesterhazy Nov 7, 2018
e8bf717
bump version to 1.14.0 (#463)
jesterhazy Nov 7, 2018
eea2ad5
Skip gpu tests in regions without ml.p2.xlarge (#461)
yangaws Nov 7, 2018
c8147a9
Adding Object2Vec support to SageMaker Python SDK (#467)
pnpnpn Nov 8, 2018
52d1ec4
fix readme rendering (#464)
jesterhazy Nov 8, 2018
3a69cf6
Add Pylint (#465)
iquintero Nov 8, 2018
9a997a5
Support optional input channels in local mode. (#466)
nadiaya Nov 9, 2018
6a1d93c
build: upgrade docker-compose to 1.23 (#470)
iquintero Nov 9, 2018
876287e
add tensorflow serving docs (#468)
jesterhazy Nov 10, 2018
0c4ad9c
Very minor: Better documentation comment on DeferredError. (#469)
leopd Nov 11, 2018
1df9317
Update empty framework_version warning (#472)
laurenyu Nov 13, 2018
a9ed02e
Remove hardcoded 'training' in error message for checking job status …
laurenyu Nov 13, 2018
3fd5d9a
Bump version to 1.14.2 (#477)
iquintero Nov 13, 2018
ce1de18
Add missing changelog entry for 1.14.2 (#479)
iquintero Nov 14, 2018
aaf59b9
Bug fix for getting dataframes in TrainingJobAnalytics.
Oct 24, 2018
25038d1
Resolving conflits in analytics
Nov 14, 2018
2f425ab
Merge branch 'master' into TrainingJobAnalytics
laurenyu Nov 14, 2018
93e3e48
Updating change log for version 1.14.2
Nov 14, 2018
c88611b
Merge branch 'master' into TrainingJobAnalytics
laurenyu Nov 14, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,6 +15,7 @@ CHANGELOG
* enhancement: Frameworks: update warning for not setting framework_version as we aren't planning a breaking change anymore
* enhancement: Session: remove hardcoded 'training' from job status error message
* bug-fix: Updated Cloudwatch namespace for metrics in TrainingJobsAnalytics
* bug-fix: Changes to use correct s3 bucket and time range for dataframes in TrainingJobAnalytics.


1.14.1
Expand Down
7 changes: 6 additions & 1 deletion src/sagemaker/analytics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -246,7 +246,12 @@ def _determine_timeinterval(self):
"""
description = self._sage_client.describe_training_job(TrainingJobName=self.name)
start_time = description[u'TrainingStartTime'] # datetime object
end_time = description.get(u'TrainingEndTime', datetime.datetime.utcnow())
# Incrementing end time by 1 min since CloudWatch drops seconds before finding the logs.
# This results in logs being searched in the time range in which the correct log line was not present.
# Example - Log time - 2018-10-22 08:25:55
# Here calculated end time would also be 2018-10-22 08:25:55 (without 1 min addition)
# CW will consider end time as 2018-10-22 08:25 and will not be able to search the correct log.
end_time = description.get(u'TrainingEndTime', datetime.datetime.utcnow()) + datetime.timedelta(minutes=1)
Comment thread
laurenyu marked this conversation as resolved.
return {
'start_time': start_time,
'end_time': end_time,
Expand Down
57 changes: 50 additions & 7 deletions tests/unit/test_analytics.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,12 +47,49 @@ def create_sagemaker_session(describe_training_result=None, list_training_result
cwm_mock = Mock(name='cloudwatch_client')
boto_mock.client = Mock(return_value=cwm_mock)
cwm_mock.get_metric_statistics = Mock(
name='get_metric_statistics',
return_value=metric_stats_results,
name='get_metric_statistics'
)
cwm_mock.get_metric_statistics.side_effect = cw_request_side_effect
return sms


def cw_request_side_effect(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
if _is_valid_request(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
return _metric_stats_results()


def _is_valid_request(Namespace, MetricName, Dimensions, StartTime, EndTime, Period, Statistics):
could_watch_request = {
'Namespace': Namespace,
'MetricName': MetricName,
'Dimensions': Dimensions,
'StartTime': StartTime,
'EndTime': EndTime,
'Period': Period,
'Statistics': Statistics,
}
print(could_watch_request)
return could_watch_request == cw_request()


def cw_request():
describe_training_result = _describe_training_result()
return {
'Namespace': '/aws/sagemaker/TrainingJobs',
'MetricName': 'train:acc',
'Dimensions': [
{
'Name': 'TrainingJobName',
'Value': 'my-training-job'
}
],
'StartTime': describe_training_result['TrainingStartTime'],
'EndTime': describe_training_result['TrainingEndTime'] + datetime.timedelta(minutes=1),
'Period': 60,
'Statistics': ['Average'],
}


def test_abstract_base_class():
# confirm that the abstract base class can't be instantiated directly
with pytest.raises(TypeError) as _: # noqa: F841
Expand DownExpand Up@@ -165,12 +202,15 @@ def test_trainer_name():
assert str(trainer).find("my-training-job") != -1


def test_trainer_dataframe():
describe_training_result = {
def _describe_training_result():
return {
'TrainingStartTime': datetime.datetime(2018, 5, 16, 1, 2, 3),
'TrainingEndTime': datetime.datetime(2018, 5, 16, 5, 6, 7),
}
metric_stats_results = {


def _metric_stats_results():
return {
'Datapoints': [
{
'Average': 77.1,
Expand All@@ -186,8 +226,11 @@ def test_trainer_dataframe():
},
]
}
session = create_sagemaker_session(describe_training_result=describe_training_result,
metric_stats_results=metric_stats_results)


def test_trainer_dataframe():
session = create_sagemaker_session(describe_training_result=_describe_training_result(),
metric_stats_results=_metric_stats_results())
trainer = TrainingJobAnalytics("my-training-job", ["train:acc"], sagemaker_session=session)

df = trainer.dataframe()
Expand Down