|
6 | 6 | from typing import Any, Dict, List, Optional
|
7 | 7 |
|
8 | 8 | from oci.data_science.models import Model
|
9 |
| -from pydantic import BaseModel, Field, model_validator |
| 9 | +from pydantic import BaseModel, ConfigDict, Field, model_validator |
10 | 10 |
|
11 | 11 | from ads.aqua import logger
|
12 | 12 | from ads.aqua.config.utils.serializer import Serializable
|
@@ -80,24 +80,29 @@ class GPUShapesIndex(Serializable):
|
80 | 80 |
|
81 | 81 | class ComputeShapeSummary(Serializable):
|
82 | 82 | """
|
83 |
| - Represents the specifications of a compute instance's shape. |
| 83 | + Represents the specifications of a compute instance shape, |
| 84 | + including CPU, memory, and optional GPU characteristics. |
84 | 85 | """
|
85 | 86 |
|
86 | 87 | core_count: Optional[int] = Field(
|
87 |
| - default=None, description="The number of CPU cores available." |
| 88 | + default=None, |
| 89 | + description="Total number of CPU cores available for the compute shape.", |
88 | 90 | )
|
89 | 91 | memory_in_gbs: Optional[int] = Field(
|
90 |
| - default=None, description="The amount of memory (in GB) available." |
| 92 | + default=None, |
| 93 | + description="Amount of memory (in GB) available for the compute shape.", |
91 | 94 | )
|
92 | 95 | name: Optional[str] = Field(
|
93 |
| - default=None, description="The name identifier of the compute shape." |
| 96 | + default=None, |
| 97 | + description="Full name of the compute shape, e.g., 'VM.GPU.A10.2'.", |
94 | 98 | )
|
95 | 99 | shape_series: Optional[str] = Field(
|
96 |
| - default=None, description="The series or category of the compute shape." |
| 100 | + default=None, |
| 101 | + description="Shape family or series, e.g., 'GPU', 'Standard', etc.", |
97 | 102 | )
|
98 | 103 | gpu_specs: Optional[GPUSpecs] = Field(
|
99 | 104 | default=None,
|
100 |
| - description="The GPU specifications associated with the compute shape.", |
| 105 | + description="Optional GPU specifications associated with the shape.", |
101 | 106 | )
|
102 | 107 |
|
103 | 108 | @model_validator(mode="after")
|
@@ -136,27 +141,46 @@ def set_gpu_specs(cls, model: "ComputeShapeSummary") -> "ComputeShapeSummary":
|
136 | 141 | return model
|
137 | 142 |
|
138 | 143 |
|
139 |
| -class LoraModuleSpec(Serializable): |
| 144 | +class LoraModuleSpec(BaseModel): |
140 | 145 | """
|
141 |
| - Lightweight descriptor for LoRA Modules used in fine-tuning models. |
| 146 | + Descriptor for a LoRA (Low-Rank Adaptation) module used in fine-tuning base models. |
| 147 | +
|
| 148 | + This class is used to define a single fine-tuned module that can be loaded during |
| 149 | + multi-model deployment alongside a base model. |
142 | 150 |
|
143 | 151 | Attributes
|
144 | 152 | ----------
|
145 | 153 | 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 |
| 154 | + The OCID of the fine-tuned model registered in the OCI Model Catalog. |
| 155 | + model_name : Optional[str] |
| 156 | + The unique name used to route inference requests to this model variant. |
| 157 | + model_path : Optional[str] |
| 158 | + The relative path within the artifact pointing to the LoRA adapter weights. |
151 | 159 | """
|
152 | 160 |
|
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.") |
| 161 | + model_config = ConfigDict(protected_namespaces=(), extra="allow") |
| 162 | + |
| 163 | + model_id: str = Field( |
| 164 | + ..., |
| 165 | + description="OCID of the fine-tuned model (must be registered in the Model Catalog).", |
| 166 | + ) |
| 167 | + model_name: Optional[str] = Field( |
| 168 | + default=None, |
| 169 | + description="Name assigned to the fine-tuned model for serving (used as inference route).", |
| 170 | + ) |
155 | 171 | model_path: Optional[str] = Field(
|
156 |
| - None, |
157 |
| - description="The model-by-reference path to the LoRA Module within the model artifact.", |
| 172 | + default=None, |
| 173 | + description="Relative path to the LoRA weights inside the model artifact.", |
158 | 174 | )
|
159 | 175 |
|
| 176 | + @model_validator(mode="before") |
| 177 | + @classmethod |
| 178 | + def validate_lora_module(cls, data: dict) -> dict: |
| 179 | + """Validates that required structure exists for a LoRA module.""" |
| 180 | + if "model_id" not in data or not data["model_id"]: |
| 181 | + raise ValueError("Missing required field: 'model_id' for fine-tuned model.") |
| 182 | + return data |
| 183 | + |
160 | 184 |
|
161 | 185 | class AquaMultiModelRef(Serializable):
|
162 | 186 | """
|
@@ -203,6 +227,22 @@ class AquaMultiModelRef(Serializable):
|
203 | 227 | description="For fine tuned models, the artifact path of the modified model weights",
|
204 | 228 | )
|
205 | 229 |
|
| 230 | + def all_model_ids(self) -> List[str]: |
| 231 | + """ |
| 232 | + Returns all associated model OCIDs, including the base model and any fine-tuned models. |
| 233 | +
|
| 234 | + Returns |
| 235 | + ------- |
| 236 | + List[str] |
| 237 | + A list of all model OCIDs associated with this multi-model reference. |
| 238 | + """ |
| 239 | + ids = {self.model_id} |
| 240 | + if self.fine_tune_weights: |
| 241 | + ids.update( |
| 242 | + module.model_id for module in self.fine_tune_weights if module.model_id |
| 243 | + ) |
| 244 | + return list(ids) |
| 245 | + |
206 | 246 | class Config:
|
207 | 247 | extra = "ignore"
|
208 | 248 | protected_namespaces = ()
|
|
0 commit comments