oracle-ads 2.13.4__py3-none-any.whl → 2.13.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ads/aqua/app.py +6 -0
- ads/aqua/client/openai_client.py +305 -0
- ads/aqua/common/entities.py +224 -2
- ads/aqua/common/enums.py +3 -0
- ads/aqua/common/utils.py +105 -3
- ads/aqua/config/container_config.py +9 -0
- ads/aqua/constants.py +29 -1
- ads/aqua/evaluation/entities.py +6 -1
- ads/aqua/evaluation/evaluation.py +191 -7
- ads/aqua/extension/aqua_ws_msg_handler.py +6 -36
- ads/aqua/extension/base_handler.py +13 -71
- ads/aqua/extension/deployment_handler.py +67 -76
- ads/aqua/extension/errors.py +19 -0
- ads/aqua/extension/utils.py +114 -2
- ads/aqua/finetuning/finetuning.py +50 -1
- ads/aqua/model/constants.py +3 -0
- ads/aqua/model/enums.py +5 -0
- ads/aqua/model/model.py +236 -24
- ads/aqua/modeldeployment/deployment.py +671 -152
- ads/aqua/modeldeployment/entities.py +551 -42
- ads/aqua/modeldeployment/inference.py +4 -5
- ads/aqua/modeldeployment/utils.py +525 -0
- ads/aqua/resources/gpu_shapes_index.json +94 -0
- {oracle_ads-2.13.4.dist-info → oracle_ads-2.13.5.dist-info}/METADATA +1 -1
- {oracle_ads-2.13.4.dist-info → oracle_ads-2.13.5.dist-info}/RECORD +28 -25
- {oracle_ads-2.13.4.dist-info → oracle_ads-2.13.5.dist-info}/WHEEL +0 -0
- {oracle_ads-2.13.4.dist-info → oracle_ads-2.13.5.dist-info}/entry_points.txt +0 -0
- {oracle_ads-2.13.4.dist-info → oracle_ads-2.13.5.dist-info}/licenses/LICENSE.txt +0 -0
ads/aqua/model/model.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
2
|
# Copyright (c) 2024, 2025 Oracle and/or its affiliates.
|
3
3
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
4
|
+
import json
|
4
5
|
import os
|
5
6
|
import pathlib
|
6
7
|
from datetime import datetime, timedelta
|
@@ -14,6 +15,7 @@ from oci.data_science.models import JobRun, Metadata, Model, UpdateModelDetails
|
|
14
15
|
|
15
16
|
from ads.aqua import ODSC_MODEL_COMPARTMENT_OCID, logger
|
16
17
|
from ads.aqua.app import AquaApp
|
18
|
+
from ads.aqua.common.entities import AquaMultiModelRef
|
17
19
|
from ads.aqua.common.enums import (
|
18
20
|
ConfigFolder,
|
19
21
|
CustomInferenceContainerTypeFamily,
|
@@ -42,7 +44,7 @@ from ads.aqua.common.utils import (
|
|
42
44
|
read_file,
|
43
45
|
upload_folder,
|
44
46
|
)
|
45
|
-
from ads.aqua.config.container_config import AquaContainerConfig
|
47
|
+
from ads.aqua.config.container_config import AquaContainerConfig, Usage
|
46
48
|
from ads.aqua.constants import (
|
47
49
|
AQUA_MODEL_ARTIFACT_CONFIG,
|
48
50
|
AQUA_MODEL_ARTIFACT_CONFIG_MODEL_NAME,
|
@@ -77,6 +79,7 @@ from ads.aqua.model.entities import (
|
|
77
79
|
ImportModelDetails,
|
78
80
|
ModelValidationResult,
|
79
81
|
)
|
82
|
+
from ads.aqua.model.enums import MultiModelSupportedTaskType
|
80
83
|
from ads.common.auth import default_signer
|
81
84
|
from ads.common.oci_resource import SEARCH_TYPE, OCIResource
|
82
85
|
from ads.common.utils import UNKNOWN, get_console_link
|
@@ -91,6 +94,7 @@ from ads.config import (
|
|
91
94
|
TENANCY_OCID,
|
92
95
|
)
|
93
96
|
from ads.model import DataScienceModel
|
97
|
+
from ads.model.common.utils import MetadataArtifactPathType
|
94
98
|
from ads.model.model_metadata import (
|
95
99
|
MetadataCustomCategory,
|
96
100
|
ModelCustomMetadata,
|
@@ -135,40 +139,45 @@ class AquaModelApp(AquaApp):
|
|
135
139
|
@telemetry(entry_point="plugin=model&action=create", name="aqua")
|
136
140
|
def create(
|
137
141
|
self,
|
138
|
-
model_id: str,
|
139
|
-
project_id: str,
|
140
|
-
compartment_id: str = None,
|
141
|
-
freeform_tags: Optional[
|
142
|
-
defined_tags: Optional[
|
142
|
+
model_id: Union[str, AquaMultiModelRef],
|
143
|
+
project_id: Optional[str] = None,
|
144
|
+
compartment_id: Optional[str] = None,
|
145
|
+
freeform_tags: Optional[Dict] = None,
|
146
|
+
defined_tags: Optional[Dict] = None,
|
143
147
|
**kwargs,
|
144
148
|
) -> DataScienceModel:
|
145
|
-
"""
|
149
|
+
"""
|
150
|
+
Creates a custom Aqua model from a service model.
|
146
151
|
|
147
152
|
Parameters
|
148
153
|
----------
|
149
|
-
model_id: str
|
150
|
-
The
|
151
|
-
project_id: str
|
152
|
-
The project
|
153
|
-
compartment_id: str
|
154
|
-
The compartment
|
155
|
-
If not provided, compartment
|
156
|
-
freeform_tags:
|
157
|
-
Freeform tags for the model
|
158
|
-
defined_tags:
|
159
|
-
Defined tags for the model
|
154
|
+
model_id : Union[str, AquaMultiModelRef]
|
155
|
+
The model ID as a string or a AquaMultiModelRef instance to be deployed.
|
156
|
+
project_id : Optional[str]
|
157
|
+
The project ID for the custom model.
|
158
|
+
compartment_id : Optional[str]
|
159
|
+
The compartment ID for the custom model. Defaults to None.
|
160
|
+
If not provided, the compartment ID will be fetched from environment variables.
|
161
|
+
freeform_tags : Optional[Dict]
|
162
|
+
Freeform tags for the model.
|
163
|
+
defined_tags : Optional[Dict]
|
164
|
+
Defined tags for the model.
|
165
|
+
|
160
166
|
Returns
|
161
167
|
-------
|
162
|
-
DataScienceModel
|
168
|
+
DataScienceModel
|
163
169
|
The instance of DataScienceModel.
|
164
170
|
"""
|
171
|
+
model_id = (
|
172
|
+
model_id.model_id if isinstance(model_id, AquaMultiModelRef) else model_id
|
173
|
+
)
|
165
174
|
service_model = DataScienceModel.from_id(model_id)
|
166
175
|
target_project = project_id or PROJECT_OCID
|
167
176
|
target_compartment = compartment_id or COMPARTMENT_OCID
|
168
177
|
|
169
178
|
if service_model.compartment_id != ODSC_MODEL_COMPARTMENT_OCID:
|
170
179
|
logger.info(
|
171
|
-
f"Aqua Model {model_id} already exists in user's compartment."
|
180
|
+
f"Aqua Model {model_id} already exists in the user's compartment."
|
172
181
|
"Skipped copying."
|
173
182
|
)
|
174
183
|
return service_model
|
@@ -195,14 +204,13 @@ class AquaModelApp(AquaApp):
|
|
195
204
|
.with_custom_metadata_list(service_model.custom_metadata_list)
|
196
205
|
.with_defined_metadata_list(service_model.defined_metadata_list)
|
197
206
|
.with_provenance_metadata(service_model.provenance_metadata)
|
198
|
-
# TODO: decide what kwargs will be needed.
|
199
207
|
.create(model_by_reference=True, **kwargs)
|
200
208
|
)
|
201
209
|
logger.info(
|
202
210
|
f"Aqua Model {custom_model.id} created with the service model {model_id}."
|
203
211
|
)
|
204
212
|
|
205
|
-
#
|
213
|
+
# Track unique models that were created in the user's compartment
|
206
214
|
self.telemetry.record_event_async(
|
207
215
|
category="aqua/service/model",
|
208
216
|
action="create",
|
@@ -211,6 +219,207 @@ class AquaModelApp(AquaApp):
|
|
211
219
|
|
212
220
|
return custom_model
|
213
221
|
|
222
|
+
@telemetry(entry_point="plugin=model&action=create", name="aqua")
|
223
|
+
def create_multi(
|
224
|
+
self,
|
225
|
+
models: List[AquaMultiModelRef],
|
226
|
+
project_id: Optional[str] = None,
|
227
|
+
compartment_id: Optional[str] = None,
|
228
|
+
freeform_tags: Optional[Dict] = None,
|
229
|
+
defined_tags: Optional[Dict] = None,
|
230
|
+
**kwargs, # noqa: ARG002
|
231
|
+
) -> DataScienceModel:
|
232
|
+
"""
|
233
|
+
Creates a multi-model grouping using the provided model list.
|
234
|
+
|
235
|
+
Parameters
|
236
|
+
----------
|
237
|
+
models : List[AquaMultiModelRef]
|
238
|
+
List of AquaMultiModelRef instances for creating a multi-model group.
|
239
|
+
project_id : Optional[str]
|
240
|
+
The project ID for the multi-model group.
|
241
|
+
compartment_id : Optional[str]
|
242
|
+
The compartment ID for the multi-model group.
|
243
|
+
freeform_tags : Optional[Dict]
|
244
|
+
Freeform tags for the model.
|
245
|
+
defined_tags : Optional[Dict]
|
246
|
+
Defined tags for the model.
|
247
|
+
|
248
|
+
Returns
|
249
|
+
-------
|
250
|
+
DataScienceModel
|
251
|
+
Instance of DataScienceModel object.
|
252
|
+
"""
|
253
|
+
|
254
|
+
if not models:
|
255
|
+
raise AquaValueError(
|
256
|
+
"Model list cannot be empty. Please provide at least one model for deployment."
|
257
|
+
)
|
258
|
+
|
259
|
+
artifact_list = []
|
260
|
+
display_name_list = []
|
261
|
+
model_custom_metadata = ModelCustomMetadata()
|
262
|
+
|
263
|
+
# Get container config
|
264
|
+
container_config = get_container_config()
|
265
|
+
|
266
|
+
service_inference_containers = AquaContainerConfig.from_container_index_json(
|
267
|
+
config=container_config
|
268
|
+
).inference.values()
|
269
|
+
|
270
|
+
supported_container_families = [
|
271
|
+
container_config_item.family
|
272
|
+
for container_config_item in service_inference_containers
|
273
|
+
if any(
|
274
|
+
usage in container_config_item.usages
|
275
|
+
for usage in [Usage.MULTI_MODEL, Usage.OTHER]
|
276
|
+
)
|
277
|
+
]
|
278
|
+
|
279
|
+
if not supported_container_families:
|
280
|
+
raise AquaValueError(
|
281
|
+
"Currently, there are no containers that support multi-model deployment."
|
282
|
+
)
|
283
|
+
|
284
|
+
selected_models_deployment_containers = set()
|
285
|
+
|
286
|
+
# Process each model
|
287
|
+
for model in models:
|
288
|
+
source_model = DataScienceModel.from_id(model.model_id)
|
289
|
+
display_name = source_model.display_name
|
290
|
+
# Update model name in user's input model
|
291
|
+
model.model_name = model.model_name or display_name
|
292
|
+
|
293
|
+
# TODO Uncomment the section below, if only service models should be allowed for multi-model deployment
|
294
|
+
# if not source_model.freeform_tags.get(Tags.AQUA_SERVICE_MODEL_TAG, UNKNOWN):
|
295
|
+
# raise AquaValueError(
|
296
|
+
# f"Invalid selected model {display_name}. "
|
297
|
+
# "Currently only service models are supported for multi model deployment."
|
298
|
+
# )
|
299
|
+
|
300
|
+
if (
|
301
|
+
source_model.freeform_tags.get(Tags.TASK, UNKNOWN).lower()
|
302
|
+
not in MultiModelSupportedTaskType
|
303
|
+
):
|
304
|
+
raise AquaValueError(
|
305
|
+
f"Invalid or missing {Tags.TASK} tag for selected model {display_name}. "
|
306
|
+
f"Currently only `{MultiModelSupportedTaskType.values()}` models are supported for multi model deployment."
|
307
|
+
)
|
308
|
+
|
309
|
+
display_name_list.append(display_name)
|
310
|
+
|
311
|
+
# Retrieve model artifact
|
312
|
+
model_artifact_path = source_model.artifact
|
313
|
+
if not model_artifact_path:
|
314
|
+
raise AquaValueError(
|
315
|
+
f"Model '{display_name}' (ID: {model.model_id}) has no artifacts. "
|
316
|
+
"Please register the model first."
|
317
|
+
)
|
318
|
+
|
319
|
+
# Update model artifact location in user's input model
|
320
|
+
model.artifact_location = model_artifact_path
|
321
|
+
|
322
|
+
artifact_list.append(model_artifact_path)
|
323
|
+
|
324
|
+
# Validate deployment container consistency
|
325
|
+
deployment_container = source_model.custom_metadata_list.get(
|
326
|
+
ModelCustomMetadataFields.DEPLOYMENT_CONTAINER,
|
327
|
+
ModelCustomMetadataItem(
|
328
|
+
key=ModelCustomMetadataFields.DEPLOYMENT_CONTAINER
|
329
|
+
),
|
330
|
+
).value
|
331
|
+
|
332
|
+
if deployment_container not in supported_container_families:
|
333
|
+
raise AquaValueError(
|
334
|
+
f"Unsupported deployment container '{deployment_container}' for model '{source_model.id}'. "
|
335
|
+
f"Only '{supported_container_families}' are supported for multi-model deployments."
|
336
|
+
)
|
337
|
+
|
338
|
+
selected_models_deployment_containers.add(deployment_container)
|
339
|
+
|
340
|
+
# Check if the all models in the group shares same container family
|
341
|
+
if len(selected_models_deployment_containers) > 1:
|
342
|
+
raise AquaValueError(
|
343
|
+
"The selected models are associated with different container families: "
|
344
|
+
f"{list(selected_models_deployment_containers)}."
|
345
|
+
"For multi-model deployment, all models in the group must share the same container family."
|
346
|
+
)
|
347
|
+
|
348
|
+
deployment_container = selected_models_deployment_containers.pop()
|
349
|
+
|
350
|
+
# Generate model group details
|
351
|
+
timestamp = datetime.now().strftime("%Y%m%d")
|
352
|
+
model_group_display_name = f"model_group_{timestamp}"
|
353
|
+
combined_models = ", ".join(display_name_list)
|
354
|
+
model_group_description = f"Multi-model grouping using {combined_models}."
|
355
|
+
|
356
|
+
# Add global metadata
|
357
|
+
model_custom_metadata.add(
|
358
|
+
key=ModelCustomMetadataFields.DEPLOYMENT_CONTAINER,
|
359
|
+
value=deployment_container,
|
360
|
+
description=f"Inference container mapping for {model_group_display_name}",
|
361
|
+
category="Other",
|
362
|
+
)
|
363
|
+
model_custom_metadata.add(
|
364
|
+
key=ModelCustomMetadataFields.MULTIMODEL_GROUP_COUNT,
|
365
|
+
value=str(len(models)),
|
366
|
+
description="Number of models in the group.",
|
367
|
+
category="Other",
|
368
|
+
)
|
369
|
+
|
370
|
+
# Combine tags. The `Tags.AQUA_TAG` has been excluded, because we don't want to show
|
371
|
+
# the models created for multi-model purpose in the AQUA models list.
|
372
|
+
tags = {
|
373
|
+
# Tags.AQUA_TAG: "active",
|
374
|
+
Tags.MULTIMODEL_TYPE_TAG: "true",
|
375
|
+
**(freeform_tags or {}),
|
376
|
+
}
|
377
|
+
|
378
|
+
# Create multi-model group
|
379
|
+
custom_model = (
|
380
|
+
DataScienceModel()
|
381
|
+
.with_compartment_id(compartment_id)
|
382
|
+
.with_project_id(project_id)
|
383
|
+
.with_display_name(model_group_display_name)
|
384
|
+
.with_description(model_group_description)
|
385
|
+
.with_freeform_tags(**tags)
|
386
|
+
.with_defined_tags(**(defined_tags or {}))
|
387
|
+
.with_custom_metadata_list(model_custom_metadata)
|
388
|
+
)
|
389
|
+
|
390
|
+
# Attach artifacts
|
391
|
+
for artifact in artifact_list:
|
392
|
+
custom_model.add_artifact(uri=artifact)
|
393
|
+
|
394
|
+
# Finalize creation
|
395
|
+
custom_model.create(model_by_reference=True)
|
396
|
+
|
397
|
+
logger.info(
|
398
|
+
f"Aqua Model '{custom_model.id}' created with models: {', '.join(display_name_list)}."
|
399
|
+
)
|
400
|
+
|
401
|
+
# Create custom metadata for multi model metadata
|
402
|
+
custom_model.create_custom_metadata_artifact(
|
403
|
+
metadata_key_name=ModelCustomMetadataFields.MULTIMODEL_METADATA,
|
404
|
+
artifact_path_or_content=json.dumps(
|
405
|
+
[model.model_dump() for model in models]
|
406
|
+
).encode(),
|
407
|
+
path_type=MetadataArtifactPathType.CONTENT,
|
408
|
+
)
|
409
|
+
|
410
|
+
logger.debug(
|
411
|
+
f"Multi model metadata uploaded for Aqua model: {custom_model.id}."
|
412
|
+
)
|
413
|
+
|
414
|
+
# Track telemetry event
|
415
|
+
self.telemetry.record_event_async(
|
416
|
+
category="aqua/multimodel",
|
417
|
+
action="create",
|
418
|
+
detail=combined_models,
|
419
|
+
)
|
420
|
+
|
421
|
+
return custom_model
|
422
|
+
|
214
423
|
@telemetry(entry_point="plugin=model&action=get", name="aqua")
|
215
424
|
def get(self, model_id: str, load_model_card: Optional[bool] = True) -> "AquaModel":
|
216
425
|
"""Gets the information of an Aqua model.
|
@@ -1448,8 +1657,9 @@ class AquaModelApp(AquaApp):
|
|
1448
1657
|
self, import_model_details: ImportModelDetails = None, **kwargs
|
1449
1658
|
) -> AquaModel:
|
1450
1659
|
"""Loads the model from object storage and registers as Model in Data Science Model catalog
|
1451
|
-
The inference container and finetuning container could be of type Service
|
1452
|
-
If it is custom, full container URI is expected. If it of type SMC, only the container family name is expected
|
1660
|
+
The inference container and finetuning container could be of type Service Managed Container(SMC) or custom.
|
1661
|
+
If it is custom, full container URI is expected. If it of type SMC, only the container family name is expected.\n
|
1662
|
+
For detailed information about CLI flags see: https://github.com/oracle-samples/oci-data-science-ai-samples/blob/main/ai-quick-actions/cli-tips.md#register-model
|
1453
1663
|
|
1454
1664
|
Args:
|
1455
1665
|
import_model_details (ImportModelDetails): Model details for importing the model.
|
@@ -1609,6 +1819,8 @@ class AquaModelApp(AquaApp):
|
|
1609
1819
|
filter_tag = Tags.AQUA_FINE_TUNED_MODEL_TAG
|
1610
1820
|
elif model_type == ModelType.BASE:
|
1611
1821
|
filter_tag = Tags.BASE_MODEL_CUSTOM
|
1822
|
+
# elif model_type == ModelType.MULTIMODEL:
|
1823
|
+
# filter_tag = Tags.MULTIMODEL_TYPE_TAG
|
1612
1824
|
else:
|
1613
1825
|
raise AquaValueError(
|
1614
1826
|
f"Model of type {model_type} is unknown. The values should be in {ModelType.values()}"
|