oracle-ads 2.12.1__py3-none-any.whl → 2.12.3__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.
Files changed (43) hide show
  1. ads/aqua/common/enums.py +9 -0
  2. ads/aqua/common/utils.py +83 -6
  3. ads/aqua/config/config.py +0 -15
  4. ads/aqua/constants.py +2 -0
  5. ads/aqua/extension/deployment_handler.py +2 -0
  6. ads/aqua/extension/finetune_handler.py +1 -2
  7. ads/aqua/extension/ui_handler.py +22 -3
  8. ads/aqua/finetuning/entities.py +5 -4
  9. ads/aqua/finetuning/finetuning.py +13 -8
  10. ads/aqua/model/constants.py +1 -0
  11. ads/aqua/model/entities.py +2 -0
  12. ads/aqua/model/model.py +223 -138
  13. ads/aqua/modeldeployment/deployment.py +106 -62
  14. ads/aqua/modeldeployment/entities.py +10 -2
  15. ads/aqua/ui.py +29 -16
  16. ads/config.py +3 -8
  17. ads/llm/deploy.py +6 -0
  18. ads/llm/guardrails/base.py +0 -1
  19. ads/llm/langchain/plugins/chat_models/oci_data_science.py +118 -41
  20. ads/llm/langchain/plugins/llms/oci_data_science_model_deployment_endpoint.py +18 -14
  21. ads/llm/templates/score_chain.jinja2 +0 -1
  22. ads/model/datascience_model.py +519 -16
  23. ads/model/deployment/model_deployment.py +13 -0
  24. ads/model/deployment/model_deployment_infrastructure.py +34 -0
  25. ads/model/generic_model.py +10 -0
  26. ads/model/model_properties.py +1 -0
  27. ads/model/service/oci_datascience_model.py +28 -0
  28. ads/opctl/operator/common/data/synthetic.csv +16001 -0
  29. ads/opctl/operator/lowcode/anomaly/MLoperator +1 -0
  30. ads/opctl/operator/lowcode/anomaly/const.py +66 -1
  31. ads/opctl/operator/lowcode/anomaly/model/anomaly_merlion.py +161 -0
  32. ads/opctl/operator/lowcode/anomaly/model/autots.py +30 -15
  33. ads/opctl/operator/lowcode/anomaly/model/factory.py +15 -3
  34. ads/opctl/operator/lowcode/anomaly/model/randomcutforest.py +1 -1
  35. ads/opctl/operator/lowcode/anomaly/schema.yaml +10 -0
  36. ads/opctl/operator/lowcode/anomaly/utils.py +3 -0
  37. {oracle_ads-2.12.1.dist-info → oracle_ads-2.12.3.dist-info}/METADATA +2 -1
  38. {oracle_ads-2.12.1.dist-info → oracle_ads-2.12.3.dist-info}/RECORD +41 -41
  39. ads/aqua/config/deployment_config_defaults.json +0 -37
  40. ads/aqua/config/resource_limit_names.json +0 -8
  41. {oracle_ads-2.12.1.dist-info → oracle_ads-2.12.3.dist-info}/LICENSE.txt +0 -0
  42. {oracle_ads-2.12.1.dist-info → oracle_ads-2.12.3.dist-info}/WHEEL +0 -0
  43. {oracle_ads-2.12.1.dist-info → oracle_ads-2.12.3.dist-info}/entry_points.txt +0 -0
ads/aqua/common/enums.py CHANGED
@@ -52,6 +52,7 @@ class InferenceContainerTypeFamily(str, metaclass=ExtendedEnumMeta):
52
52
  AQUA_VLLM_CONTAINER_FAMILY = "odsc-vllm-serving"
53
53
  AQUA_TGI_CONTAINER_FAMILY = "odsc-tgi-serving"
54
54
  AQUA_LLAMA_CPP_CONTAINER_FAMILY = "odsc-llama-cpp-serving"
55
+ AQUA_TEI_CONTAINER_FAMILY = "odsc-tei-serving"
55
56
 
56
57
 
57
58
  class InferenceContainerParamType(str, metaclass=ExtendedEnumMeta):
@@ -80,3 +81,11 @@ class RqsAdditionalDetails(str, metaclass=ExtendedEnumMeta):
80
81
  MODEL_VERSION_SET_NAME = "modelVersionSetName"
81
82
  PROJECT_ID = "projectId"
82
83
  VERSION_LABEL = "versionLabel"
84
+
85
+
86
+ class TextEmbeddingInferenceContainerParams(str, metaclass=ExtendedEnumMeta):
87
+ """Contains a subset of params that are required for enabling model deployment in OCI Data Science. More options
88
+ are available at https://huggingface.co/docs/text-embeddings-inference/en/cli_arguments"""
89
+
90
+ MODEL_ID = "model-id"
91
+ PORT = "port"
ads/aqua/common/utils.py CHANGED
@@ -35,6 +35,7 @@ from ads.aqua.common.enums import (
35
35
  InferenceContainerParamType,
36
36
  InferenceContainerType,
37
37
  RqsAdditionalDetails,
38
+ TextEmbeddingInferenceContainerParams,
38
39
  )
39
40
  from ads.aqua.common.errors import (
40
41
  AquaFileNotFoundError,
@@ -51,6 +52,7 @@ from ads.aqua.constants import (
51
52
  MODEL_BY_REFERENCE_OSS_PATH_KEY,
52
53
  SERVICE_MANAGED_CONTAINER_URI_SCHEME,
53
54
  SUPPORTED_FILE_FORMATS,
55
+ TEI_CONTAINER_DEFAULT_HOST,
54
56
  TGI_INFERENCE_RESTRICTED_PARAMS,
55
57
  UNKNOWN,
56
58
  UNKNOWN_JSON_STR,
@@ -63,7 +65,12 @@ from ads.common.extended_enum import ExtendedEnumMeta
63
65
  from ads.common.object_storage_details import ObjectStorageDetails
64
66
  from ads.common.oci_resource import SEARCH_TYPE, OCIResource
65
67
  from ads.common.utils import copy_file, get_console_link, upload_to_os
66
- from ads.config import AQUA_SERVICE_MODELS_BUCKET, CONDA_BUCKET_NS, TENANCY_OCID
68
+ from ads.config import (
69
+ AQUA_MODEL_DEPLOYMENT_FOLDER,
70
+ AQUA_SERVICE_MODELS_BUCKET,
71
+ CONDA_BUCKET_NS,
72
+ TENANCY_OCID,
73
+ )
67
74
  from ads.model import DataScienceModel, ModelVersionSet
68
75
 
69
76
  logger = logging.getLogger("ads.aqua")
@@ -569,15 +576,13 @@ def get_container_image(
569
576
  A dict of allowed configs.
570
577
  """
571
578
 
579
+ container_image = UNKNOWN
572
580
  config = config_file_name or get_container_config()
573
581
  config_file_name = service_config_path()
574
582
 
575
583
  if container_type not in config:
576
- raise AquaValueError(
577
- f"{config_file_name} does not have config details for model: {container_type}"
578
- )
584
+ return UNKNOWN
579
585
 
580
- container_image = None
581
586
  mapping = config[container_type]
582
587
  versions = [obj["version"] for obj in mapping]
583
588
  # assumes numbered versions, update if `latest` is used
@@ -1071,7 +1076,6 @@ def list_hf_models(query: str) -> List[str]:
1071
1076
  try:
1072
1077
  models = HfApi().list_models(
1073
1078
  model_name=query,
1074
- task="text-generation",
1075
1079
  sort="downloads",
1076
1080
  direction=-1,
1077
1081
  limit=20,
@@ -1079,3 +1083,76 @@ def list_hf_models(query: str) -> List[str]:
1079
1083
  return [model.id for model in models if model.disabled is None]
1080
1084
  except HfHubHTTPError as err:
1081
1085
  raise format_hf_custom_error_message(err) from err
1086
+
1087
+
1088
+ def generate_tei_cmd_var(os_path: str) -> List[str]:
1089
+ """This utility functions generates CMD params for Text Embedding Inference container. Only the
1090
+ essential parameters for OCI model deployment are added, defaults are used for the rest.
1091
+ Parameters
1092
+ ----------
1093
+ os_path: str
1094
+ OCI bucket path where the model artifacts are uploaded - oci://bucket@namespace/prefix
1095
+
1096
+ Returns
1097
+ -------
1098
+ cmd_var:
1099
+ List of command line arguments
1100
+ """
1101
+
1102
+ cmd_prefix = "--"
1103
+ cmd_var = [
1104
+ f"{cmd_prefix}{TextEmbeddingInferenceContainerParams.MODEL_ID}",
1105
+ f"{AQUA_MODEL_DEPLOYMENT_FOLDER}{ObjectStorageDetails.from_path(os_path.rstrip('/')).filepath}/",
1106
+ f"{cmd_prefix}{TextEmbeddingInferenceContainerParams.PORT}",
1107
+ TEI_CONTAINER_DEFAULT_HOST,
1108
+ ]
1109
+
1110
+ return cmd_var
1111
+
1112
+
1113
+ def parse_cmd_var(cmd_list: List[str]) -> dict:
1114
+ """Helper functions that parses a list into a key-value dictionary. The list contains keys separated by the prefix
1115
+ '--' and the value of the key is the subsequent element.
1116
+ """
1117
+ parsed_cmd = {}
1118
+
1119
+ for i, cmd in enumerate(cmd_list):
1120
+ if cmd.startswith("--"):
1121
+ if i + 1 < len(cmd_list) and not cmd_list[i + 1].startswith("--"):
1122
+ parsed_cmd[cmd] = cmd_list[i + 1]
1123
+ i += 1
1124
+ else:
1125
+ parsed_cmd[cmd] = None
1126
+ return parsed_cmd
1127
+
1128
+
1129
+ def validate_cmd_var(cmd_var: List[str], overrides: List[str]) -> List[str]:
1130
+ """This function accepts two lists of parameters and combines them. If the second list shares the common parameter
1131
+ names/keys, then it raises an error.
1132
+ Parameters
1133
+ ----------
1134
+ cmd_var: List[str]
1135
+ Default list of parameters
1136
+ overrides: List[str]
1137
+ List of parameters to override
1138
+ Returns
1139
+ -------
1140
+ List[str] of combined parameters
1141
+ """
1142
+ cmd_var = [str(x) for x in cmd_var]
1143
+ if not overrides:
1144
+ return cmd_var
1145
+ overrides = [str(x) for x in overrides]
1146
+
1147
+ cmd_dict = parse_cmd_var(cmd_var)
1148
+ overrides_dict = parse_cmd_var(overrides)
1149
+
1150
+ # check for conflicts
1151
+ common_keys = set(cmd_dict.keys()) & set(overrides_dict.keys())
1152
+ if common_keys:
1153
+ raise AquaValueError(
1154
+ f"The following CMD input cannot be overridden for model deployment: {', '.join(common_keys)}"
1155
+ )
1156
+
1157
+ combined_cmd_var = cmd_var + overrides
1158
+ return combined_cmd_var
ads/aqua/config/config.py CHANGED
@@ -29,18 +29,3 @@ def get_evaluation_service_config(
29
29
  .get(ContainerSpec.CONTAINER_SPEC, {})
30
30
  .get(container, {})
31
31
  )
32
-
33
-
34
- # TODO: move this to global config.json in object storage
35
- def get_finetuning_config_defaults():
36
- """Generate and return the fine-tuning default configuration dictionary."""
37
- return {
38
- "shape": {
39
- "VM.GPU.A10.1": {"batch_size": 1, "replica": "1-10"},
40
- "VM.GPU.A10.2": {"batch_size": 1, "replica": "1-10"},
41
- "BM.GPU.A10.4": {"batch_size": 1, "replica": 1},
42
- "BM.GPU4.8": {"batch_size": 4, "replica": 1},
43
- "BM.GPU.A100-v2.8": {"batch_size": 6, "replica": 1},
44
- "BM.GPU.H100.8": {"batch_size": 6, "replica": 1},
45
- }
46
- }
ads/aqua/constants.py CHANGED
@@ -27,6 +27,7 @@ NB_SESSION_IDENTIFIER = "NB_SESSION_OCID"
27
27
  LIFECYCLE_DETAILS_MISSING_JOBRUN = "The associated JobRun resource has been deleted."
28
28
  READY_TO_DEPLOY_STATUS = "ACTIVE"
29
29
  READY_TO_FINE_TUNE_STATUS = "TRUE"
30
+ PRIVATE_ENDPOINT_TYPE = "MODEL_DEPLOYMENT"
30
31
  AQUA_GA_LIST = ["id19sfcrra6z"]
31
32
  AQUA_MODEL_TYPE_SERVICE = "service"
32
33
  AQUA_MODEL_TYPE_CUSTOM = "custom"
@@ -79,3 +80,4 @@ LLAMA_CPP_INFERENCE_RESTRICTED_PARAMS = {
79
80
  "--port",
80
81
  "--host",
81
82
  }
83
+ TEI_CONTAINER_DEFAULT_HOST = "8080"
@@ -102,6 +102,7 @@ class AquaDeploymentHandler(AquaAPIhandler):
102
102
  ocpus = input_data.get("ocpus")
103
103
  memory_in_gbs = input_data.get("memory_in_gbs")
104
104
  model_file = input_data.get("model_file")
105
+ private_endpoint_id = input_data.get("private_endpoint_id")
105
106
 
106
107
  self.finish(
107
108
  AquaDeploymentApp().create(
@@ -124,6 +125,7 @@ class AquaDeploymentHandler(AquaAPIhandler):
124
125
  ocpus=ocpus,
125
126
  memory_in_gbs=memory_in_gbs,
126
127
  model_file=model_file,
128
+ private_endpoint_id=private_endpoint_id,
127
129
  )
128
130
  )
129
131
 
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
2
  # Copyright (c) 2024 Oracle and/or its affiliates.
4
3
  # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
5
4
 
@@ -9,8 +8,8 @@ from urllib.parse import urlparse
9
8
  from tornado.web import HTTPError
10
9
 
11
10
  from ads.aqua.common.decorator import handle_exceptions
12
- from ads.aqua.extension.errors import Errors
13
11
  from ads.aqua.extension.base_handler import AquaAPIhandler
12
+ from ads.aqua.extension.errors import Errors
14
13
  from ads.aqua.extension.utils import validate_function_parameters
15
14
  from ads.aqua.finetuning import AquaFineTuningApp
16
15
  from ads.aqua.finetuning.entities import CreateFineTuningDetails
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
2
  # Copyright (c) 2024 Oracle and/or its affiliates.
4
3
  # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
5
4
 
@@ -10,8 +9,9 @@ from tornado.web import HTTPError
10
9
 
11
10
  from ads.aqua.common.decorator import handle_exceptions
12
11
  from ads.aqua.common.enums import Tags
13
- from ads.aqua.extension.errors import Errors
12
+ from ads.aqua.constants import PRIVATE_ENDPOINT_TYPE
14
13
  from ads.aqua.extension.base_handler import AquaAPIhandler
14
+ from ads.aqua.extension.errors import Errors
15
15
  from ads.aqua.extension.utils import validate_function_parameters
16
16
  from ads.aqua.model.entities import ImportModelDetails
17
17
  from ads.aqua.ui import AquaUIApp
@@ -72,6 +72,8 @@ class AquaUIHandler(AquaAPIhandler):
72
72
  return self.list_vcn()
73
73
  elif paths.startswith("aqua/subnets"):
74
74
  return self.list_subnets()
75
+ elif paths.startswith("aqua/privateendpoints"):
76
+ return self.list_private_endpoints()
75
77
  elif paths.startswith("aqua/shapes/limit"):
76
78
  return self.get_shape_availability()
77
79
  elif paths.startswith("aqua/bucket/versioning"):
@@ -175,15 +177,31 @@ class AquaUIHandler(AquaAPIhandler):
175
177
  )
176
178
  )
177
179
 
180
+ def list_private_endpoints(self, **kwargs):
181
+ """Lists the private endpoints in the specified compartment."""
182
+ compartment_id = self.get_argument("compartment_id", default=COMPARTMENT_OCID)
183
+ resource_type = self.get_argument(
184
+ "resource_type", default=PRIVATE_ENDPOINT_TYPE
185
+ )
186
+ return self.finish(
187
+ AquaUIApp().list_private_endpoints(
188
+ compartment_id=compartment_id, resource_type=resource_type, **kwargs
189
+ )
190
+ )
191
+
178
192
  def get_shape_availability(self, **kwargs):
179
193
  """For a given compartmentId, resource limit name, and scope, returns the number of available resources associated
180
194
  with the given limit."""
181
195
  compartment_id = self.get_argument("compartment_id", default=COMPARTMENT_OCID)
182
196
  instance_shape = self.get_argument("instance_shape")
197
+ limit_name = self.get_argument("limit_name")
183
198
 
184
199
  return self.finish(
185
200
  AquaUIApp().get_shape_availability(
186
- compartment_id=compartment_id, instance_shape=instance_shape, **kwargs
201
+ compartment_id=compartment_id,
202
+ instance_shape=instance_shape,
203
+ limit_name=limit_name,
204
+ **kwargs,
187
205
  )
188
206
  )
189
207
 
@@ -244,6 +262,7 @@ __handlers__ = [
244
262
  ("job/shapes/?([^/]*)", AquaUIHandler),
245
263
  ("vcn/?([^/]*)", AquaUIHandler),
246
264
  ("subnets/?([^/]*)", AquaUIHandler),
265
+ ("privateendpoints/?([^/]*)", AquaUIHandler),
247
266
  ("shapes/limit/?([^/]*)", AquaUIHandler),
248
267
  ("bucket/versioning/?([^/]*)", AquaUIHandler),
249
268
  ("containers/?([^/]*)", AquaUIHandler),
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
2
  # Copyright (c) 2024 Oracle and/or its affiliates.
4
3
  # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
5
4
  from dataclasses import dataclass, field
@@ -14,9 +13,9 @@ class AquaFineTuningParams(DataClassSerializable):
14
13
  epochs: int
15
14
  learning_rate: Optional[float] = None
16
15
  sample_packing: Optional[bool] = "auto"
17
- batch_size: Optional[
18
- int
19
- ] = None # make it batch_size for user, but internally this is micro_batch_size
16
+ batch_size: Optional[int] = (
17
+ None # make it batch_size for user, but internally this is micro_batch_size
18
+ )
20
19
  sequence_len: Optional[int] = None
21
20
  pad_to_sequence_len: Optional[bool] = None
22
21
  lora_r: Optional[int] = None
@@ -24,6 +23,8 @@ class AquaFineTuningParams(DataClassSerializable):
24
23
  lora_dropout: Optional[float] = None
25
24
  lora_target_linear: Optional[bool] = None
26
25
  lora_target_modules: Optional[List] = None
26
+ early_stopping_patience: Optional[int] = None
27
+ early_stopping_threshold: Optional[float] = None
27
28
 
28
29
 
29
30
  @dataclass(repr=False)
@@ -1,11 +1,10 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
2
  # Copyright (c) 2024 Oracle and/or its affiliates.
4
3
  # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
5
4
 
6
5
  import json
7
6
  import os
8
- from dataclasses import asdict, fields, MISSING
7
+ from dataclasses import MISSING, asdict, fields
9
8
  from typing import Dict
10
9
 
11
10
  from oci.data_science.models import (
@@ -14,7 +13,7 @@ from oci.data_science.models import (
14
13
  UpdateModelProvenanceDetails,
15
14
  )
16
15
 
17
- from ads.aqua import ODSC_MODEL_COMPARTMENT_OCID, logger
16
+ from ads.aqua import logger
18
17
  from ads.aqua.app import AquaApp
19
18
  from ads.aqua.common.enums import Resource, Tags
20
19
  from ads.aqua.common.errors import AquaFileExistsError, AquaValueError
@@ -31,7 +30,6 @@ from ads.aqua.constants import (
31
30
  UNKNOWN,
32
31
  UNKNOWN_DICT,
33
32
  )
34
- from ads.aqua.config.config import get_finetuning_config_defaults
35
33
  from ads.aqua.data import AquaResourceIdentifier
36
34
  from ads.aqua.finetuning.constants import *
37
35
  from ads.aqua.finetuning.entities import *
@@ -132,7 +130,7 @@ class AquaFineTuningApp(AquaApp):
132
130
  or create_fine_tuning_details.validation_set_size >= 1
133
131
  ):
134
132
  raise AquaValueError(
135
- f"Fine tuning validation set size should be a float number in between [0, 1)."
133
+ "Fine tuning validation set size should be a float number in between [0, 1)."
136
134
  )
137
135
 
138
136
  if create_fine_tuning_details.replica < DEFAULT_FT_REPLICA:
@@ -394,7 +392,7 @@ class AquaFineTuningApp(AquaApp):
394
392
  )
395
393
  # track shapes that were used for fine-tune creation
396
394
  self.telemetry.record_event_async(
397
- category=f"aqua/service/finetune/create/shape/",
395
+ category="aqua/service/finetune/create/shape/",
398
396
  action=f"{create_fine_tuning_details.shape_name}x{create_fine_tuning_details.replica}",
399
397
  **telemetry_kwargs,
400
398
  )
@@ -533,6 +531,12 @@ class AquaFineTuningApp(AquaApp):
533
531
  oci_launch_cmd += f"--num_{key} {value} "
534
532
  elif key == "lora_target_modules":
535
533
  oci_launch_cmd += f"--{key} {','.join(str(k) for k in value)} "
534
+ elif key == "early_stopping_patience":
535
+ if value != 0:
536
+ oci_launch_cmd += f"--{key} {value} "
537
+ elif key == "early_stopping_threshold":
538
+ if "early_stopping_patience" in oci_launch_cmd:
539
+ oci_launch_cmd += f"--{key} {value} "
536
540
  else:
537
541
  oci_launch_cmd += f"--{key} {value} "
538
542
 
@@ -558,8 +562,9 @@ class AquaFineTuningApp(AquaApp):
558
562
 
559
563
  config = self.get_config(model_id, AQUA_MODEL_FINETUNING_CONFIG)
560
564
  if not config:
561
- logger.info(f"Fetching default fine-tuning config for model: {model_id}")
562
- config = get_finetuning_config_defaults()
565
+ logger.debug(
566
+ f"Fine-tuning config for custom model: {model_id} is not available."
567
+ )
563
568
  return config
564
569
 
565
570
  @telemetry(
@@ -17,6 +17,7 @@ class ModelCustomMetadataFields(str, metaclass=ExtendedEnumMeta):
17
17
  DEPLOYMENT_CONTAINER = "deployment-container"
18
18
  EVALUATION_CONTAINER = "evaluation-container"
19
19
  FINETUNE_CONTAINER = "finetune-container"
20
+ DEPLOYMENT_CONTAINER_URI = "deployment-container-uri"
20
21
 
21
22
 
22
23
  class ModelTask(str, metaclass=ExtendedEnumMeta):
@@ -98,6 +98,7 @@ class AquaModel(AquaModelSummary, DataClassSerializable):
98
98
 
99
99
  model_card: str = None
100
100
  inference_container: str = None
101
+ inference_container_uri: str = None
101
102
  finetuning_container: str = None
102
103
  evaluation_container: str = None
103
104
  artifact_location: str = None
@@ -287,6 +288,7 @@ class ImportModelDetails(CLIBuilderMixin):
287
288
  compartment_id: Optional[str] = None
288
289
  project_id: Optional[str] = None
289
290
  model_file: Optional[str] = None
291
+ inference_container_uri: Optional[str] = None
290
292
 
291
293
  def __post_init__(self):
292
294
  self._command = "model register"