Skip to content

Commit 82dd075

Browse files
vertex-sdk-botcopybara-github
authored andcommitted
feat: Add FlexStart option to DeploymentResourcePool.create, Endpoint.deploy, and Model.deploy (preview)
PiperOrigin-RevId: 785601050
1 parent f1207f1 commit 82dd075

4 files changed

Lines changed: 204 additions & 3 deletions

File tree

google/cloud/aiplatform/preview/models.py

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from google.cloud.aiplatform import models
2929
from google.cloud.aiplatform import utils
3030
from google.cloud.aiplatform.utils import _explanation_utils
31+
from google.cloud.aiplatform.utils import prediction_utils
3132
from google.cloud.aiplatform.compat.services import (
3233
deployment_resource_pool_service_client_v1beta1,
3334
endpoint_service_client,
@@ -140,6 +141,7 @@ def create(
140141
create_request_timeout: Optional[float] = None,
141142
required_replica_count: Optional[int] = 0,
142143
multihost_gpu_node_count: Optional[int] = None,
144+
max_runtime_duration: Optional[int] = None,
143145
) -> "DeploymentResourcePool":
144146
"""Creates a new DeploymentResourcePool.
145147
@@ -209,6 +211,13 @@ def create(
209211
multihost_gpu_node_count (int):
210212
Optional. The number of nodes per replica for multihost GPU
211213
deployments. Required for multihost GPU deployments.
214+
max_runtime_duration (int):
215+
Optional. Immutable. If set, use FlexStart VM powered by
216+
Dynamic Workload Scheduler to schedule the deployment workload.
217+
The FlexStart VM will be available for a maximum of 7 days or up
218+
to the max_runtime_duration specified, whichever is shorter.
219+
After this period, the model will be automatically undeployed.
220+
The value is in seconds.
212221
213222
Returns:
214223
DeploymentResourcePool
@@ -237,6 +246,7 @@ def create(
237246
create_request_timeout=create_request_timeout,
238247
required_replica_count=required_replica_count,
239248
multihost_gpu_node_count=multihost_gpu_node_count,
249+
max_runtime_duration=max_runtime_duration,
240250
)
241251

242252
@classmethod
@@ -260,6 +270,7 @@ def _create(
260270
create_request_timeout: Optional[float] = None,
261271
required_replica_count: Optional[int] = 0,
262272
multihost_gpu_node_count: Optional[int] = None,
273+
max_runtime_duration: Optional[int] = None,
263274
) -> "DeploymentResourcePool":
264275
"""Creates a new DeploymentResourcePool.
265276
@@ -332,7 +343,13 @@ def _create(
332343
multihost_gpu_node_count (int):
333344
Optional. The number of nodes per replica for multihost GPU
334345
deployments. Required for multihost GPU deployments.
335-
346+
max_runtime_duration (int):
347+
Optional. Immutable. If set, use FlexStart VM powered by Dynamic
348+
Workload Scheduler to schedule the deployment workload. The DWS
349+
resource will be available for a maximum of 7 days or up to the
350+
max_runtime_duration specified, whichever is shorter. After this
351+
period, the model will be automatically undeployed. The value is
352+
in seconds.
336353
Returns:
337354
DeploymentResourcePool
338355
"""
@@ -347,6 +364,10 @@ def _create(
347364
required_replica_count=required_replica_count,
348365
)
349366

367+
prediction_utils.add_flex_start_to_dedicated_resources(
368+
dedicated_resources, max_runtime_duration
369+
)
370+
350371
machine_spec = gca_machine_resources_compat.MachineSpec(
351372
machine_type=machine_type,
352373
multihost_gpu_node_count=multihost_gpu_node_count,
@@ -706,6 +727,7 @@ def deploy(
706727
required_replica_count: Optional[int] = 0,
707728
rollout_options: Optional[RolloutOptions] = None,
708729
multihost_gpu_node_count: Optional[int] = None,
730+
max_runtime_duration: Optional[int] = None,
709731
) -> None:
710732
"""Deploys a Model to the Endpoint.
711733
@@ -809,6 +831,12 @@ def deploy(
809831
multihost_gpu_node_count (int): Optional. The number of nodes per
810832
replica for multihost GPU deployments. Required for multihost GPU
811833
deployments.
834+
max_runtime_duration (int):
835+
Optional. Immutable. If set, use DWS resource
836+
to schedule the deployment workload. The DWS resource will be available
837+
for a maximum of 7 days or up to the max_runtime_duration specified,
838+
whichever is shorter. After this period, the model will be
839+
automatically undeployed. The value is in seconds.
812840
"""
813841
self._sync_gca_resource_if_skipped()
814842

@@ -853,6 +881,7 @@ def deploy(
853881
required_replica_count=required_replica_count,
854882
rollout_options=rollout_options,
855883
multihost_gpu_node_count=multihost_gpu_node_count,
884+
max_runtime_duration=max_runtime_duration,
856885
)
857886

858887
@base.optional_sync()
@@ -882,6 +911,7 @@ def _deploy(
882911
required_replica_count: Optional[int] = 0,
883912
rollout_options: Optional[RolloutOptions] = None,
884913
multihost_gpu_node_count: Optional[int] = None,
914+
max_runtime_duration: Optional[int] = None,
885915
) -> None:
886916
"""Deploys a Model to the Endpoint.
887917
@@ -979,7 +1009,12 @@ def _deploy(
9791009
multihost_gpu_node_count (int): Optional. The number of nodes per
9801010
replica for multihost GPU deployments. Required for multihost
9811011
GPU deployments.
982-
1012+
max_runtime_duration (int):
1013+
Optional. Immutable. If set, use DWS resource
1014+
to schedule the deployment workload. The DWS resource will be available
1015+
for a maximum of 7 days or up to the max_runtime_duration specified,
1016+
whichever is shorter. After this period, the model will be
1017+
automatically undeployed. The value is in seconds.
9831018
"""
9841019
_LOGGER.log_action_start_against_resource(
9851020
f"Deploying Model {model.resource_name} to", "", self
@@ -1013,6 +1048,7 @@ def _deploy(
10131048
required_replica_count=required_replica_count,
10141049
rollout_options=rollout_options,
10151050
multihost_gpu_node_count=multihost_gpu_node_count,
1051+
max_runtime_duration=max_runtime_duration,
10161052
)
10171053

10181054
_LOGGER.log_action_completed_against_resource("model", "deployed", self)
@@ -1049,6 +1085,7 @@ def _deploy_call(
10491085
required_replica_count: Optional[int] = 0,
10501086
rollout_options: Optional[RolloutOptions] = None,
10511087
multihost_gpu_node_count: Optional[int] = None,
1088+
max_runtime_duration: Optional[int] = None,
10521089
) -> None:
10531090
"""Helper method to deploy model to endpoint.
10541091
@@ -1153,6 +1190,12 @@ def _deploy_call(
11531190
multihost_gpu_node_count (int):
11541191
Optional. The number of nodes per replica for multihost GPU
11551192
deployments. Required for multihost GPU deployments.
1193+
max_runtime_duration (int):
1194+
Optional. Immutable. If set, use DWS resource
1195+
to schedule the deployment workload. The DWS resource will be available
1196+
for a maximum of 7 days or up to the max_runtime_duration specified,
1197+
whichever is shorter. After this period, the model will be
1198+
automatically undeployed. The value is in seconds.
11561199
11571200
Raises:
11581201
ValueError: If only `accelerator_type` or `accelerator_count` is
@@ -1235,6 +1278,10 @@ def _deploy_call(
12351278
required_replica_count=required_replica_count,
12361279
)
12371280

1281+
prediction_utils.add_flex_start_to_dedicated_resources(
1282+
dedicated_resources, max_runtime_duration
1283+
)
1284+
12381285
machine_spec = gca_machine_resources_compat.MachineSpec(
12391286
machine_type=machine_type,
12401287
multihost_gpu_node_count=multihost_gpu_node_count,
@@ -1599,6 +1646,7 @@ def deploy(
15991646
required_replica_count: Optional[int] = 0,
16001647
rollout_options: Optional[RolloutOptions] = None,
16011648
multihost_gpu_node_count: Optional[int] = None,
1649+
max_runtime_duration: Optional[int] = None,
16021650
) -> Union[Endpoint, models.PrivateEndpoint]:
16031651
"""Deploys model to endpoint.
16041652
@@ -1723,7 +1771,12 @@ def deploy(
17231771
multihost_gpu_node_count (int):
17241772
Optional. The number of nodes per replica for multihost GPU
17251773
deployments. Required for multihost GPU deployments.
1726-
1774+
max_runtime_duration (int):
1775+
Optional. Immutable. If set, use DWS resource
1776+
to schedule the deployment workload. The DWS resource will be available
1777+
for a maximum of 7 days or up to the max_runtime_duration specified,
1778+
whichever is shorter. After this period, the model will be
1779+
automatically undeployed. The value is in seconds.
17271780
Returns:
17281781
endpoint (Union[Endpoint, models.PrivateEndpoint]):
17291782
Endpoint with the deployed model.
@@ -1785,6 +1838,7 @@ def deploy(
17851838
required_replica_count=required_replica_count,
17861839
rollout_options=rollout_options,
17871840
multihost_gpu_node_count=multihost_gpu_node_count,
1841+
max_runtime_duration=max_runtime_duration,
17881842
)
17891843

17901844
def _should_enable_dedicated_endpoint(self, fast_tryout_enabled: bool) -> bool:
@@ -1823,6 +1877,7 @@ def _deploy(
18231877
required_replica_count: Optional[int] = 0,
18241878
rollout_options: Optional[RolloutOptions] = None,
18251879
multihost_gpu_node_count: Optional[int] = None,
1880+
max_runtime_duration: Optional[int] = None,
18261881
) -> Union[Endpoint, models.PrivateEndpoint]:
18271882
"""Deploys model to endpoint.
18281883
@@ -1938,6 +1993,12 @@ def _deploy(
19381993
multihost_gpu_node_count (int):
19391994
Optional. The number of nodes per replica for multihost GPU
19401995
deployments. Required for multihost GPU deployments.
1996+
max_runtime_duration (int):
1997+
Optional. Immutable. If set, use DWS resource
1998+
to schedule the deployment workload. The DWS resource will be available
1999+
for a maximum of 7 days or up to the max_runtime_duration specified,
2000+
whichever is shorter. After this period, the model will be
2001+
automatically undeployed. The value is in seconds.
19412002
Returns:
19422003
endpoint (Union[Endpoint, models.PrivateEndpoint]):
19432004
Endpoint with the deployed model.
@@ -2004,6 +2065,7 @@ def _deploy(
20042065
system_labels=system_labels,
20052066
required_replica_count=required_replica_count,
20062067
multihost_gpu_node_count=multihost_gpu_node_count,
2068+
max_runtime_duration=max_runtime_duration,
20072069
**preview_kwargs,
20082070
)
20092071

google/cloud/aiplatform/utils/prediction_utils.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@
2626
from google.cloud import storage
2727
from google.cloud.aiplatform.constants import prediction
2828
from google.cloud.aiplatform.utils import path_utils
29+
from google.cloud.aiplatform.compat.types import (
30+
machine_resources_v1beta1 as gca_machine_resources_compat,
31+
)
32+
from google.protobuf import duration_pb2
2933

3034
_logger = logging.getLogger(__name__)
3135

@@ -151,3 +155,22 @@ def download_model_artifacts(artifact_uri: str) -> None:
151155
else:
152156
# Copy files to the current working directory.
153157
shutil.copytree(artifact_uri, ".", dirs_exist_ok=True)
158+
159+
160+
def add_flex_start_to_dedicated_resources(
161+
dedicated_resources: gca_machine_resources_compat.DedicatedResources,
162+
max_runtime_duration: Optional[int] = None,
163+
) -> None:
164+
"""Adds FlexStart configuration to DedicatedResources if max_runtime_duration is provided.
165+
166+
Args:
167+
dedicated_resources (gca_machine_resources_compat.DedicatedResources):
168+
Required. The DedicatedResources object to modify.
169+
max_runtime_duration (int):
170+
Optional. The maximum runtime duration in seconds. If provided and
171+
greater than 0, a FlexStart configuration will be added.
172+
"""
173+
if max_runtime_duration is not None and max_runtime_duration > 0:
174+
dedicated_resources.flex_start = gca_machine_resources_compat.FlexStart(
175+
max_runtime_duration=duration_pb2.Duration(seconds=max_runtime_duration)
176+
)

tests/unit/aiplatform/test_endpoints.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,8 @@
279279
inference_timeout=duration_pb2.Duration(seconds=_TEST_INFERENCE_TIMEOUT)
280280
)
281281

282+
_TEST_MAX_RUNTIME_DURATION = 600
283+
282284
"""
283285
----------------------------------------------------------------------------
284286
Endpoint Fixtures
@@ -4645,3 +4647,60 @@ def test_construct_sdk_resource_from_gapic_uses_resource_project(self):
46454647
)
46464648
assert endpoint2.project != _TEST_PROJECT
46474649
assert endpoint2.location != _TEST_LOCATION
4650+
4651+
@pytest.mark.usefixtures(
4652+
"get_endpoint_mock", "get_model_mock", "create_endpoint_mock"
4653+
)
4654+
@pytest.mark.parametrize("sync", [True, False])
4655+
def test_deploy_no_endpoint_with_max_runtime_duration(
4656+
self, preview_deploy_model_mock, sync
4657+
):
4658+
test_model = preview_models.Model(_TEST_ID)
4659+
test_model._gca_resource.supported_deployment_resources_types.append(
4660+
aiplatform.gapic.Model.DeploymentResourcesType.DEDICATED_RESOURCES
4661+
)
4662+
test_endpoint = test_model.deploy(
4663+
machine_type=_TEST_MACHINE_TYPE,
4664+
accelerator_type=_TEST_ACCELERATOR_TYPE,
4665+
accelerator_count=_TEST_ACCELERATOR_COUNT,
4666+
service_account=_TEST_SERVICE_ACCOUNT,
4667+
sync=sync,
4668+
deploy_request_timeout=None,
4669+
max_runtime_duration=_TEST_MAX_RUNTIME_DURATION,
4670+
)
4671+
4672+
if not sync:
4673+
test_endpoint.wait()
4674+
4675+
expected_machine_spec = gca_machine_resources_v1beta1.MachineSpec(
4676+
machine_type=_TEST_MACHINE_TYPE,
4677+
accelerator_type=_TEST_ACCELERATOR_TYPE,
4678+
accelerator_count=_TEST_ACCELERATOR_COUNT,
4679+
)
4680+
expected_dedicated_resources = gca_machine_resources_v1beta1.DedicatedResources(
4681+
machine_spec=expected_machine_spec,
4682+
min_replica_count=1,
4683+
max_replica_count=1,
4684+
spot=False,
4685+
required_replica_count=0,
4686+
flex_start=gca_machine_resources_v1beta1.FlexStart(
4687+
max_runtime_duration=duration_pb2.Duration(
4688+
seconds=_TEST_MAX_RUNTIME_DURATION
4689+
),
4690+
),
4691+
)
4692+
expected_deployed_model = gca_endpoint_v1beta1.DeployedModel(
4693+
dedicated_resources=expected_dedicated_resources,
4694+
model=test_model.resource_name,
4695+
display_name=None,
4696+
service_account=_TEST_SERVICE_ACCOUNT,
4697+
enable_container_logging=True,
4698+
faster_deployment_config=gca_endpoint_v1beta1.FasterDeploymentConfig(),
4699+
)
4700+
preview_deploy_model_mock.assert_called_once_with(
4701+
endpoint=test_endpoint.resource_name,
4702+
deployed_model=expected_deployed_model,
4703+
traffic_split={"0": 100},
4704+
metadata=(),
4705+
timeout=None,
4706+
)

tests/unit/aiplatform/test_models.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2556,6 +2556,63 @@ def test_preview_deploy_no_endpoint_dedicated_resources_autoscaling_request_coun
25562556
timeout=None,
25572557
)
25582558

2559+
@pytest.mark.usefixtures(
2560+
"get_endpoint_mock",
2561+
"get_model_mock",
2562+
"create_endpoint_mock",
2563+
"preview_deploy_model_mock",
2564+
)
2565+
@pytest.mark.parametrize("sync", [True, False])
2566+
def test_preview_deploy_no_endpoint_with_flex_start(
2567+
self, preview_deploy_model_mock, sync
2568+
):
2569+
test_model = preview_models.Model(_TEST_ID)
2570+
test_model._gca_resource.supported_deployment_resources_types.append(
2571+
aiplatform.gapic.Model.DeploymentResourcesType.DEDICATED_RESOURCES
2572+
)
2573+
2574+
test_endpoint = test_model.deploy(
2575+
machine_type=_TEST_MACHINE_TYPE,
2576+
accelerator_type=_TEST_ACCELERATOR_TYPE,
2577+
accelerator_count=_TEST_ACCELERATOR_COUNT,
2578+
sync=sync,
2579+
deploy_request_timeout=None,
2580+
max_runtime_duration=600,
2581+
)
2582+
2583+
if not sync:
2584+
test_endpoint.wait()
2585+
2586+
expected_machine_spec = gca_machine_resources_v1beta1.MachineSpec(
2587+
machine_type=_TEST_MACHINE_TYPE,
2588+
accelerator_type=_TEST_ACCELERATOR_TYPE,
2589+
accelerator_count=_TEST_ACCELERATOR_COUNT,
2590+
)
2591+
expected_dedicated_resources = gca_machine_resources_v1beta1.DedicatedResources(
2592+
machine_spec=expected_machine_spec,
2593+
min_replica_count=1,
2594+
max_replica_count=1,
2595+
spot=False,
2596+
flex_start=gca_machine_resources_v1beta1.FlexStart(
2597+
max_runtime_duration=duration_pb2.Duration(seconds=600),
2598+
),
2599+
)
2600+
expected_deployed_model = gca_endpoint_v1beta1.DeployedModel(
2601+
dedicated_resources=expected_dedicated_resources,
2602+
model=test_model.resource_name,
2603+
display_name=None,
2604+
enable_container_logging=True,
2605+
faster_deployment_config=gca_endpoint_v1beta1.FasterDeploymentConfig(),
2606+
)
2607+
2608+
preview_deploy_model_mock.assert_called_once_with(
2609+
endpoint=test_endpoint.resource_name,
2610+
deployed_model=expected_deployed_model,
2611+
traffic_split={"0": 100},
2612+
metadata=(),
2613+
timeout=None,
2614+
)
2615+
25592616
@pytest.mark.usefixtures(
25602617
"get_endpoint_mock", "get_model_mock", "create_endpoint_mock"
25612618
)

0 commit comments

Comments
 (0)