Skip to content

Commit 05d3810

Browse files
authored
Merge branch 'master' into feat/jumpstart-model-artifact-instance-type-variants
2 parents 11e20e5 + 561301e commit 05d3810

Some content is hidden

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

44 files changed

+1503
-67
lines changed

CHANGELOG.md

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

3+
## v2.192.0 (2023-10-11)
4+
5+
### Features
6+
7+
* jumpstart estimator enable infra check flag
8+
* jumpstart default payloads
9+
* allow non-python files in job dependencies
10+
* allow configuring docker container in local mode
11+
12+
### Bug Fixes and Other Changes
13+
14+
* js tagging s3 prefix
15+
* Batch transform: Add support for split_type == "None" in local mode
16+
* use correct line endings and s3 uris on windows
17+
* Fixed bug in _create_training_details
18+
* DJL Neuronx 0.24.0
19+
20+
### Documentation Changes
21+
22+
* Include FeatureGroup's load_feature_definitions API documentation
23+
324
## v2.191.0 (2023-10-05)
425

526
### Features

VERSION

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

doc/overview.rst

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1560,9 +1560,20 @@ You can install necessary dependencies for this feature using pip.
15601560
Additionally, Local Mode also requires Docker Compose V2. Follow the guidelines in https://docs.docker.com/compose/install/ to install.
15611561
Make sure to have a Compose Version compatible with your Docker Engine installation. Check Docker Engine release notes https://docs.docker.com/engine/release-notes to find a compatible version.
15621562

1563-
If you want to keep everything local, and not use Amazon S3 either, you can enable "local code" in one of two ways:
1563+
Local mode configuration
1564+
========================
15641565

1565-
- Create a file at ``~/.sagemaker/config.yaml`` that contains:
1566+
The local mode uses a YAML configuration file located at ``~/.sagemaker/config.yaml`` to define the default values that are automatically passed to the ``config`` attribute of ``LocalSession``. This is an example of the configuration, for the full schema, see `sagemaker.config.config_schema.SAGEMAKER_PYTHON_SDK_LOCAL_MODE_CONFIG_SCHEMA <https://github.com/aws/sagemaker-python-sdk/blob/master/src/sagemaker/config/config_schema.py>`_.
1567+
1568+
.. code:: yaml
1569+
1570+
local:
1571+
local_code: true # Using everything locally
1572+
region_name: "us-west-2" # Name of the region
1573+
container_config: # Additional docker container config
1574+
shm_size: "128M
1575+
1576+
If you want to keep everything local, and not use Amazon S3 either, you can enable "local code" in one of two ways:
15661577
15671578
.. code:: yaml
15681579
@@ -1583,6 +1594,9 @@ If you want to keep everything local, and not use Amazon S3 either, you can enab
15831594
.. note::
15841595
If you enable "local code," then you cannot use the ``dependencies`` parameter in your estimator or model.
15851596

1597+
Activating local mode by ``instance_type`` argument
1598+
====================================================
1599+
15861600
We can take the example in `Using Estimators <#using-estimators>`__ , and use either ``local`` or ``local_gpu`` as the instance type.
15871601

15881602
.. code:: python

src/sagemaker/base_predictor.py

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from __future__ import print_function, absolute_import
1515

1616
import abc
17-
from typing import Any, Tuple
17+
from typing import Any, Optional, Tuple, Union
1818

1919
from sagemaker.deprecations import (
2020
deprecated_class,
@@ -32,6 +32,9 @@
3232
StreamDeserializer,
3333
StringDeserializer,
3434
)
35+
from sagemaker.jumpstart.payload_utils import PayloadSerializer
36+
from sagemaker.jumpstart.types import JumpStartSerializablePayload
37+
from sagemaker.jumpstart.utils import get_jumpstart_content_bucket
3538
from sagemaker.model_monitor import (
3639
DataCaptureConfig,
3740
DefaultModelMonitor,
@@ -201,20 +204,44 @@ def _create_request_args(
201204
custom_attributes=None,
202205
):
203206
"""Placeholder docstring"""
207+
208+
jumpstart_serialized_data: Optional[Union[str, bytes]] = None
209+
jumpstart_accept: Optional[str] = None
210+
jumpstart_content_type: Optional[str] = None
211+
212+
if isinstance(data, JumpStartSerializablePayload):
213+
s3_client = self.sagemaker_session.s3_client
214+
region = self.sagemaker_session._region_name
215+
bucket = get_jumpstart_content_bucket(region)
216+
217+
jumpstart_serialized_data = PayloadSerializer(
218+
bucket=bucket, region=region, s3_client=s3_client
219+
).serialize(data)
220+
jumpstart_content_type = data.content_type
221+
jumpstart_accept = data.accept
222+
204223
args = dict(initial_args) if initial_args else {}
205224

206225
if "EndpointName" not in args:
207226
args["EndpointName"] = self.endpoint_name
208227

209228
if "ContentType" not in args:
210-
args["ContentType"] = (
211-
self.content_type
212-
if isinstance(self.content_type, str)
213-
else ", ".join(self.content_type)
214-
)
229+
if isinstance(data, JumpStartSerializablePayload) and jumpstart_content_type:
230+
args["ContentType"] = jumpstart_content_type
231+
else:
232+
args["ContentType"] = (
233+
self.content_type
234+
if isinstance(self.content_type, str)
235+
else ", ".join(self.content_type)
236+
)
215237

216238
if "Accept" not in args:
217-
args["Accept"] = self.accept if isinstance(self.accept, str) else ", ".join(self.accept)
239+
if isinstance(data, JumpStartSerializablePayload) and jumpstart_accept:
240+
args["Accept"] = jumpstart_accept
241+
else:
242+
args["Accept"] = (
243+
self.accept if isinstance(self.accept, str) else ", ".join(self.accept)
244+
)
218245

219246
if target_model:
220247
args["TargetModel"] = target_model
@@ -228,7 +255,11 @@ def _create_request_args(
228255
if custom_attributes:
229256
args["CustomAttributes"] = custom_attributes
230257

231-
data = self.serializer.serialize(data)
258+
data = (
259+
jumpstart_serialized_data
260+
if isinstance(data, JumpStartSerializablePayload) and jumpstart_serialized_data
261+
else self.serializer.serialize(data)
262+
)
232263

233264
args["Body"] = data
234265
return args

src/sagemaker/config/__init__.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313
"""This module configures the default values for SageMaker Python SDK."""
1414

1515
from __future__ import absolute_import
16-
from sagemaker.config.config import load_sagemaker_config, validate_sagemaker_config # noqa: F401
16+
from sagemaker.config.config import ( # noqa: F401
17+
load_local_mode_config,
18+
load_sagemaker_config,
19+
validate_sagemaker_config,
20+
)
1721
from sagemaker.config.config_schema import ( # noqa: F401
1822
KEY,
1923
TRAINING_JOB,
@@ -161,4 +165,8 @@
161165
INFERENCE_SPECIFICATION,
162166
ESTIMATOR,
163167
DEBUG_HOOK_CONFIG,
168+
SAGEMAKER_PYTHON_SDK_LOCAL_MODE_CONFIG_SCHEMA,
169+
LOCAL,
170+
LOCAL_CODE,
171+
CONTAINER_CONFIG,
164172
)

src/sagemaker/config/config.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
The schema of the config file is dictated in config_schema.py in the same module.
1717
1818
"""
19-
from __future__ import absolute_import
19+
from __future__ import absolute_import, annotations
2020

2121
import pathlib
2222
import os
@@ -33,12 +33,18 @@
3333
logger = get_sagemaker_config_logger()
3434

3535
_APP_NAME = "sagemaker"
36+
# The default name of the config file.
37+
_CONFIG_FILE_NAME = "config.yaml"
3638
# The default config file location of the Administrator provided config file. This path can be
3739
# overridden with `SAGEMAKER_ADMIN_CONFIG_OVERRIDE` environment variable.
38-
_DEFAULT_ADMIN_CONFIG_FILE_PATH = os.path.join(site_config_dir(_APP_NAME), "config.yaml")
40+
_DEFAULT_ADMIN_CONFIG_FILE_PATH = os.path.join(site_config_dir(_APP_NAME), _CONFIG_FILE_NAME)
3941
# The default config file location of the user provided config file. This path can be
4042
# overridden with `SAGEMAKER_USER_CONFIG_OVERRIDE` environment variable.
41-
_DEFAULT_USER_CONFIG_FILE_PATH = os.path.join(user_config_dir(_APP_NAME), "config.yaml")
43+
_DEFAULT_USER_CONFIG_FILE_PATH = os.path.join(user_config_dir(_APP_NAME), _CONFIG_FILE_NAME)
44+
# The default config file location of the local mode.
45+
_DEFAULT_LOCAL_MODE_CONFIG_FILE_PATH = os.path.join(
46+
os.path.expanduser("~"), ".sagemaker", _CONFIG_FILE_NAME
47+
)
4248

4349
ENV_VARIABLE_ADMIN_CONFIG_OVERRIDE = "SAGEMAKER_ADMIN_CONFIG_OVERRIDE"
4450
ENV_VARIABLE_USER_CONFIG_OVERRIDE = "SAGEMAKER_USER_CONFIG_OVERRIDE"
@@ -144,11 +150,21 @@ def validate_sagemaker_config(sagemaker_config: dict = None):
144150
jsonschema.validate(sagemaker_config, SAGEMAKER_PYTHON_SDK_CONFIG_SCHEMA)
145151

146152

153+
def load_local_mode_config() -> dict | None:
154+
"""Loads the local mode config file."""
155+
try:
156+
content = _load_config_from_file(_DEFAULT_LOCAL_MODE_CONFIG_FILE_PATH)
157+
except ValueError:
158+
content = None
159+
160+
return content
161+
162+
147163
def _load_config_from_file(file_path: str) -> dict:
148164
"""Placeholder docstring"""
149165
inferred_file_path = file_path
150166
if os.path.isdir(file_path):
151-
inferred_file_path = os.path.join(file_path, "config.yaml")
167+
inferred_file_path = os.path.join(file_path, _CONFIG_FILE_NAME)
152168
if not os.path.exists(inferred_file_path):
153169
raise ValueError(
154170
f"Unable to load the config file from the location: {file_path}"
@@ -194,10 +210,14 @@ def _get_inferred_s3_uri(s3_uri, s3_resource_for_config):
194210
if len(s3_files_with_same_prefix) > 1:
195211
# Customer has provided us with a S3 URI which points to a directory
196212
# search for s3://<bucket>/directory-key-prefix/config.yaml
197-
inferred_s3_uri = str(pathlib.PurePosixPath(s3_uri, "config.yaml")).replace("s3:/", "s3://")
213+
inferred_s3_uri = str(pathlib.PurePosixPath(s3_uri, _CONFIG_FILE_NAME)).replace(
214+
"s3:/", "s3://"
215+
)
198216
if inferred_s3_uri not in s3_files_with_same_prefix:
199217
# We don't know which file we should be operating with.
200-
raise ValueError("Provide an S3 URI of a directory that has a config.yaml file.")
218+
raise ValueError(
219+
f"Provide an S3 URI of a directory that has a {_CONFIG_FILE_NAME} file."
220+
)
201221
# Customer has a config.yaml present in the directory that was provided as the S3 URI
202222
return inferred_s3_uri
203223
return s3_uri

src/sagemaker/config/config_schema.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@
102102
DISABLE_PROFILER = "DisableProfiler"
103103
ESTIMATOR = "Estimator"
104104
DEBUG_HOOK_CONFIG = "DebugHookConfig"
105+
LOCAL = "local"
106+
LOCAL_CODE = "local_code"
107+
SERVING_PORT = "serving_port"
108+
CONTAINER_CONFIG = "container_config"
109+
CONTAINER_ROOT = "container_root"
110+
REGION_NAME = "region_name"
105111

106112

107113
def _simple_path(*args: str):
@@ -1068,3 +1074,31 @@ def _simple_path(*args: str):
10681074
},
10691075
},
10701076
}
1077+
1078+
SAGEMAKER_PYTHON_SDK_LOCAL_MODE_CONFIG_SCHEMA = {
1079+
"$schema": "https://json-schema.org/draft/2020-12/schema",
1080+
TYPE: OBJECT,
1081+
ADDITIONAL_PROPERTIES: False,
1082+
PROPERTIES: {
1083+
LOCAL: {
1084+
TYPE: OBJECT,
1085+
ADDITIONAL_PROPERTIES: False,
1086+
PROPERTIES: {
1087+
LOCAL_CODE: {
1088+
TYPE: "boolean",
1089+
},
1090+
REGION_NAME: {TYPE: "string"},
1091+
SERVING_PORT: {
1092+
TYPE: "integer",
1093+
},
1094+
CONTAINER_ROOT: {
1095+
TYPE: "string",
1096+
},
1097+
CONTAINER_CONFIG: {
1098+
TYPE: OBJECT,
1099+
},
1100+
},
1101+
},
1102+
},
1103+
"required": [LOCAL],
1104+
}

src/sagemaker/estimator.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3082,6 +3082,7 @@ def __init__(
30823082
hyperparameters=hyperparameters,
30833083
instance_groups=instance_groups,
30843084
training_repository_access_mode=training_repository_access_mode,
3085+
enable_infra_check=enable_infra_check,
30853086
training_repository_credentials_provider_arn=training_repository_credentials_provider_arn, # noqa: E501 # pylint: disable=line-too-long
30863087
container_entry_point=container_entry_point,
30873088
container_arguments=container_arguments,

src/sagemaker/feature_store/feature_processor/_config_uploader.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# language governing permissions and limitations under the License.
1313
"""Contains classes for preparing and uploading configs for a scheduled feature processor."""
1414
from __future__ import absolute_import
15-
from typing import Callable, Dict, Tuple, List
15+
from typing import Callable, Dict, Optional, Tuple, List
1616

1717
import attr
1818

@@ -70,6 +70,7 @@ def prepare_step_input_channel_for_spark_mode(
7070
s3_base_uri,
7171
self.remote_decorator_config.s3_kms_key,
7272
sagemaker_session,
73+
self.remote_decorator_config.custom_file_filter,
7374
)
7475

7576
(
@@ -134,6 +135,7 @@ def _prepare_and_upload_dependencies(
134135
s3_base_uri: str,
135136
s3_kms_key: str,
136137
sagemaker_session: Session,
138+
custom_file_filter: Optional[Callable[[str, List], List]] = None,
137139
) -> str:
138140
"""Upload the training step dependencies to S3 if present"""
139141
return _prepare_and_upload_dependencies(
@@ -144,6 +146,7 @@ def _prepare_and_upload_dependencies(
144146
s3_base_uri=s3_base_uri,
145147
s3_kms_key=s3_kms_key,
146148
sagemaker_session=sagemaker_session,
149+
custom_file_filter=custom_file_filter,
147150
)
148151

149152
def _prepare_and_upload_runtime_scripts(

0 commit comments

Comments
 (0)