Skip to content

Commit ed7a972

Browse files
authored
Merge branch 'main' into feature/model_group
2 parents bcd84b1 + 42f297b commit ed7a972

File tree

14 files changed

+192
-31
lines changed

14 files changed

+192
-31
lines changed

ads/aqua/model/model.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,11 @@ def list(
10301030
aqua_models = []
10311031
inference_containers = self.get_container_config().to_dict().get("inference")
10321032
for model in models:
1033+
# Skip models without required tags early
1034+
freeform_tags = model.freeform_tags or {}
1035+
if Tags.AQUA_TAG.lower() not in {tag.lower() for tag in freeform_tags}:
1036+
continue
1037+
10331038
aqua_models.append(
10341039
AquaModelSummary(
10351040
**self._process_model(
@@ -1040,6 +1045,8 @@ def list(
10401045
project_id=project_id or UNKNOWN,
10411046
)
10421047
)
1048+
1049+
# Adds service models to cache
10431050
if category == SERVICE:
10441051
self._service_models_cache.__setitem__(
10451052
key=AQUA_SERVICE_MODELS, value=aqua_models

ads/opctl/backend/ads_ml_job.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@
1111
import shutil
1212
import tempfile
1313
import time
14+
import re
1415
from distutils import dir_util
1516
from typing import Dict, Tuple, Union
1617

1718
from ads.common.auth import AuthContext, AuthType, create_signer
1819
from ads.common.oci_client import OCIClientFactory
20+
from ads.config import (
21+
CONDA_BUCKET_NAME,
22+
CONDA_BUCKET_NS,
23+
)
1924
from ads.jobs import (
2025
ContainerRuntime,
2126
DataScienceJob,
@@ -65,6 +70,32 @@ def __init__(self, config: Dict) -> None:
6570
self.auth_type = config["execution"].get("auth")
6671
self.profile = config["execution"].get("oci_profile", None)
6772
self.client = OCIClientFactory(**self.oci_auth).data_science
73+
self.object_storage = OCIClientFactory(**self.oci_auth).object_storage
74+
75+
def _get_latest_conda_pack(self,
76+
prefix,
77+
python_version,
78+
base_conda) -> str:
79+
"""
80+
get the latest conda pack.
81+
"""
82+
try:
83+
objects = self.object_storage.list_objects(namespace_name=CONDA_BUCKET_NS,
84+
bucket_name=CONDA_BUCKET_NAME,
85+
prefix=prefix).data.objects
86+
py_str = python_version.replace(".", "")
87+
py_filter = [obj for obj in objects if f"p{py_str}" in obj.name]
88+
89+
def extract_version(obj_name):
90+
match = re.search(rf"{prefix}([\d.]+)/", obj_name)
91+
return tuple(map(int, match.group(1).split("."))) if match else (0,)
92+
93+
latest_obj = max(py_filter, key=lambda obj: extract_version(obj.name))
94+
return latest_obj.name.split("/")[-1]
95+
except Exception as e:
96+
logger.warning(f"Error while fetching latest conda pack: {e}")
97+
return base_conda
98+
6899

69100
def init(
70101
self,
@@ -100,6 +131,16 @@ def init(
100131
or ""
101132
).lower()
102133

134+
# If a tag is present
135+
if ":" in conda_slug:
136+
base_conda = conda_slug.split(":")[0]
137+
conda_slug = self._get_latest_conda_pack(
138+
self.config["prefix"],
139+
self.config["python_version"],
140+
base_conda
141+
)
142+
logger.info(f"Proceeding with the {conda_slug} conda pack.")
143+
103144
# if conda slug contains '/' then the assumption is that it is a custom conda pack
104145
# the conda prefix needs to be added
105146
if "/" in conda_slug:

ads/opctl/operator/common/backend_factory.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,8 @@ def _init_backend_config(
362362
if operator_info.conda_type == PACK_TYPE.SERVICE
363363
else operator_info.conda_prefix,
364364
"freeform_tags": freeform_tags,
365+
"python_version": operator_info.python_version,
366+
"prefix": operator_info.prefix,
365367
}
366368
},
367369
{

ads/opctl/operator/common/operator_loader.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ class OperatorInfo(DataClassSerializable):
152152
description: str = ""
153153
version: str = ""
154154
conda: str = ""
155+
prefix: str = ""
156+
python_version: str = "3.11"
155157
conda_type: str = ""
156158
path: str = ""
157159
keywords: List[str] = None

ads/opctl/operator/lowcode/anomaly/MLoperator

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ type: anomaly
22
version: v1
33
conda_type: service
44
name: Anomaly Detection Operator
5-
conda: anomaly_p310_cpu_x86_64_v1
5+
conda: anomaly_p311_cpu_x86_64_v2:latest
6+
prefix: service_pack/cpu/AI_Anomaly_Detection_Operator/
7+
python_version: "3.11"
68
gpu: no
79
keywords:
810
- Anomaly Detection

ads/opctl/operator/lowcode/common/utils.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,17 +218,12 @@ def _write_file(local_filename, remote_filename, storage_options, **kwargs):
218218

219219

220220
def load_pkl(filepath):
221-
return _safe_write(fn=_load_pkl, filepath=filepath)
222-
223-
224-
def _load_pkl(filepath):
225221
storage_options = {}
226222
if ObjectStorageDetails.is_oci_path(filepath):
227223
storage_options = default_signer()
228224

229225
with fsspec.open(filepath, "rb", **storage_options) as f:
230226
return cloudpickle.load(f)
231-
return None
232227

233228

234229
def write_pkl(obj, filename, output_dir, storage_options):

ads/opctl/operator/lowcode/forecast/MLoperator

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ type: forecast
22
version: v1
33
name: Forecasting Operator
44
conda_type: service
5-
conda: forecast_p310_cpu_x86_64_v4
5+
conda: forecast_p311_cpu_x86_64_v10:latest
6+
prefix: service_pack/cpu/AI_Forecasting_Operator/
7+
python_version: "3.11"
68
gpu: no
79
jobs_default_params:
810
shape_name: VM.Standard.E4.Flex

ads/opctl/operator/lowcode/forecast/model/arima.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,11 @@ def _train_model(self, i, s_id, df, model_kwargs):
8585
X_pred = self.get_horizon(data).drop(target, axis=1)
8686

8787
if self.loaded_models is not None and s_id in self.loaded_models:
88-
model = self.loaded_models[s_id]
88+
model = self.loaded_models[s_id]["model"]
89+
order = model.order
90+
seasonal_order = model.seasonal_order
91+
model = pm.ARIMA(order=order, seasonal_order=seasonal_order)
92+
model.fit(y=y, X=X_in)
8993
else:
9094
# Build and fit model
9195
model = pm.auto_arima(y=y, X=X_in, **model_kwargs)

ads/opctl/operator/lowcode/forecast/model/automlx.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -142,17 +142,20 @@ def _build_model(self) -> pd.DataFrame:
142142
)
143143

144144
if self.loaded_models is not None and s_id in self.loaded_models:
145-
model = self.loaded_models[s_id]
146-
else:
147-
model = Pipeline(
148-
task="forecasting",
149-
**model_kwargs,
150-
)
151-
model.fit(
152-
X=data_i.drop(target, axis=1),
153-
y=data_i[[target]],
154-
time_budget=time_budget,
155-
)
145+
model = self.loaded_models[s_id]["model"]
146+
model_kwargs["model_list"] = [model.selected_model_]
147+
model_kwargs["search_space"]={}
148+
model_kwargs["search_space"][model.selected_model_] = model.selected_model_params_
149+
150+
model = Pipeline(
151+
task="forecasting",
152+
**model_kwargs,
153+
)
154+
model.fit(
155+
X=data_i.drop(target, axis=1),
156+
y=data_i[[target]],
157+
time_budget=time_budget,
158+
)
156159
logger.debug(f"Selected model: {model.selected_model_}")
157160
logger.debug(f"Selected model params: {model.selected_model_params_}")
158161
summary_frame = model.forecast(

ads/opctl/operator/lowcode/forecast/model/prophet.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import matplotlib as mpl
1010
import numpy as np
1111
import optuna
12+
import inspect
1213
import pandas as pd
1314
from joblib import Parallel, delayed
1415

@@ -39,6 +40,22 @@ def _add_unit(num, unit):
3940
return f"{num} {unit}"
4041

4142

43+
def _extract_parameter(model):
44+
"""
45+
extract Prophet initialization parameters
46+
"""
47+
from prophet import Prophet
48+
sig = inspect.signature(Prophet.__init__)
49+
param_names = list(sig.parameters.keys())
50+
params = {}
51+
for name in param_names:
52+
if hasattr(model, name):
53+
value = getattr(model, name)
54+
if isinstance(value, (int, float, str, bool, type(None), dict, list)):
55+
params[name] = value
56+
return params
57+
58+
4259
def _fit_model(data, params, additional_regressors):
4360
from prophet import Prophet
4461

@@ -96,16 +113,17 @@ def _train_model(self, i, series_id, df, model_kwargs):
96113
data = self.preprocess(df, series_id)
97114
data_i = self.drop_horizon(data)
98115
if self.loaded_models is not None and series_id in self.loaded_models:
99-
model = self.loaded_models[series_id]
116+
previous_model = self.loaded_models[series_id]["model"]
117+
model_kwargs.update(_extract_parameter(previous_model))
100118
else:
101119
if self.perform_tuning:
102120
model_kwargs = self.run_tuning(data_i, model_kwargs)
103121

104-
model = _fit_model(
105-
data=data,
106-
params=model_kwargs,
107-
additional_regressors=self.additional_regressors,
108-
)
122+
model = _fit_model(
123+
data=data,
124+
params=model_kwargs,
125+
additional_regressors=self.additional_regressors,
126+
)
109127

110128
# Get future df for prediction
111129
future = data.drop("y", axis=1)

0 commit comments

Comments
 (0)