Skip to content

Commit 2c292bc

Browse files
Merge branch 'master' into bugfix/update-batch-monitoring-schedule
2 parents 8ae7572 + 19115a2 commit 2c292bc

23 files changed

+496
-137
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
## v2.145.0 (2023-04-06)
4+
5+
### Features
6+
7+
* add support for async inline error notifications
8+
* Add methods for feature group to list feature metadata parameters and tags
9+
* Support huggingface hub model_id for DJL Models
10+
11+
### Bug Fixes and Other Changes
12+
13+
* load_sagemaker_config should lazy initialize a default S3 resource
14+
315
## v2.144.0 (2023-04-05)
416

517
### Features

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.144.1.dev0
1+
2.145.1.dev0

doc/api/prep_data/feature_store.rst

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Feature Store APIs
22
------------------
33

4-
Feature group
4+
Feature Group
55
*************
66

77
.. autoclass:: sagemaker.feature_store.feature_group.FeatureGroup
@@ -18,7 +18,7 @@ Feature group
1818
:show-inheritance:
1919

2020

21-
Feature definition
21+
Feature Definition
2222
******************
2323

2424
.. autoclass:: sagemaker.feature_store.feature_definition.FeatureDefinition
@@ -77,10 +77,46 @@ Inputs
7777
:members:
7878
:show-inheritance:
7979

80+
.. autoclass:: sagemaker.feature_store.inputs.ResourceEnum
81+
:members:
82+
:show-inheritance:
83+
84+
.. autoclass:: sagemaker.feature_store.inputs.SearchOperatorEnum
85+
:members:
86+
:show-inheritance:
87+
88+
.. autoclass:: sagemaker.feature_store.inputs.SortOrderEnum
89+
:members:
90+
:show-inheritance:
91+
92+
.. autoclass:: sagemaker.feature_store.inputs.FilterOperatorEnum
93+
:members:
94+
:show-inheritance:
95+
96+
.. autoclass:: sagemaker.feature_store.inputs.Filter
97+
:members:
98+
:show-inheritance:
99+
100+
.. autoclass:: sagemaker.feature_store.inputs.Identifier
101+
:members:
102+
:show-inheritance:
103+
104+
.. autoclass:: sagemaker.feature_store.inputs.FeatureParameter
105+
:members:
106+
:show-inheritance:
107+
80108

81109
Dataset Builder
82110
***************
83111

84112
.. autoclass:: sagemaker.feature_store.dataset_builder.DatasetBuilder
85113
:members:
86114
:show-inheritance:
115+
116+
117+
Feature Store
118+
*************
119+
120+
.. autoclass:: sagemaker.feature_store.feature_store.FeatureStore
121+
:members:
122+
:show-inheritance:

doc/overview.rst

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,7 +1164,8 @@ More information about SageMaker Asynchronous Inference can be found in the `AWS
11641164

11651165
To deploy asynchronous inference endpoint, you will need to create a ``AsyncInferenceConfig`` object.
11661166
If you create ``AsyncInferenceConfig`` without specifying its arguments, the default ``S3OutputPath`` will
1167-
be ``s3://sagemaker-{REGION}-{ACCOUNTID}/async-endpoint-outputs/{UNIQUE-JOB-NAME}``. (example shown below):
1167+
be ``s3://sagemaker-{REGION}-{ACCOUNTID}/async-endpoint-outputs/{UNIQUE-JOB-NAME}``, ``S3FailurePath`` will
1168+
be ``s3://sagemaker-{REGION}-{ACCOUNTID}/async-endpoint-failures/{UNIQUE-JOB-NAME}`` (example shown below):
11681169

11691170
.. code:: python
11701171
@@ -1174,18 +1175,21 @@ be ``s3://sagemaker-{REGION}-{ACCOUNTID}/async-endpoint-outputs/{UNIQUE-JOB-NAME
11741175
async_config = AsyncInferenceConfig()
11751176
11761177
Or you can specify configurations in ``AsyncInferenceConfig`` as you like. All of those configuration parameters
1177-
are optional but if you don’t specify the ``output_path``, Amazon SageMaker will use the default ``S3OutputPath``
1178+
are optional but if you don’t specify the ``output_path`` or ``failure_path``, Amazon SageMaker will use the
1179+
default ``S3OutputPath`` or ``S3FailurePath``
11781180
mentioned above (example shown below):
11791181

11801182
.. code:: python
11811183
1182-
# Specify S3OutputPath, MaxConcurrentInvocationsPerInstance and NotificationConfig in the async config object
1184+
# Specify S3OutputPath, S3FailurePath, MaxConcurrentInvocationsPerInstance and NotificationConfig
1185+
# in the async config object
11831186
async_config = AsyncInferenceConfig(
11841187
output_path="s3://{s3_bucket}/{bucket_prefix}/output",
11851188
max_concurrent_invocations_per_instance=10,
11861189
notification_config = {
11871190
"SuccessTopic": "arn:aws:sns:aws-region:account-id:topic-name",
11881191
"ErrorTopic": "arn:aws:sns:aws-region:account-id:topic-name",
1192+
"IncludeInferenceResponseIn": ["SUCCESS_NOTIFICATION_TOPIC","ERROR_NOTIFICATION_TOPIC"],
11891193
}
11901194
)
11911195

src/sagemaker/async_inference/async_inference_config.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ def __init__(
3131
max_concurrent_invocations_per_instance=None,
3232
kms_key_id=None,
3333
notification_config=None,
34+
failure_path=None,
3435
):
3536
"""Initialize an AsyncInferenceConfig object for async inference configuration.
3637
@@ -45,6 +46,9 @@ def __init__(
4546
kms_key_id (str): Optional. The Amazon Web Services Key Management Service
4647
(Amazon Web Services KMS) key that Amazon SageMaker uses to encrypt the
4748
asynchronous inference output in Amazon S3. (Default: None)
49+
failure_path (str): Optional. The Amazon S3 location that endpoints upload model
50+
responses for failed requests. If no value is provided, Amazon SageMaker will
51+
use default Amazon S3 Async Inference failure path. (Default: None)
4852
notification_config (dict): Optional. Specifies the configuration for notifications
4953
of inference results for asynchronous inference. Only one notification is generated
5054
per invocation request (Default: None):
@@ -54,17 +58,24 @@ def __init__(
5458
* error_topic (str): Amazon SNS topic to post a notification to when inference
5559
fails. If no topic is provided, no notification is sent on failure.
5660
The key in notification_config is 'ErrorTopic'.
61+
* include_inference_response_in (list): Optional. When provided the inference
62+
response will be included in the notification topics. If not provided,
63+
a notification will still be generated on success/error, but will not
64+
contain the inference response.
65+
Valid options are SUCCESS_NOTIFICATION_TOPIC, ERROR_NOTIFICATION_TOPIC
5766
"""
5867
self.output_path = output_path
5968
self.max_concurrent_invocations_per_instance = max_concurrent_invocations_per_instance
6069
self.kms_key_id = kms_key_id
6170
self.notification_config = notification_config
71+
self.failure_path = failure_path
6272

6373
def _to_request_dict(self):
6474
"""Generates a request dictionary using the parameters provided to the class."""
6575
request_dict = {
6676
"OutputConfig": {
6777
"S3OutputPath": self.output_path,
78+
"S3FailurePath": self.failure_path,
6879
},
6980
}
7081

src/sagemaker/async_inference/async_inference_response.py

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717
from botocore.exceptions import ClientError
1818
from sagemaker.s3 import parse_s3_url
1919
from sagemaker.async_inference import WaiterConfig
20-
from sagemaker.exceptions import ObjectNotExistedError, UnexpectedClientError
20+
from sagemaker.exceptions import (
21+
ObjectNotExistedError,
22+
UnexpectedClientError,
23+
AsyncInferenceModelError,
24+
)
2125

2226

2327
class AsyncInferenceResponse(object):
@@ -32,6 +36,7 @@ def __init__(
3236
self,
3337
predictor_async,
3438
output_path,
39+
failure_path,
3540
):
3641
"""Initialize an AsyncInferenceResponse object.
3742
@@ -43,10 +48,13 @@ def __init__(
4348
that return this response.
4449
output_path (str): The Amazon S3 location that endpoints upload inference responses
4550
to.
51+
failure_path (str): The Amazon S3 location that endpoints upload model errors
52+
for failed requests.
4653
"""
4754
self.predictor_async = predictor_async
4855
self.output_path = output_path
4956
self._result = None
57+
self.failure_path = failure_path
5058

5159
def get_result(
5260
self,
@@ -71,28 +79,34 @@ def get_result(
7179

7280
if self._result is None:
7381
if waiter_config is None:
74-
self._result = self._get_result_from_s3(self.output_path)
82+
self._result = self._get_result_from_s3(self.output_path, self.failure_path)
7583
else:
7684
self._result = self.predictor_async._wait_for_output(
77-
self.output_path, waiter_config
85+
self.output_path, self.failure_path, waiter_config
7886
)
7987
return self._result
8088

81-
def _get_result_from_s3(
82-
self,
83-
output_path,
84-
):
89+
def _get_result_from_s3(self, output_path, failure_path):
8590
"""Get inference result from the output Amazon S3 path"""
8691
bucket, key = parse_s3_url(output_path)
8792
try:
8893
response = self.predictor_async.s3_client.get_object(Bucket=bucket, Key=key)
8994
return self.predictor_async.predictor._handle_response(response)
90-
except ClientError as ex:
91-
if ex.response["Error"]["Code"] == "NoSuchKey":
92-
raise ObjectNotExistedError(
93-
message="Inference could still be running",
94-
output_path=output_path,
95-
)
96-
raise UnexpectedClientError(
97-
message=ex.response["Error"]["Message"],
98-
)
95+
except ClientError as e:
96+
if e.response["Error"]["Code"] == "NoSuchKey":
97+
try:
98+
failure_bucket, failure_key = parse_s3_url(failure_path)
99+
failure_response = self.predictor_async.s3_client.get_object(
100+
Bucket=failure_bucket, Key=failure_key
101+
)
102+
failure_response = self.predictor_async.predictor._handle_response(
103+
failure_response
104+
)
105+
raise AsyncInferenceModelError(message=failure_response)
106+
except ClientError as ex:
107+
if ex.response["Error"]["Code"] == "NoSuchKey":
108+
raise ObjectNotExistedError(
109+
message="Inference could still be running", output_path=output_path
110+
)
111+
raise UnexpectedClientError(message=ex.response["Error"]["Message"])
112+
raise UnexpectedClientError(message=e.response["Error"]["Message"])

src/sagemaker/config/config.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,10 @@
4343
ENV_VARIABLE_ADMIN_CONFIG_OVERRIDE = "SAGEMAKER_ADMIN_CONFIG_OVERRIDE"
4444
ENV_VARIABLE_USER_CONFIG_OVERRIDE = "SAGEMAKER_USER_CONFIG_OVERRIDE"
4545

46-
_BOTO_SESSION = boto3.DEFAULT_SESSION or boto3.Session()
47-
# The default Boto3 S3 Resource. This is constructed from the default Boto3 session. This will be
48-
# used to fetch SageMakerConfig from S3. Users can override this by passing their own S3 Resource
49-
# as the constructor parameter for SageMakerConfig.
50-
_DEFAULT_S3_RESOURCE = _BOTO_SESSION.resource("s3")
5146
S3_PREFIX = "s3://"
5247

5348

54-
def load_sagemaker_config(
55-
additional_config_paths: List[str] = None, s3_resource=_DEFAULT_S3_RESOURCE
56-
) -> dict:
49+
def load_sagemaker_config(additional_config_paths: List[str] = None, s3_resource=None) -> dict:
5750
"""Loads config files and merges them.
5851
5952
By default, this method first searches for config files in the default locations
@@ -95,8 +88,9 @@ def load_sagemaker_config(
9588
9689
Note: S3 URI follows the format ``s3://<bucket>/<Key prefix>``
9790
s3_resource (boto3.resource("s3")): The Boto3 S3 resource. This is used to fetch
98-
config files from S3. If it is not provided, this method creates a default S3 resource.
99-
See `Boto3 Session documentation <https://boto3.amazonaws.com/v1/documentation/api\
91+
config files from S3. If it is not provided but config files are present in S3,
92+
this method creates a default S3 resource. See `Boto3 Session documentation
93+
<https://boto3.amazonaws.com/v1/documentation/api\
10094
/latest/reference/core/session.html#boto3.session.Session.resource>`__.
10195
This argument is not needed if the config files are present in the local file system.
10296
"""
@@ -161,7 +155,15 @@ def _load_config_from_file(file_path: str) -> dict:
161155
def _load_config_from_s3(s3_uri, s3_resource_for_config) -> dict:
162156
"""Placeholder docstring"""
163157
if not s3_resource_for_config:
164-
raise RuntimeError("No S3 client found. Provide a S3 client to load the config file.")
158+
# Constructing a default Boto3 S3 Resource from a default Boto3 session.
159+
boto_session = boto3.DEFAULT_SESSION or boto3.Session()
160+
boto_region_name = boto_session.region_name
161+
if boto_region_name is None:
162+
raise ValueError(
163+
"Must setup local AWS configuration with a region supported by SageMaker."
164+
)
165+
s3_resource_for_config = boto_session.resource("s3", region_name=boto_region_name)
166+
165167
logger.debug("Fetching config file from the S3 URI: %s", s3_uri)
166168
inferred_s3_uri = _get_inferred_s3_uri(s3_uri, s3_resource_for_config)
167169
parsed_url = urlparse(inferred_s3_uri)

src/sagemaker/exceptions.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,12 @@ def __init__(self, **kwargs):
7777
msg = self.fmt.format(**kwargs)
7878
Exception.__init__(self, msg)
7979
self.kwargs = kwargs
80+
81+
82+
class AsyncInferenceModelError(AsyncInferenceError):
83+
"""Raised when model returns errors for failed requests"""
84+
85+
fmt = "Model returned error: {message} "
86+
87+
def __init__(self, message):
88+
super().__init__(message=message)

src/sagemaker/feature_store/feature_group.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,32 @@ def describe_feature_metadata(self, feature_name: str) -> Dict[str, Any]:
690690
feature_group_name=self.name, feature_name=feature_name
691691
)
692692

693+
def list_tags(self) -> Sequence[Dict[str, str]]:
694+
"""List all tags for a feature group.
695+
696+
Returns:
697+
list of key, value pair of the tags.
698+
"""
699+
700+
feature_group_arn = self.sagemaker_session.describe_feature_group(
701+
feature_group_name=self.name
702+
).get("FeatureGroupArn")
703+
704+
return self.sagemaker_session.list_tags(resource_arn=feature_group_arn)
705+
706+
def list_parameters_for_feature_metadata(self, feature_name: str) -> Sequence[Dict[str, str]]:
707+
"""List all parameters for a feature metadata.
708+
709+
Args:
710+
feature_name (str): name of the feature.
711+
Returns:
712+
list of key, value pair of the parameters.
713+
"""
714+
715+
return self.sagemaker_session.describe_feature_metadata(
716+
feature_group_name=self.name, feature_name=feature_name
717+
).get("Parameters")
718+
693719
def load_feature_definitions(
694720
self,
695721
data_frame: DataFrame,

src/sagemaker/local/local_session.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -674,22 +674,19 @@ def _initialize(
674674
self.sagemaker_client = LocalSagemakerClient(self)
675675
self.sagemaker_runtime_client = LocalSagemakerRuntimeClient(self.config)
676676
self.local_mode = True
677-
sagemaker_config = kwargs.get("sagemaker_config", None)
678-
if sagemaker_config:
679-
validate_sagemaker_config(sagemaker_config)
680677

681678
if self.s3_endpoint_url is not None:
682679
self.s3_resource = boto_session.resource("s3", endpoint_url=self.s3_endpoint_url)
683680
self.s3_client = boto_session.client("s3", endpoint_url=self.s3_endpoint_url)
684-
self.sagemaker_config = (
685-
sagemaker_config
686-
if sagemaker_config
687-
else load_sagemaker_config(s3_resource=self.s3_resource)
688-
)
681+
682+
sagemaker_config = kwargs.get("sagemaker_config", None)
683+
if sagemaker_config:
684+
validate_sagemaker_config(sagemaker_config)
685+
self.sagemaker_config = sagemaker_config
689686
else:
690-
self.sagemaker_config = (
691-
sagemaker_config if sagemaker_config else load_sagemaker_config()
692-
)
687+
# self.s3_resource might be None. If it is None, load_sagemaker_config will
688+
# create a default S3 resource, but only if it needs to fetch from S3
689+
self.sagemaker_config = load_sagemaker_config(s3_resource=self.s3_resource)
693690

694691
sagemaker_config_file = os.path.join(os.path.expanduser("~"), ".sagemaker", "config.yaml")
695692
if os.path.exists(sagemaker_config_file):

0 commit comments

Comments
 (0)