From 021937b7b76e2c50ce2a6be6f59eeb9d04446735 Mon Sep 17 00:00:00 2001 From: Chuyang Deng Date: Tue, 28 Jul 2020 13:09:38 -0700 Subject: [PATCH 1/2] change: use image_uris.retrieve() for ModelMonitor default image --- .../image_uri_config/model-monitor.json | 30 ++++++++++++ src/sagemaker/image_uris.py | 9 +++- .../model_monitor/model_monitoring.py | 36 +++----------- src/sagemaker/predictor.py | 7 +-- .../sagemaker/image_uris/expected_uris.py | 6 +++ .../image_uris/test_model_monitor.py | 48 +++++++++++++++++++ .../monitor/test_model_monitoring.py | 2 + 7 files changed, 102 insertions(+), 36 deletions(-) create mode 100644 src/sagemaker/image_uri_config/model-monitor.json create mode 100644 tests/unit/sagemaker/image_uris/test_model_monitor.py diff --git a/src/sagemaker/image_uri_config/model-monitor.json b/src/sagemaker/image_uri_config/model-monitor.json new file mode 100644 index 0000000000..3af47a937c --- /dev/null +++ b/src/sagemaker/image_uri_config/model-monitor.json @@ -0,0 +1,30 @@ +{ + "scope": ["monitoring"], + "versions": { + "1": { + "registries": { + "eu-north-1": "895015795356", + "me-south-1": "607024016150", + "ap-south-1": "126357580389", + "us-east-2": "777275614652", + "eu-west-1": "468650794304", + "eu-central-1": "048819808253", + "sa-east-1": "539772159869", + "ap-east-1": "001633400207", + "us-east-1": "156813124566", + "ap-northeast-2": "709848358524", + "eu-west-2": "749857270468", + "eu-west-3": "680080141114", + "ap-northeast-1": "574779866223", + "us-west-2": "159807026194", + "us-west-1": "890145073186", + "ap-southeast-1": "245545462676", + "ap-southeast-2": "563025443158", + "ca-central-1": "536280801234", + "cn-north-1": "453000072557", + "cn-northwest-1": "453252182341" + }, + "repository": "sagemaker-model-monitor-analyzer" + } + } +} diff --git a/src/sagemaker/image_uris.py b/src/sagemaker/image_uris.py index 6ca8425e96..ef12dabe45 100644 --- a/src/sagemaker/image_uris.py +++ b/src/sagemaker/image_uris.py @@ -22,6 +22,7 @@ logger = logging.getLogger(__name__) ECR_URI_TEMPLATE = "{registry}.dkr.{hostname}/{repository}:{tag}" +MONITOR_URI_TEMPLATE = "{registry}.dkr.{hostname}/{repository}" def retrieve( @@ -68,13 +69,17 @@ def retrieve( registry = _registry_from_region(region, version_config["registries"]) hostname = utils._botocore_resolver().construct_endpoint("ecr", region)["hostname"] + repo = version_config["repository"] + + # model-monitoring image uri does not have tags + if framework == "model-monitor": + return MONITOR_URI_TEMPLATE.format(registry=registry, hostname=hostname, repository=repo) + processor = _processor( instance_type, config.get("processors") or version_config.get("processors") ) tag = _format_tag(version_config.get("tag_prefix", version), processor, py_version) - repo = version_config["repository"] - return ECR_URI_TEMPLATE.format(registry=registry, hostname=hostname, repository=repo, tag=tag) diff --git a/src/sagemaker/model_monitor/model_monitoring.py b/src/sagemaker/model_monitor/model_monitoring.py index 21e8040e53..cdcc648be8 100644 --- a/src/sagemaker/model_monitor/model_monitoring.py +++ b/src/sagemaker/model_monitor/model_monitoring.py @@ -26,38 +26,16 @@ from six.moves.urllib.parse import urlparse from botocore.exceptions import ClientError +from sagemaker import image_uris from sagemaker.exceptions import UnexpectedStatusException from sagemaker.model_monitor.monitoring_files import Constraints, ConstraintViolations, Statistics from sagemaker.network import NetworkConfig from sagemaker.processing import Processor, ProcessingInput, ProcessingJob, ProcessingOutput from sagemaker.s3 import S3Uploader from sagemaker.session import Session -from sagemaker.utils import name_from_base, retries, get_ecr_image_uri_prefix - -_DEFAULT_MONITOR_IMAGE_URI_WITH_PLACEHOLDERS = "{}/sagemaker-model-monitor-analyzer" - -_DEFAULT_MONITOR_IMAGE_REGION_ACCOUNT_MAPPING = { - "eu-north-1": "895015795356", - "me-south-1": "607024016150", - "ap-south-1": "126357580389", - "us-east-2": "777275614652", - "eu-west-1": "468650794304", - "eu-central-1": "048819808253", - "sa-east-1": "539772159869", - "ap-east-1": "001633400207", - "us-east-1": "156813124566", - "ap-northeast-2": "709848358524", - "eu-west-2": "749857270468", - "eu-west-3": "680080141114", - "ap-northeast-1": "574779866223", - "us-west-2": "159807026194", - "us-west-1": "890145073186", - "ap-southeast-1": "245545462676", - "ap-southeast-2": "563025443158", - "ca-central-1": "536280801234", - "cn-north-1": "453000072557", - "cn-northwest-1": "453252182341", -} +from sagemaker.utils import name_from_base, retries + +DEFAULT_REPOSITORY_NAME = "sagemaker-model-monitor-analyzer" STATISTICS_JSON_DEFAULT_FILE_NAME = "statistics.json" CONSTRAINTS_JSON_DEFAULT_FILE_NAME = "constraints.json" @@ -89,6 +67,8 @@ _LOGGER = logging.getLogger(__name__) +framework_name = "model-monitor" + class ModelMonitor(object): """Sets up Amazon SageMaker Monitoring Schedules and baseline suggestions. Use this class when @@ -1787,9 +1767,7 @@ def _get_default_image_uri(region): Returns: str: The Default Model Monitoring image uri based on the region. """ - return _DEFAULT_MONITOR_IMAGE_URI_WITH_PLACEHOLDERS.format( - get_ecr_image_uri_prefix(_DEFAULT_MONITOR_IMAGE_REGION_ACCOUNT_MAPPING[region], region) - ) + return image_uris.retrieve(framework=framework_name, region=region) class BaseliningJob(ProcessingJob): diff --git a/src/sagemaker/predictor.py b/src/sagemaker/predictor.py index f5e2f29820..b4423c1c98 100644 --- a/src/sagemaker/predictor.py +++ b/src/sagemaker/predictor.py @@ -18,7 +18,7 @@ from sagemaker.utils import name_from_base from sagemaker.model_monitor.model_monitoring import ( - _DEFAULT_MONITOR_IMAGE_URI_WITH_PLACEHOLDERS, + DEFAULT_REPOSITORY_NAME, ModelMonitor, DefaultModelMonitor, ) @@ -357,10 +357,7 @@ def list_monitors(self): image_uri = schedule["MonitoringScheduleConfig"]["MonitoringJobDefinition"][ "MonitoringAppSpecification" ]["ImageUri"] - index_after_placeholders = _DEFAULT_MONITOR_IMAGE_URI_WITH_PLACEHOLDERS.rfind("{}") - if image_uri.endswith( - _DEFAULT_MONITOR_IMAGE_URI_WITH_PLACEHOLDERS[index_after_placeholders + len("{}") :] - ): + if image_uri.endswith(DEFAULT_REPOSITORY_NAME): monitors.append( DefaultModelMonitor.attach( monitor_schedule_name=schedule_name, diff --git a/tests/unit/sagemaker/image_uris/expected_uris.py b/tests/unit/sagemaker/image_uris/expected_uris.py index 55347ba6e9..5d1444bcf7 100644 --- a/tests/unit/sagemaker/image_uris/expected_uris.py +++ b/tests/unit/sagemaker/image_uris/expected_uris.py @@ -19,6 +19,7 @@ } DOMAIN = "amazonaws.com" IMAGE_URI_FORMAT = "{}.dkr.ecr.{}.{}/{}:{}" +MONITOR_URI_FORMAT = "{}.dkr.ecr.{}.{}/sagemaker-model-monitor-analyzer" REGION = "us-west-2" @@ -34,3 +35,8 @@ def framework_uri(repo, fw_version, account, py_version=None, processor="cpu", r def algo_uri(algo, account, region, version=1): domain = ALTERNATE_DOMAINS.get(region, DOMAIN) return IMAGE_URI_FORMAT.format(account, region, domain, algo, version) + + +def monitor_uri(account, region=REGION): + domain = ALTERNATE_DOMAINS.get(region, DOMAIN) + return MONITOR_URI_FORMAT.format(account, region, domain) diff --git a/tests/unit/sagemaker/image_uris/test_model_monitor.py b/tests/unit/sagemaker/image_uris/test_model_monitor.py new file mode 100644 index 0000000000..fba0d60958 --- /dev/null +++ b/tests/unit/sagemaker/image_uris/test_model_monitor.py @@ -0,0 +1,48 @@ +# Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +from __future__ import absolute_import + +from sagemaker import image_uris +from tests.unit.sagemaker.image_uris import expected_uris, regions + +ACCOUNTS = { + "eu-north-1": "895015795356", + "me-south-1": "607024016150", + "ap-south-1": "126357580389", + "us-east-2": "777275614652", + "eu-west-1": "468650794304", + "eu-central-1": "048819808253", + "sa-east-1": "539772159869", + "ap-east-1": "001633400207", + "us-east-1": "156813124566", + "ap-northeast-2": "709848358524", + "eu-west-2": "749857270468", + "eu-west-3": "680080141114", + "ap-northeast-1": "574779866223", + "us-west-2": "159807026194", + "us-west-1": "890145073186", + "ap-southeast-1": "245545462676", + "ap-southeast-2": "563025443158", + "ca-central-1": "536280801234", + "cn-north-1": "453000072557", + "cn-northwest-1": "453252182341", +} + + +def test_model_monitor(): + for region in regions.regions(): + if region in ACCOUNTS.keys(): + uri = image_uris.retrieve("model-monitor", region=region) + + expected = expected_uris.monitor_uri(ACCOUNTS[region], region) + assert expected == uri diff --git a/tests/unit/sagemaker/monitor/test_model_monitoring.py b/tests/unit/sagemaker/monitor/test_model_monitoring.py index 4450b0b7e8..7b54fdc123 100644 --- a/tests/unit/sagemaker/monitor/test_model_monitoring.py +++ b/tests/unit/sagemaker/monitor/test_model_monitoring.py @@ -56,6 +56,7 @@ CUSTOM_IMAGE_URI = "012345678901.dkr.ecr.us-west-2.amazonaws.com/my-custom-image-uri" +DEFAULT_IMAGE_URI = "159807026194.dkr.ecr.us-west-2.amazonaws.com/sagemaker-model-monitor-analyzer" INTER_CONTAINER_ENCRYPTION_EXCEPTION_MSG = ( "EnableInterContainerTrafficEncryption is not supported in Model Monitor. Please ensure that " @@ -126,6 +127,7 @@ def test_default_model_monitor_suggest_baseline(sagemaker_session): assert my_default_monitor.sagemaker_session == sagemaker_session assert my_default_monitor.tags == TAGS assert my_default_monitor.network_config == NETWORK_CONFIG + assert my_default_monitor.image_uri == DEFAULT_IMAGE_URI assert BASE_JOB_NAME in my_default_monitor.latest_baselining_job_name assert my_default_monitor.latest_baselining_job_name != BASE_JOB_NAME From 6b0b83fafc61a94db5a842a2ebc73f43efb8af72 Mon Sep 17 00:00:00 2001 From: Chuyang Deng Date: Tue, 28 Jul 2020 14:43:39 -0700 Subject: [PATCH 2/2] using the generic template for model monitor image retrieve --- src/sagemaker/image_uri_config/model-monitor.json | 2 +- src/sagemaker/image_uris.py | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/sagemaker/image_uri_config/model-monitor.json b/src/sagemaker/image_uri_config/model-monitor.json index 3af47a937c..867657e27b 100644 --- a/src/sagemaker/image_uri_config/model-monitor.json +++ b/src/sagemaker/image_uri_config/model-monitor.json @@ -1,7 +1,7 @@ { "scope": ["monitoring"], "versions": { - "1": { + "": { "registries": { "eu-north-1": "895015795356", "me-south-1": "607024016150", diff --git a/src/sagemaker/image_uris.py b/src/sagemaker/image_uris.py index ef12dabe45..debfb108dd 100644 --- a/src/sagemaker/image_uris.py +++ b/src/sagemaker/image_uris.py @@ -21,8 +21,7 @@ logger = logging.getLogger(__name__) -ECR_URI_TEMPLATE = "{registry}.dkr.{hostname}/{repository}:{tag}" -MONITOR_URI_TEMPLATE = "{registry}.dkr.{hostname}/{repository}" +ECR_URI_TEMPLATE = "{registry}.dkr.{hostname}/{repository}" def retrieve( @@ -71,16 +70,15 @@ def retrieve( repo = version_config["repository"] - # model-monitoring image uri does not have tags - if framework == "model-monitor": - return MONITOR_URI_TEMPLATE.format(registry=registry, hostname=hostname, repository=repo) - processor = _processor( instance_type, config.get("processors") or version_config.get("processors") ) tag = _format_tag(version_config.get("tag_prefix", version), processor, py_version) - return ECR_URI_TEMPLATE.format(registry=registry, hostname=hostname, repository=repo, tag=tag) + if tag: + repo += ":{}".format(tag) + + return ECR_URI_TEMPLATE.format(registry=registry, hostname=hostname, repository=repo) def _config_for_framework_and_scope(framework, image_scope, accelerator_type=None):