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.
Files changed (31) hide show
  1. ads/aqua/app.py +13 -7
  2. ads/aqua/cli.py +15 -0
  3. ads/aqua/common/entities.py +31 -5
  4. ads/aqua/common/utils.py +35 -0
  5. ads/aqua/config/container_config.py +0 -1
  6. ads/aqua/evaluation/evaluation.py +5 -4
  7. ads/aqua/extension/deployment_handler.py +4 -1
  8. ads/aqua/extension/model_handler.py +1 -1
  9. ads/aqua/model/enums.py +19 -1
  10. ads/aqua/model/model.py +45 -36
  11. ads/aqua/model/utils.py +1 -2
  12. ads/aqua/modeldeployment/config_loader.py +815 -0
  13. ads/aqua/modeldeployment/constants.py +4 -1
  14. ads/aqua/modeldeployment/deployment.py +100 -124
  15. ads/aqua/modeldeployment/entities.py +4 -178
  16. ads/aqua/modeldeployment/model_group_config.py +240 -0
  17. ads/aqua/modeldeployment/utils.py +0 -539
  18. ads/common/work_request.py +39 -38
  19. ads/jobs/builders/infrastructure/dsc_job.py +121 -24
  20. ads/jobs/builders/infrastructure/dsc_job_runtime.py +71 -24
  21. ads/jobs/builders/runtimes/base.py +7 -5
  22. ads/jobs/builders/runtimes/pytorch_runtime.py +6 -8
  23. ads/jobs/templates/driver_pytorch.py +486 -172
  24. ads/jobs/templates/driver_utils.py +27 -11
  25. ads/model/service/oci_datascience_model_deployment.py +6 -11
  26. ads/telemetry/client.py +4 -4
  27. {oracle_ads-2.13.10rc0.dist-info → oracle_ads-2.13.12.dist-info}/METADATA +2 -2
  28. {oracle_ads-2.13.10rc0.dist-info → oracle_ads-2.13.12.dist-info}/RECORD +31 -29
  29. {oracle_ads-2.13.10rc0.dist-info → oracle_ads-2.13.12.dist-info}/WHEEL +0 -0
  30. {oracle_ads-2.13.10rc0.dist-info → oracle_ads-2.13.12.dist-info}/entry_points.txt +0 -0
  31. {oracle_ads-2.13.10rc0.dist-info → oracle_ads-2.13.12.dist-info}/licenses/LICENSE.txt +0 -0
@@ -0,0 +1,240 @@
1
+ #!/usr/bin/env python
2
+ # Copyright (c) 2025 Oracle and/or its affiliates.
3
+ # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
4
+
5
+ from typing import List, Optional, Tuple, Union
6
+
7
+ from pydantic import BaseModel, Field, field_validator
8
+ from typing_extensions import Self
9
+
10
+ from ads.aqua import logger
11
+ from ads.aqua.common.entities import AquaMultiModelRef
12
+ from ads.aqua.common.errors import AquaValueError
13
+ from ads.aqua.common.utils import (
14
+ build_params_string,
15
+ find_restricted_params,
16
+ get_combined_params,
17
+ get_container_params_type,
18
+ get_params_dict,
19
+ )
20
+ from ads.aqua.config.utils.serializer import Serializable
21
+ from ads.aqua.modeldeployment.config_loader import (
22
+ AquaDeploymentConfig,
23
+ ConfigurationItem,
24
+ ModelDeploymentConfigSummary,
25
+ )
26
+ from ads.aqua.modeldeployment.entities import CreateModelDeploymentDetails
27
+ from ads.common.object_storage_details import ObjectStorageDetails
28
+ from ads.common.utils import UNKNOWN
29
+
30
+ __all__ = ["ModelGroupConfig", "BaseModelSpec"]
31
+
32
+ from ads.aqua.common.entities import LoraModuleSpec
33
+
34
+
35
+ class BaseModelSpec(BaseModel):
36
+ """
37
+ Defines configuration for a single base model in multi-model deployment.
38
+
39
+ Attributes
40
+ ----------
41
+ model_id: str
42
+ The OCID of the base model.
43
+ model_path : str
44
+ Path to the model in OCI Object Storage.
45
+ params : str
46
+ Additional vLLM launch parameters for this model (e.g. parallelism, max context).
47
+ model_task : str, optional
48
+ Model task type (e.g., text-generation, image-to-text).
49
+ fine_tune_weights : List[List[LoraModuleSpec]], optional
50
+ List of associated LoRA modules for fine-tuned models.
51
+ """
52
+
53
+ model_id: str = Field(..., description="The base model OCID.")
54
+ model_path: str = Field(..., description="Path to the base model.")
55
+ params: str = Field(..., description="Startup parameters passed to vLLM.")
56
+ model_task: Optional[str] = Field(
57
+ ..., description="Task type the model is intended for."
58
+ )
59
+ fine_tune_weights: Optional[List[LoraModuleSpec]] = Field(
60
+ default_factory=list,
61
+ description="Optional list of fine-tuned model variants associated with this base model.",
62
+ )
63
+
64
+ @field_validator("model_path")
65
+ @classmethod
66
+ def clean_model_path(cls, artifact_path_prefix: str) -> str:
67
+ """Validates and cleans the file path for model_path parameter."""
68
+ if ObjectStorageDetails.is_oci_path(artifact_path_prefix):
69
+ os_path = ObjectStorageDetails.from_path(artifact_path_prefix)
70
+ artifact_path_prefix = os_path.filepath.rstrip("/")
71
+ return artifact_path_prefix
72
+
73
+ raise AquaValueError(
74
+ "The base model path is not available in the model artifact."
75
+ )
76
+
77
+ @classmethod
78
+ def dedup_lora_modules(cls, fine_tune_weights: List[LoraModuleSpec]):
79
+ """Removes duplicate LoRA Modules (duplicate model_names in fine_tune_weights)"""
80
+ seen = set()
81
+ unique_modules: List[LoraModuleSpec] = []
82
+
83
+ for module in fine_tune_weights or []:
84
+ name = getattr(module, "model_name", None)
85
+ if not name:
86
+ logger.warning("Fine-tuned model in AquaMultiModelRef is missing model_name.")
87
+ continue
88
+ if name in seen:
89
+ logger.warning(f"Duplicate LoRA Module detected: {name!r} (skipping duplicate).")
90
+ continue
91
+ seen.add(name)
92
+ unique_modules.append(module)
93
+
94
+ return unique_modules
95
+
96
+ @classmethod
97
+ def from_aqua_multi_model_ref(
98
+ cls, model: AquaMultiModelRef, model_params: str
99
+ ) -> Self:
100
+ """Converts AquaMultiModelRef to BaseModelSpec. Fields are validated using @field_validator methods above."""
101
+
102
+ return cls(
103
+ model_id=model.model_id,
104
+ model_path=model.artifact_location,
105
+ params=model_params,
106
+ model_task=model.model_task,
107
+ fine_tune_weights=cls.dedup_lora_modules(model.fine_tune_weights),
108
+ )
109
+
110
+
111
+ class ModelGroupConfig(Serializable):
112
+ """
113
+ Schema representing the metadata passed via MULTI_MODEL_CONFIG for multi-model deployments.
114
+
115
+ Attributes
116
+ ----------
117
+ models : List[BaseModelConfig]
118
+ List of base models (with optional fine-tune weights) to be served.
119
+ """
120
+
121
+ models: List[BaseModelSpec] = Field(
122
+ ..., description="List of models in the multi-model deployment."
123
+ )
124
+
125
+ @staticmethod
126
+ def _extract_model_params(
127
+ model: AquaMultiModelRef,
128
+ container_params: Union[str, List[str]],
129
+ container_type_key: str,
130
+ ) -> Tuple[str, str]:
131
+ """
132
+ Validates if user-provided parameters override pre-set parameters by AQUA.
133
+ Updates model name and TP size parameters to user-provided parameters.
134
+ """
135
+ user_params = build_params_string(model.env_var)
136
+ if user_params:
137
+ restricted_params = find_restricted_params(
138
+ container_params, user_params, container_type_key
139
+ )
140
+ if restricted_params:
141
+ selected_model = model.model_name or model.model_id
142
+ raise AquaValueError(
143
+ f"Parameters {restricted_params} are set by Aqua "
144
+ f"and cannot be overridden or are invalid."
145
+ f"Select other parameters for model {selected_model}."
146
+ )
147
+
148
+ # replaces `--served-model-name`` with user's model name
149
+ container_params_dict = get_params_dict(container_params)
150
+ container_params_dict.update({"--served-model-name": model.model_name})
151
+ # replaces `--tensor-parallel-size` with model gpu count
152
+ container_params_dict.update({"--tensor-parallel-size": model.gpu_count})
153
+ params = build_params_string(container_params_dict)
154
+
155
+ return user_params, params
156
+
157
+ @staticmethod
158
+ def _merge_gpu_count_params(
159
+ model: AquaMultiModelRef,
160
+ model_config_summary: ModelDeploymentConfigSummary,
161
+ create_deployment_details: CreateModelDeploymentDetails,
162
+ container_type_key: str,
163
+ container_params,
164
+ ):
165
+ """Finds the corresponding deployment parameters based on the GPU count
166
+ and combines them with user's parameters. Existing deployment parameters
167
+ will be overriden by user's parameters."""
168
+ user_params, params = ModelGroupConfig._extract_model_params(
169
+ model, container_params, container_type_key
170
+ )
171
+
172
+ model_id = (
173
+ model.fine_tune_weights[0].model_id
174
+ if model.fine_tune_weights
175
+ else model.model_id
176
+ )
177
+
178
+ deployment_config = model_config_summary.deployment_config.get(
179
+ model_id, AquaDeploymentConfig()
180
+ ).configuration.get(
181
+ create_deployment_details.instance_shape, ConfigurationItem()
182
+ )
183
+ params_found = False
184
+ for item in deployment_config.multi_model_deployment:
185
+ if model.gpu_count and item.gpu_count and item.gpu_count == model.gpu_count:
186
+ config_parameters = item.parameters.get(
187
+ get_container_params_type(container_type_key), UNKNOWN
188
+ )
189
+ params = f"{params} {get_combined_params(config_parameters, user_params)}".strip()
190
+ params_found = True
191
+ break
192
+
193
+ if not params_found and deployment_config.parameters:
194
+ config_parameters = deployment_config.parameters.get(
195
+ get_container_params_type(container_type_key), UNKNOWN
196
+ )
197
+ params = f"{params} {get_combined_params(config_parameters, user_params)}".strip()
198
+ params_found = True
199
+
200
+ # if no config parameters found, append user parameters directly.
201
+ if not params_found:
202
+ params = f"{params} {user_params}".strip()
203
+
204
+ return params
205
+
206
+ @classmethod
207
+ def from_create_model_deployment_details(
208
+ cls,
209
+ create_deployment_details: CreateModelDeploymentDetails,
210
+ model_config_summary: ModelDeploymentConfigSummary,
211
+ container_type_key,
212
+ container_params,
213
+ ) -> Self:
214
+ """
215
+ Converts CreateModelDeploymentDetail to ModelGroupConfig.
216
+ CreateModelDeploymentDetail represents user-provided parameters and models within a multi-model group after model artifact is created.
217
+ ModelGroupConfig is the Pydantic representation of MULTI_MODEL_CONFIG environment variable during model deployment.
218
+ """
219
+ models = []
220
+ seen_models = set()
221
+ for model in create_deployment_details.models:
222
+ params = ModelGroupConfig._merge_gpu_count_params(
223
+ model,
224
+ model_config_summary,
225
+ create_deployment_details,
226
+ container_type_key,
227
+ container_params,
228
+ )
229
+
230
+ if model.model_name not in seen_models:
231
+ seen_models.add(model.model_name)
232
+ base_model_spec = BaseModelSpec.from_aqua_multi_model_ref(model, params)
233
+ models.append(base_model_spec)
234
+ else:
235
+ raise AquaValueError(
236
+ f"Duplicate model name ‘{model.model_name}’ detected in multi-model group. "
237
+ "Each base model must have a unique `model_name`. "
238
+ "Please remove or rename the duplicate model and register the model group again."
239
+ )
240
+ return cls(models=models)