oracle-ads 2.13.10rc0__py3-none-any.whl → 2.13.12__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 +13 -7
- ads/aqua/cli.py +15 -0
- ads/aqua/common/entities.py +31 -5
- ads/aqua/common/utils.py +35 -0
- ads/aqua/config/container_config.py +0 -1
- ads/aqua/evaluation/evaluation.py +5 -4
- ads/aqua/extension/deployment_handler.py +4 -1
- ads/aqua/extension/model_handler.py +1 -1
- ads/aqua/model/enums.py +19 -1
- ads/aqua/model/model.py +45 -36
- ads/aqua/model/utils.py +1 -2
- ads/aqua/modeldeployment/config_loader.py +815 -0
- ads/aqua/modeldeployment/constants.py +4 -1
- ads/aqua/modeldeployment/deployment.py +100 -124
- ads/aqua/modeldeployment/entities.py +4 -178
- ads/aqua/modeldeployment/model_group_config.py +240 -0
- ads/aqua/modeldeployment/utils.py +0 -539
- ads/common/work_request.py +39 -38
- ads/jobs/builders/infrastructure/dsc_job.py +121 -24
- ads/jobs/builders/infrastructure/dsc_job_runtime.py +71 -24
- ads/jobs/builders/runtimes/base.py +7 -5
- ads/jobs/builders/runtimes/pytorch_runtime.py +6 -8
- ads/jobs/templates/driver_pytorch.py +486 -172
- ads/jobs/templates/driver_utils.py +27 -11
- ads/model/service/oci_datascience_model_deployment.py +6 -11
- ads/telemetry/client.py +4 -4
- {oracle_ads-2.13.10rc0.dist-info → oracle_ads-2.13.12.dist-info}/METADATA +2 -2
- {oracle_ads-2.13.10rc0.dist-info → oracle_ads-2.13.12.dist-info}/RECORD +31 -29
- {oracle_ads-2.13.10rc0.dist-info → oracle_ads-2.13.12.dist-info}/WHEEL +0 -0
- {oracle_ads-2.13.10rc0.dist-info → oracle_ads-2.13.12.dist-info}/entry_points.txt +0 -0
- {oracle_ads-2.13.10rc0.dist-info → oracle_ads-2.13.12.dist-info}/licenses/LICENSE.txt +0 -0
ads/aqua/app.py
CHANGED
@@ -22,7 +22,7 @@ from ads import set_auth
|
|
22
22
|
from ads.aqua import logger
|
23
23
|
from ads.aqua.common.entities import ModelConfigResult
|
24
24
|
from ads.aqua.common.enums import ConfigFolder, Tags
|
25
|
-
from ads.aqua.common.errors import
|
25
|
+
from ads.aqua.common.errors import AquaValueError
|
26
26
|
from ads.aqua.common.utils import (
|
27
27
|
_is_valid_mvs,
|
28
28
|
get_artifact_path,
|
@@ -284,8 +284,11 @@ class AquaApp:
|
|
284
284
|
logger.info(f"Artifact not found in model {model_id}.")
|
285
285
|
return False
|
286
286
|
|
287
|
+
@cached(cache=TTLCache(maxsize=5, ttl=timedelta(minutes=1), timer=datetime.now))
|
287
288
|
def get_config_from_metadata(
|
288
|
-
self,
|
289
|
+
self,
|
290
|
+
model_id: str,
|
291
|
+
metadata_key: str,
|
289
292
|
) -> ModelConfigResult:
|
290
293
|
"""Gets the config for the given Aqua model from model catalog metadata content.
|
291
294
|
|
@@ -300,8 +303,9 @@ class AquaApp:
|
|
300
303
|
ModelConfigResult
|
301
304
|
A Pydantic model containing the model_details (extracted from OCI) and the config dictionary.
|
302
305
|
"""
|
303
|
-
config = {}
|
306
|
+
config: Dict[str, Any] = {}
|
304
307
|
oci_model = self.ds_client.get_model(model_id).data
|
308
|
+
|
305
309
|
try:
|
306
310
|
config = self.ds_client.get_model_defined_metadatum_artifact_content(
|
307
311
|
model_id, metadata_key
|
@@ -321,7 +325,7 @@ class AquaApp:
|
|
321
325
|
)
|
322
326
|
return ModelConfigResult(config=config, model_details=oci_model)
|
323
327
|
|
324
|
-
@cached(cache=TTLCache(maxsize=1, ttl=timedelta(minutes=
|
328
|
+
@cached(cache=TTLCache(maxsize=1, ttl=timedelta(minutes=5), timer=datetime.now))
|
325
329
|
def get_config(
|
326
330
|
self,
|
327
331
|
model_id: str,
|
@@ -346,8 +350,10 @@ class AquaApp:
|
|
346
350
|
ModelConfigResult
|
347
351
|
A Pydantic model containing the model_details (extracted from OCI) and the config dictionary.
|
348
352
|
"""
|
349
|
-
|
353
|
+
config: Dict[str, Any] = {}
|
350
354
|
oci_model = self.ds_client.get_model(model_id).data
|
355
|
+
|
356
|
+
config_folder = config_folder or ConfigFolder.CONFIG
|
351
357
|
oci_aqua = (
|
352
358
|
(
|
353
359
|
Tags.AQUA_TAG in oci_model.freeform_tags
|
@@ -357,9 +363,9 @@ class AquaApp:
|
|
357
363
|
else False
|
358
364
|
)
|
359
365
|
if not oci_aqua:
|
360
|
-
|
366
|
+
logger.debug(f"Target model {oci_model.id} is not an Aqua model.")
|
367
|
+
return ModelConfigResult(config=config, model_details=oci_model)
|
361
368
|
|
362
|
-
config: Dict[str, Any] = {}
|
363
369
|
artifact_path = get_artifact_path(oci_model.custom_metadata_list)
|
364
370
|
if not artifact_path:
|
365
371
|
logger.debug(
|
ads/aqua/cli.py
CHANGED
@@ -94,3 +94,18 @@ class AquaCommand:
|
|
94
94
|
"If you intend to chain a function call to the result, please separate the "
|
95
95
|
"flag and the subsequent function call with separator `-`."
|
96
96
|
)
|
97
|
+
|
98
|
+
@staticmethod
|
99
|
+
def install():
|
100
|
+
"""Install ADS Aqua Extension from wheel file. Set enviroment variable `AQUA_EXTENSTION_PATH` to change the wheel file path.
|
101
|
+
|
102
|
+
Return
|
103
|
+
------
|
104
|
+
int:
|
105
|
+
Installatation status.
|
106
|
+
"""
|
107
|
+
import subprocess
|
108
|
+
|
109
|
+
wheel_file_path = os.environ.get("AQUA_EXTENSTION_PATH", "/ads/extension/adsjupyterlab_aqua_extension*.whl")
|
110
|
+
status = subprocess.run(f"pip install {wheel_file_path}",shell=True)
|
111
|
+
return status.check_returncode
|
ads/aqua/common/entities.py
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
4
4
|
|
5
5
|
import re
|
6
|
-
from typing import Any, Dict, Optional
|
6
|
+
from typing import Any, Dict, List, Optional
|
7
7
|
|
8
8
|
from oci.data_science.models import Model
|
9
9
|
from pydantic import BaseModel, Field, model_validator
|
@@ -136,6 +136,28 @@ class ComputeShapeSummary(Serializable):
|
|
136
136
|
return model
|
137
137
|
|
138
138
|
|
139
|
+
class LoraModuleSpec(Serializable):
|
140
|
+
"""
|
141
|
+
Lightweight descriptor for LoRA Modules used in fine-tuning models.
|
142
|
+
|
143
|
+
Attributes
|
144
|
+
----------
|
145
|
+
model_id : str
|
146
|
+
The unique identifier of the fine tuned model.
|
147
|
+
model_name : str
|
148
|
+
The name of the fine-tuned model.
|
149
|
+
model_path : str
|
150
|
+
The model-by-reference path to the LoRA Module within the model artifact
|
151
|
+
"""
|
152
|
+
|
153
|
+
model_id: Optional[str] = Field(None, description="The fine tuned model OCID to deploy.")
|
154
|
+
model_name: Optional[str] = Field(None, description="The name of the fine-tuned model.")
|
155
|
+
model_path: Optional[str] = Field(
|
156
|
+
None,
|
157
|
+
description="The model-by-reference path to the LoRA Module within the model artifact.",
|
158
|
+
)
|
159
|
+
|
160
|
+
|
139
161
|
class AquaMultiModelRef(Serializable):
|
140
162
|
"""
|
141
163
|
Lightweight model descriptor used for multi-model deployment.
|
@@ -157,7 +179,7 @@ class AquaMultiModelRef(Serializable):
|
|
157
179
|
Optional environment variables to override during deployment.
|
158
180
|
artifact_location : Optional[str]
|
159
181
|
Artifact path of model in the multimodel group.
|
160
|
-
|
182
|
+
fine_tune_weights : Optional[List[LoraModuleSpec]]
|
161
183
|
For fine tuned models, the artifact path of the modified model weights
|
162
184
|
"""
|
163
185
|
|
@@ -166,15 +188,19 @@ class AquaMultiModelRef(Serializable):
|
|
166
188
|
gpu_count: Optional[int] = Field(
|
167
189
|
None, description="The gpu count allocation for the model."
|
168
190
|
)
|
169
|
-
model_task: Optional[str] = Field(
|
191
|
+
model_task: Optional[str] = Field(
|
192
|
+
None,
|
193
|
+
description="The task that model operates on. Supported tasks are in MultiModelSupportedTaskType",
|
194
|
+
)
|
170
195
|
env_var: Optional[dict] = Field(
|
171
196
|
default_factory=dict, description="The environment variables of the model."
|
172
197
|
)
|
173
198
|
artifact_location: Optional[str] = Field(
|
174
199
|
None, description="Artifact path of model in the multimodel group."
|
175
200
|
)
|
176
|
-
|
177
|
-
None,
|
201
|
+
fine_tune_weights: Optional[List[LoraModuleSpec]] = Field(
|
202
|
+
None,
|
203
|
+
description="For fine tuned models, the artifact path of the modified model weights",
|
178
204
|
)
|
179
205
|
|
180
206
|
class Config:
|
ads/aqua/common/utils.py
CHANGED
@@ -870,6 +870,41 @@ def get_combined_params(params1: str = None, params2: str = None) -> str:
|
|
870
870
|
return " ".join(combined_params)
|
871
871
|
|
872
872
|
|
873
|
+
def find_restricted_params(
|
874
|
+
default_params: Union[str, List[str]],
|
875
|
+
user_params: Union[str, List[str]],
|
876
|
+
container_family: str,
|
877
|
+
) -> List[str]:
|
878
|
+
"""Returns a list of restricted params that user chooses to override when creating an Aqua deployment.
|
879
|
+
The default parameters coming from the container index json file cannot be overridden.
|
880
|
+
|
881
|
+
Parameters
|
882
|
+
----------
|
883
|
+
default_params:
|
884
|
+
Inference container parameter string with default values.
|
885
|
+
user_params:
|
886
|
+
Inference container parameter string with user provided values.
|
887
|
+
container_family: str
|
888
|
+
The image family of model deployment container runtime.
|
889
|
+
|
890
|
+
Returns
|
891
|
+
-------
|
892
|
+
A list with params keys common between params1 and params2.
|
893
|
+
|
894
|
+
"""
|
895
|
+
restricted_params = []
|
896
|
+
if default_params and user_params:
|
897
|
+
default_params_dict = get_params_dict(default_params)
|
898
|
+
user_params_dict = get_params_dict(user_params)
|
899
|
+
|
900
|
+
restricted_params_set = get_restricted_params_by_container(container_family)
|
901
|
+
for key, _items in user_params_dict.items():
|
902
|
+
if key in default_params_dict or key in restricted_params_set:
|
903
|
+
restricted_params.append(key.lstrip("-"))
|
904
|
+
|
905
|
+
return restricted_params
|
906
|
+
|
907
|
+
|
873
908
|
def build_params_string(params: dict) -> str:
|
874
909
|
"""Builds params string from params dict
|
875
910
|
|
@@ -196,7 +196,6 @@ class AquaContainerConfig(Serializable):
|
|
196
196
|
config_keys = {
|
197
197
|
"MODEL_DEPLOY_PREDICT_ENDPOINT": UNKNOWN,
|
198
198
|
"MODEL_DEPLOY_HEALTH_ENDPOINT": UNKNOWN,
|
199
|
-
"MODEL_DEPLOY_ENABLE_STREAMING": UNKNOWN,
|
200
199
|
"PORT": UNKNOWN,
|
201
200
|
"HEALTH_CHECK_PORT": UNKNOWN,
|
202
201
|
"VLLM_USE_V1": UNKNOWN,
|
@@ -727,10 +727,11 @@ class AquaEvaluationApp(AquaApp):
|
|
727
727
|
raise AquaRuntimeError(error_message) from ex
|
728
728
|
|
729
729
|
# Build the list of valid model names from custom metadata.
|
730
|
-
model_names = [
|
731
|
-
|
732
|
-
|
733
|
-
|
730
|
+
model_names = []
|
731
|
+
for metadata in multi_model_metadata:
|
732
|
+
model = AquaMultiModelRef(**metadata)
|
733
|
+
model_names.append(model.model_name)
|
734
|
+
model_names.extend(ft.model_name for ft in (model.fine_tune_weights or []) if ft.model_name)
|
734
735
|
|
735
736
|
# Check if the provided model name is among the valid names.
|
736
737
|
if user_model_name not in model_names:
|
@@ -246,7 +246,10 @@ class AquaDeploymentStreamingInferenceHandler(AquaAPIhandler):
|
|
246
246
|
stream=True,
|
247
247
|
):
|
248
248
|
try:
|
249
|
-
|
249
|
+
if "text" in chunk["choices"][0]:
|
250
|
+
yield chunk["choices"][0]["text"]
|
251
|
+
elif "content" in chunk["choices"][0]["delta"]:
|
252
|
+
yield chunk["choices"][0]["delta"]["content"]
|
250
253
|
except Exception as e:
|
251
254
|
logger.debug(
|
252
255
|
f"Exception occurred while parsing streaming response: {e}"
|
@@ -241,7 +241,7 @@ class AquaHuggingFaceHandler(AquaAPIhandler):
|
|
241
241
|
aqua_model_app = AquaModelApp()
|
242
242
|
model_ocid = aqua_model_app._find_matching_aqua_model(model_id=model_id_lower)
|
243
243
|
if model_ocid:
|
244
|
-
return aqua_model_app.get(model_ocid
|
244
|
+
return aqua_model_app.get(model_ocid)
|
245
245
|
|
246
246
|
return None
|
247
247
|
|
ads/aqua/model/enums.py
CHANGED
@@ -27,6 +27,24 @@ class FineTuningCustomMetadata(ExtendedEnum):
|
|
27
27
|
|
28
28
|
class MultiModelSupportedTaskType(ExtendedEnum):
|
29
29
|
TEXT_GENERATION = "text_generation"
|
30
|
+
TEXT_GENERATION_INFERENCE = "text_generation_inference"
|
31
|
+
TEXT2TEXT_GENERATION = "text2text_generation"
|
32
|
+
SUMMARIZATION = "summarization"
|
33
|
+
TRANSLATION = "translation"
|
34
|
+
CONVERSATIONAL = "conversational"
|
35
|
+
FEATURE_EXTRACTION = "feature_extraction"
|
36
|
+
SENTENCE_SIMILARITY = "sentence_similarity"
|
37
|
+
AUTOMATIC_SPEECH_RECOGNITION = "automatic_speech_recognition"
|
38
|
+
TEXT_TO_SPEECH = "text_to_speech"
|
39
|
+
TEXT_TO_IMAGE = "text_to_image"
|
40
|
+
TEXT_EMBEDDING = "text_embedding"
|
30
41
|
IMAGE_TEXT_TO_TEXT = "image_text_to_text"
|
31
42
|
CODE_SYNTHESIS = "code_synthesis"
|
32
|
-
|
43
|
+
QUESTION_ANSWERING = "question_answering"
|
44
|
+
AUDIO_CLASSIFICATION = "audio_classification"
|
45
|
+
AUDIO_TO_AUDIO = "audio_to_audio"
|
46
|
+
IMAGE_CLASSIFICATION = "image_classification"
|
47
|
+
IMAGE_TO_TEXT = "image_to_text"
|
48
|
+
IMAGE_TO_IMAGE = "image_to_image"
|
49
|
+
VIDEO_CLASSIFICATION = "video_classification"
|
50
|
+
TIME_SERIES_FORECASTING = "time_series_forecasting"
|
ads/aqua/model/model.py
CHANGED
@@ -16,7 +16,7 @@ from oci.data_science.models import JobRun, Metadata, Model, UpdateModelDetails
|
|
16
16
|
|
17
17
|
from ads.aqua import logger
|
18
18
|
from ads.aqua.app import AquaApp
|
19
|
-
from ads.aqua.common.entities import AquaMultiModelRef
|
19
|
+
from ads.aqua.common.entities import AquaMultiModelRef, LoraModuleSpec
|
20
20
|
from ads.aqua.common.enums import (
|
21
21
|
ConfigFolder,
|
22
22
|
CustomInferenceContainerTypeFamily,
|
@@ -89,12 +89,7 @@ from ads.aqua.model.utils import (
|
|
89
89
|
)
|
90
90
|
from ads.common.auth import default_signer
|
91
91
|
from ads.common.oci_resource import SEARCH_TYPE, OCIResource
|
92
|
-
from ads.common.utils import
|
93
|
-
UNKNOWN,
|
94
|
-
get_console_link,
|
95
|
-
is_path_exists,
|
96
|
-
read_file,
|
97
|
-
)
|
92
|
+
from ads.common.utils import UNKNOWN, get_console_link, is_path_exists, read_file
|
98
93
|
from ads.config import (
|
99
94
|
AQUA_DEPLOYMENT_CONTAINER_CMD_VAR_METADATA_NAME,
|
100
95
|
AQUA_DEPLOYMENT_CONTAINER_METADATA_NAME,
|
@@ -300,57 +295,73 @@ class AquaModelApp(AquaApp):
|
|
300
295
|
|
301
296
|
selected_models_deployment_containers = set()
|
302
297
|
|
303
|
-
# Process each model
|
298
|
+
# Process each model in the input list
|
304
299
|
for model in models:
|
300
|
+
# Retrieve model metadata from the Model Catalog using the model ID
|
305
301
|
source_model = DataScienceModel.from_id(model.model_id)
|
306
302
|
display_name = source_model.display_name
|
307
303
|
model_file_description = source_model.model_file_description
|
308
|
-
#
|
304
|
+
# If model_name is not explicitly provided, use the model's display name
|
309
305
|
model.model_name = model.model_name or display_name
|
310
306
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
# )
|
307
|
+
if not model_file_description:
|
308
|
+
raise AquaValueError(
|
309
|
+
f"Model '{source_model.display_name}' (ID: {model.model_id}) has no file description. "
|
310
|
+
"Please register the model first."
|
311
|
+
)
|
317
312
|
|
318
|
-
#
|
313
|
+
# Check if the model is a fine-tuned model based on its tags
|
319
314
|
is_fine_tuned_model = (
|
320
315
|
Tags.AQUA_FINE_TUNED_MODEL_TAG in source_model.freeform_tags
|
321
316
|
)
|
322
317
|
|
318
|
+
base_model_artifact_path = ""
|
319
|
+
fine_tune_path = ""
|
320
|
+
|
323
321
|
if is_fine_tuned_model:
|
324
|
-
|
325
|
-
|
326
|
-
)
|
327
|
-
model_artifact_path, model.fine_tune_weights_location = (
|
322
|
+
# Extract artifact paths for the base and fine-tuned model
|
323
|
+
base_model_artifact_path, fine_tune_path = (
|
328
324
|
extract_fine_tune_artifacts_path(source_model)
|
329
325
|
)
|
330
326
|
|
331
|
-
|
332
|
-
#
|
333
|
-
|
327
|
+
# Create a single LoRA module specification for the fine-tuned model
|
328
|
+
# TODO: Support multiple LoRA modules in the future
|
329
|
+
model.fine_tune_weights = [
|
330
|
+
LoraModuleSpec(
|
331
|
+
model_id=model.model_id,
|
332
|
+
model_name=model.model_name,
|
333
|
+
model_path=fine_tune_path,
|
334
|
+
)
|
335
|
+
]
|
334
336
|
|
335
|
-
|
337
|
+
# Use the LoRA module name as the model's display name
|
338
|
+
display_name = model.model_name
|
336
339
|
|
337
|
-
|
340
|
+
# Temporarily override model ID and name with those of the base model
|
341
|
+
# TODO: Revisit this logic once proper base/FT model handling is implemented
|
342
|
+
model.model_id, model.model_name = extract_base_model_from_ft(
|
343
|
+
source_model
|
344
|
+
)
|
345
|
+
else:
|
346
|
+
# For base models, use the original artifact path
|
347
|
+
base_model_artifact_path = source_model.artifact
|
348
|
+
display_name = model.model_name
|
338
349
|
|
339
|
-
if not
|
350
|
+
if not base_model_artifact_path:
|
351
|
+
# Fail if no artifact is found for the base model model
|
340
352
|
raise AquaValueError(
|
341
|
-
f"Model '{
|
353
|
+
f"Model '{model.model_name}' (ID: {model.model_id}) has no artifacts. "
|
342
354
|
"Please register the model first."
|
343
355
|
)
|
344
356
|
|
345
|
-
# Update
|
346
|
-
model.artifact_location =
|
357
|
+
# Update the artifact path in the model configuration
|
358
|
+
model.artifact_location = base_model_artifact_path
|
359
|
+
display_name_list.append(display_name)
|
347
360
|
|
348
|
-
|
349
|
-
|
350
|
-
f"Model '{display_name}' (ID: {model.model_id}) has no file description. "
|
351
|
-
"Please register the model first."
|
352
|
-
)
|
361
|
+
# Extract model task metadata from source model
|
362
|
+
self._extract_model_task(model, source_model)
|
353
363
|
|
364
|
+
# Track model file description in a validated structure
|
354
365
|
model_file_description_list.append(
|
355
366
|
ModelFileDescription(**model_file_description)
|
356
367
|
)
|
@@ -480,8 +491,6 @@ class AquaModelApp(AquaApp):
|
|
480
491
|
----------
|
481
492
|
model_id: str
|
482
493
|
The model OCID.
|
483
|
-
load_model_card: (bool, optional). Defaults to `True`.
|
484
|
-
Whether to load model card from artifacts or not.
|
485
494
|
|
486
495
|
Returns
|
487
496
|
-------
|
ads/aqua/model/utils.py
CHANGED
@@ -3,9 +3,8 @@
|
|
3
3
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
4
4
|
"""AQUA model utils"""
|
5
5
|
|
6
|
-
from typing import
|
6
|
+
from typing import Tuple
|
7
7
|
|
8
|
-
from ads.aqua.common.entities import AquaMultiModelRef
|
9
8
|
from ads.aqua.common.errors import AquaValueError
|
10
9
|
from ads.aqua.common.utils import get_model_by_reference_paths
|
11
10
|
from ads.aqua.finetuning.constants import FineTuneCustomMetadata
|