oracle-ads 2.13.2__py3-none-any.whl → 2.13.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.
- ads/aqua/app.py +2 -1
- ads/aqua/evaluation/evaluation.py +11 -10
- ads/aqua/finetuning/finetuning.py +2 -3
- ads/opctl/operator/lowcode/anomaly/model/base_model.py +3 -3
- ads/opctl/operator/lowcode/anomaly/model/randomcutforest.py +1 -1
- ads/opctl/operator/lowcode/anomaly/utils.py +1 -1
- ads/opctl/operator/lowcode/common/transformations.py +5 -1
- ads/opctl/operator/lowcode/common/utils.py +7 -2
- ads/opctl/operator/lowcode/forecast/model/arima.py +15 -10
- ads/opctl/operator/lowcode/forecast/model/automlx.py +31 -9
- ads/opctl/operator/lowcode/forecast/model/autots.py +7 -5
- ads/opctl/operator/lowcode/forecast/model/base_model.py +127 -101
- ads/opctl/operator/lowcode/forecast/model/forecast_datasets.py +14 -6
- ads/opctl/operator/lowcode/forecast/model/ml_forecast.py +2 -2
- ads/opctl/operator/lowcode/forecast/model/neuralprophet.py +46 -32
- ads/opctl/operator/lowcode/forecast/model/prophet.py +82 -29
- ads/opctl/operator/lowcode/forecast/model_evaluator.py +136 -54
- ads/opctl/operator/lowcode/forecast/operator_config.py +29 -3
- ads/opctl/operator/lowcode/forecast/whatifserve/deployment_manager.py +103 -58
- {oracle_ads-2.13.2.dist-info → oracle_ads-2.13.3.dist-info}/METADATA +1 -1
- {oracle_ads-2.13.2.dist-info → oracle_ads-2.13.3.dist-info}/RECORD +24 -24
- {oracle_ads-2.13.2.dist-info → oracle_ads-2.13.3.dist-info}/WHEEL +0 -0
- {oracle_ads-2.13.2.dist-info → oracle_ads-2.13.3.dist-info}/entry_points.txt +0 -0
- {oracle_ads-2.13.2.dist-info → oracle_ads-2.13.3.dist-info}/licenses/LICENSE.txt +0 -0
ads/aqua/app.py
CHANGED
@@ -225,6 +225,7 @@ class AquaApp:
|
|
225
225
|
model_taxonomy_metadata: Union[ModelTaxonomyMetadata, Dict],
|
226
226
|
compartment_id: str,
|
227
227
|
project_id: str,
|
228
|
+
defined_tags: Dict = None,
|
228
229
|
**kwargs,
|
229
230
|
) -> DataScienceModel:
|
230
231
|
model = (
|
@@ -237,7 +238,7 @@ class AquaApp:
|
|
237
238
|
.with_custom_metadata_list(model_custom_metadata)
|
238
239
|
.with_defined_metadata_list(model_taxonomy_metadata)
|
239
240
|
.with_provenance_metadata(ModelProvenanceMetadata(training_id=UNKNOWN))
|
240
|
-
#
|
241
|
+
.with_defined_tags(**(defined_tags or {})) # Create defined tags when a model is created.
|
241
242
|
.create(
|
242
243
|
**kwargs,
|
243
244
|
)
|
@@ -260,6 +260,10 @@ class AquaEvaluationApp(AquaApp):
|
|
260
260
|
**create_aqua_evaluation_details.model_parameters,
|
261
261
|
)
|
262
262
|
|
263
|
+
evaluation_model_defined_tags = (
|
264
|
+
create_aqua_evaluation_details.defined_tags or {}
|
265
|
+
)
|
266
|
+
|
263
267
|
target_compartment = (
|
264
268
|
create_aqua_evaluation_details.compartment_id or COMPARTMENT_OCID
|
265
269
|
)
|
@@ -311,9 +315,7 @@ class AquaEvaluationApp(AquaApp):
|
|
311
315
|
create_aqua_evaluation_details.experiment_description
|
312
316
|
)
|
313
317
|
.with_freeform_tags(**evaluation_mvs_freeform_tags)
|
314
|
-
.with_defined_tags(
|
315
|
-
**(create_aqua_evaluation_details.defined_tags or {})
|
316
|
-
)
|
318
|
+
.with_defined_tags(**evaluation_model_defined_tags)
|
317
319
|
# TODO: decide what parameters will be needed
|
318
320
|
.create(**kwargs)
|
319
321
|
)
|
@@ -358,6 +360,7 @@ class AquaEvaluationApp(AquaApp):
|
|
358
360
|
.with_custom_metadata_list(evaluation_model_custom_metadata)
|
359
361
|
.with_defined_metadata_list(evaluation_model_taxonomy_metadata)
|
360
362
|
.with_provenance_metadata(ModelProvenanceMetadata(training_id=UNKNOWN))
|
363
|
+
.with_defined_tags(**evaluation_model_defined_tags)
|
361
364
|
# TODO uncomment this once the evaluation container will get the updated version of the ADS
|
362
365
|
# .with_input_schema(create_aqua_evaluation_details.to_dict())
|
363
366
|
# TODO: decide what parameters will be needed
|
@@ -390,7 +393,7 @@ class AquaEvaluationApp(AquaApp):
|
|
390
393
|
.with_shape_name(create_aqua_evaluation_details.shape_name)
|
391
394
|
.with_block_storage_size(create_aqua_evaluation_details.block_storage_size)
|
392
395
|
.with_freeform_tag(**evaluation_job_freeform_tags)
|
393
|
-
.with_defined_tag(**
|
396
|
+
.with_defined_tag(**evaluation_model_defined_tags)
|
394
397
|
)
|
395
398
|
if (
|
396
399
|
create_aqua_evaluation_details.memory_in_gbs
|
@@ -429,7 +432,9 @@ class AquaEvaluationApp(AquaApp):
|
|
429
432
|
metrics=create_aqua_evaluation_details.metrics,
|
430
433
|
inference_configuration=eval_inference_configuration or {},
|
431
434
|
)
|
432
|
-
).create(
|
435
|
+
).create(
|
436
|
+
**kwargs
|
437
|
+
) ## TODO: decide what parameters will be needed
|
433
438
|
logger.debug(
|
434
439
|
f"Successfully created evaluation job {evaluation_job.id} for {create_aqua_evaluation_details.evaluation_source_id}."
|
435
440
|
)
|
@@ -437,7 +442,7 @@ class AquaEvaluationApp(AquaApp):
|
|
437
442
|
evaluation_job_run = evaluation_job.run(
|
438
443
|
name=evaluation_model.display_name,
|
439
444
|
freeform_tags=evaluation_job_freeform_tags,
|
440
|
-
defined_tags=
|
445
|
+
defined_tags=evaluation_model_defined_tags,
|
441
446
|
wait=False,
|
442
447
|
)
|
443
448
|
logger.debug(
|
@@ -461,16 +466,12 @@ class AquaEvaluationApp(AquaApp):
|
|
461
466
|
Tags.AQUA_EVALUATION: Tags.AQUA_EVALUATION,
|
462
467
|
**(create_aqua_evaluation_details.freeform_tags or {}),
|
463
468
|
}
|
464
|
-
evaluation_model_defined_tags = (
|
465
|
-
create_aqua_evaluation_details.defined_tags or {}
|
466
|
-
)
|
467
469
|
|
468
470
|
self.ds_client.update_model(
|
469
471
|
model_id=evaluation_model.id,
|
470
472
|
update_model_details=UpdateModelDetails(
|
471
473
|
custom_metadata_list=updated_custom_metadata_list,
|
472
474
|
freeform_tags=evaluation_model_freeform_tags,
|
473
|
-
defined_tags=evaluation_model_defined_tags,
|
474
475
|
),
|
475
476
|
)
|
476
477
|
|
@@ -263,6 +263,7 @@ class AquaFineTuningApp(AquaApp):
|
|
263
263
|
compartment_id=target_compartment,
|
264
264
|
project_id=target_project,
|
265
265
|
model_by_reference=True,
|
266
|
+
defined_tags=create_fine_tuning_details.defined_tags
|
266
267
|
)
|
267
268
|
|
268
269
|
ft_job_freeform_tags = {
|
@@ -382,14 +383,12 @@ class AquaFineTuningApp(AquaApp):
|
|
382
383
|
Tags.AQUA_FINE_TUNED_MODEL_TAG: f"{source.id}#{source.display_name}",
|
383
384
|
**(create_fine_tuning_details.freeform_tags or {}),
|
384
385
|
}
|
385
|
-
model_defined_tags = create_fine_tuning_details.defined_tags or {}
|
386
386
|
|
387
387
|
self.update_model(
|
388
388
|
model_id=ft_model.id,
|
389
389
|
update_model_details=UpdateModelDetails(
|
390
390
|
custom_metadata_list=updated_custom_metadata_list,
|
391
391
|
freeform_tags=model_freeform_tags,
|
392
|
-
defined_tags=model_defined_tags,
|
393
392
|
),
|
394
393
|
)
|
395
394
|
logger.debug(
|
@@ -490,7 +489,7 @@ class AquaFineTuningApp(AquaApp):
|
|
490
489
|
"finetuning_source": source.id,
|
491
490
|
"finetuning_experiment_id": experiment_model_version_set_id,
|
492
491
|
**model_freeform_tags,
|
493
|
-
**
|
492
|
+
**(create_fine_tuning_details.defined_tags or {}),
|
494
493
|
},
|
495
494
|
parameters=ft_parameters,
|
496
495
|
)
|
@@ -71,7 +71,7 @@ class AnomalyOperatorBaseModel(ABC):
|
|
71
71
|
try:
|
72
72
|
anomaly_output = self._build_model()
|
73
73
|
except Exception as e:
|
74
|
-
logger.
|
74
|
+
logger.warning(f"Found exception: {e}")
|
75
75
|
if self.spec.datetime_column:
|
76
76
|
anomaly_output = self._fallback_build_model()
|
77
77
|
raise e
|
@@ -347,7 +347,7 @@ class AnomalyOperatorBaseModel(ABC):
|
|
347
347
|
storage_options=storage_options,
|
348
348
|
)
|
349
349
|
|
350
|
-
logger.
|
350
|
+
logger.warning(
|
351
351
|
f"The report has been successfully "
|
352
352
|
f"generated and placed to the: {unique_output_dir}."
|
353
353
|
)
|
@@ -356,7 +356,7 @@ class AnomalyOperatorBaseModel(ABC):
|
|
356
356
|
"""
|
357
357
|
Fallback method for the sub model _build_model method.
|
358
358
|
"""
|
359
|
-
logger.
|
359
|
+
logger.warning(
|
360
360
|
f"The build_model method has failed for the model: {self.spec.model}. "
|
361
361
|
"A fallback model will be built."
|
362
362
|
)
|
@@ -95,7 +95,7 @@ class RandomCutForestOperatorModel(AnomalyOperatorBaseModel):
|
|
95
95
|
|
96
96
|
anomaly_output.add_output(target, anomaly, score)
|
97
97
|
except Exception as e:
|
98
|
-
logger.
|
98
|
+
logger.warning(f"Encountered Error: {e}. Skipping series {target}.")
|
99
99
|
|
100
100
|
return anomaly_output
|
101
101
|
|
@@ -44,7 +44,7 @@ def _build_metrics_df(y_true, y_pred, column_name):
|
|
44
44
|
# Throws exception if y_true has only one class
|
45
45
|
metrics[SupportedMetrics.ROC_AUC] = roc_auc_score(y_true, y_pred)
|
46
46
|
except Exception as e:
|
47
|
-
logger.
|
47
|
+
logger.warning(f"An exception occurred: {e}")
|
48
48
|
metrics[SupportedMetrics.ROC_AUC] = None
|
49
49
|
precision, recall, thresholds = precision_recall_curve(y_true, y_pred)
|
50
50
|
metrics[SupportedMetrics.PRC_AUC] = auc(recall, precision)
|
@@ -98,7 +98,11 @@ class Transformations(ABC):
|
|
98
98
|
return clean_df
|
99
99
|
|
100
100
|
def _remove_trailing_whitespace(self, df):
|
101
|
-
return df.apply(
|
101
|
+
return df.apply(
|
102
|
+
lambda x: x.str.strip()
|
103
|
+
if hasattr(x, "dtype") and x.dtype == "object"
|
104
|
+
else x
|
105
|
+
)
|
102
106
|
|
103
107
|
def _clean_column_names(self, df):
|
104
108
|
"""
|
@@ -3,6 +3,7 @@
|
|
3
3
|
# Copyright (c) 2024, 2025 Oracle and/or its affiliates.
|
4
4
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
5
5
|
|
6
|
+
import json
|
6
7
|
import logging
|
7
8
|
import os
|
8
9
|
import shutil
|
@@ -12,7 +13,6 @@ from typing import List, Union
|
|
12
13
|
|
13
14
|
import fsspec
|
14
15
|
import oracledb
|
15
|
-
import json
|
16
16
|
import pandas as pd
|
17
17
|
|
18
18
|
from ads.common.object_storage_details import ObjectStorageDetails
|
@@ -142,6 +142,11 @@ def write_data(data, filename, format, storage_options=None, index=False, **kwar
|
|
142
142
|
)
|
143
143
|
|
144
144
|
|
145
|
+
def write_json(json_dict, filename, storage_options=None):
|
146
|
+
with fsspec.open(filename, mode="w", **storage_options) as f:
|
147
|
+
f.write(json.dumps(json_dict))
|
148
|
+
|
149
|
+
|
145
150
|
def write_simple_json(data, path):
|
146
151
|
if ObjectStorageDetails.is_oci_path(path):
|
147
152
|
storage_options = default_signer()
|
@@ -265,7 +270,7 @@ def find_output_dirname(output_dir: OutputDirectory):
|
|
265
270
|
while os.path.exists(unique_output_dir):
|
266
271
|
unique_output_dir = f"{output_dir}_{counter}"
|
267
272
|
counter += 1
|
268
|
-
logger.
|
273
|
+
logger.warning(
|
269
274
|
f"Since the output directory was not specified, the output will be saved to {unique_output_dir} directory."
|
270
275
|
)
|
271
276
|
return unique_output_dir
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
2
|
|
3
|
-
# Copyright (c) 2023,
|
3
|
+
# Copyright (c) 2023, 2025 Oracle and/or its affiliates.
|
4
4
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
5
5
|
|
6
6
|
import logging
|
@@ -132,13 +132,14 @@ class ArimaOperatorModel(ForecastOperatorBaseModel):
|
|
132
132
|
|
133
133
|
logger.debug("===========Done===========")
|
134
134
|
except Exception as e:
|
135
|
-
|
135
|
+
new_error = {
|
136
136
|
"model_name": self.spec.model,
|
137
137
|
"error": str(e),
|
138
138
|
"error_trace": traceback.format_exc(),
|
139
139
|
}
|
140
|
-
|
141
|
-
logger.
|
140
|
+
self.errors_dict[s_id] = new_error
|
141
|
+
logger.warning(f"Encountered Error: {e}. Skipping.")
|
142
|
+
logger.warning(traceback.format_exc())
|
142
143
|
|
143
144
|
def _build_model(self) -> pd.DataFrame:
|
144
145
|
full_data_dict = self.datasets.get_data_by_series()
|
@@ -166,7 +167,7 @@ class ArimaOperatorModel(ForecastOperatorBaseModel):
|
|
166
167
|
sec5_text = rc.Heading("ARIMA Model Parameters", level=2)
|
167
168
|
blocks = [
|
168
169
|
rc.Html(
|
169
|
-
m[
|
170
|
+
m["model"].summary().as_html(),
|
170
171
|
label=s_id if self.target_cat_col else None,
|
171
172
|
)
|
172
173
|
for i, (s_id, m) in enumerate(self.models.items())
|
@@ -201,11 +202,15 @@ class ArimaOperatorModel(ForecastOperatorBaseModel):
|
|
201
202
|
self.formatted_local_explanation = aggregate_local_explanations
|
202
203
|
|
203
204
|
if not self.target_cat_col:
|
204
|
-
self.formatted_global_explanation =
|
205
|
-
|
206
|
-
|
205
|
+
self.formatted_global_explanation = (
|
206
|
+
self.formatted_global_explanation.rename(
|
207
|
+
{"Series 1": self.original_target_column},
|
208
|
+
axis=1,
|
209
|
+
)
|
210
|
+
)
|
211
|
+
self.formatted_local_explanation.drop(
|
212
|
+
"Series", axis=1, inplace=True
|
207
213
|
)
|
208
|
-
self.formatted_local_explanation.drop("Series", axis=1, inplace=True)
|
209
214
|
|
210
215
|
# Create a markdown section for the global explainability
|
211
216
|
global_explanation_section = rc.Block(
|
@@ -235,7 +240,7 @@ class ArimaOperatorModel(ForecastOperatorBaseModel):
|
|
235
240
|
local_explanation_section,
|
236
241
|
]
|
237
242
|
except Exception as e:
|
238
|
-
logger.
|
243
|
+
logger.warning(f"Failed to generate Explanations with error: {e}.")
|
239
244
|
logger.debug(f"Full Traceback: {traceback.format_exc()}")
|
240
245
|
|
241
246
|
model_description = rc.Text(
|
@@ -184,13 +184,18 @@ class AutoMLXOperatorModel(ForecastOperatorBaseModel):
|
|
184
184
|
"selected_model_params": model.selected_model_params_,
|
185
185
|
}
|
186
186
|
except Exception as e:
|
187
|
-
|
187
|
+
new_error = {
|
188
188
|
"model_name": self.spec.model,
|
189
189
|
"error": str(e),
|
190
190
|
"error_trace": traceback.format_exc(),
|
191
191
|
}
|
192
|
-
|
193
|
-
|
192
|
+
if s_id in self.errors_dict:
|
193
|
+
self.errors_dict[s_id]["model_fitting"] = new_error
|
194
|
+
else:
|
195
|
+
self.errors_dict[s_id] = {"model_fitting": new_error}
|
196
|
+
logger.warning(f"Encountered Error: {e}. Skipping.")
|
197
|
+
logger.warning(f"self.errors_dict[s_id]: {self.errors_dict[s_id]}")
|
198
|
+
logger.warning(traceback.format_exc())
|
194
199
|
|
195
200
|
logger.debug("===========Forecast Generated===========")
|
196
201
|
|
@@ -257,7 +262,9 @@ class AutoMLXOperatorModel(ForecastOperatorBaseModel):
|
|
257
262
|
)
|
258
263
|
|
259
264
|
self.formatted_global_explanation.rename(
|
260
|
-
columns={
|
265
|
+
columns={
|
266
|
+
self.spec.datetime_column.name: ForecastOutputColumns.DATE
|
267
|
+
},
|
261
268
|
inplace=True,
|
262
269
|
)
|
263
270
|
|
@@ -312,7 +319,7 @@ class AutoMLXOperatorModel(ForecastOperatorBaseModel):
|
|
312
319
|
local_explanation_section,
|
313
320
|
]
|
314
321
|
except Exception as e:
|
315
|
-
logger.
|
322
|
+
logger.warning(f"Failed to generate Explanations with error: {e}.")
|
316
323
|
logger.debug(f"Full Traceback: {traceback.format_exc()}")
|
317
324
|
|
318
325
|
model_description = rc.Text(
|
@@ -462,14 +469,27 @@ class AutoMLXOperatorModel(ForecastOperatorBaseModel):
|
|
462
469
|
index="row", columns="Feature", values="Attribution"
|
463
470
|
)
|
464
471
|
explanations_df = explanations_df.reset_index(drop=True)
|
465
|
-
|
472
|
+
explanations_df[ForecastOutputColumns.DATE] = (
|
473
|
+
self.datasets.get_horizon_at_series(
|
474
|
+
s_id=s_id
|
475
|
+
)[self.spec.datetime_column.name].reset_index(drop=True)
|
476
|
+
)
|
466
477
|
# Store the explanations in the local_explanation dictionary
|
467
478
|
self.local_explanation[s_id] = explanations_df
|
468
479
|
|
469
480
|
self.global_explanation[s_id] = dict(
|
470
481
|
zip(
|
471
|
-
self.local_explanation[s_id]
|
472
|
-
|
482
|
+
self.local_explanation[s_id]
|
483
|
+
.drop(ForecastOutputColumns.DATE, axis=1)
|
484
|
+
.columns,
|
485
|
+
np.nanmean(
|
486
|
+
np.abs(
|
487
|
+
self.local_explanation[s_id].drop(
|
488
|
+
ForecastOutputColumns.DATE, axis=1
|
489
|
+
)
|
490
|
+
),
|
491
|
+
axis=0,
|
492
|
+
),
|
473
493
|
)
|
474
494
|
)
|
475
495
|
else:
|
@@ -478,7 +498,9 @@ class AutoMLXOperatorModel(ForecastOperatorBaseModel):
|
|
478
498
|
except Exception as e:
|
479
499
|
if s_id in self.errors_dict:
|
480
500
|
self.errors_dict[s_id]["explainer_error"] = str(e)
|
481
|
-
self.errors_dict[s_id]["explainer_error_trace"] =
|
501
|
+
self.errors_dict[s_id]["explainer_error_trace"] = (
|
502
|
+
traceback.format_exc()
|
503
|
+
)
|
482
504
|
else:
|
483
505
|
self.errors_dict[s_id] = {
|
484
506
|
"model_name": self.spec.model,
|
@@ -211,8 +211,8 @@ class AutoTSOperatorModel(ForecastOperatorBaseModel):
|
|
211
211
|
"error": str(e),
|
212
212
|
"error_trace": traceback.format_exc(),
|
213
213
|
}
|
214
|
-
logger.
|
215
|
-
logger.
|
214
|
+
logger.warning(f"Encountered Error: {e}. Skipping.")
|
215
|
+
logger.warning(traceback.format_exc())
|
216
216
|
|
217
217
|
logger.debug("===========Done===========")
|
218
218
|
|
@@ -242,7 +242,7 @@ class AutoTSOperatorModel(ForecastOperatorBaseModel):
|
|
242
242
|
self.models.df_wide_numeric, series=s_id
|
243
243
|
),
|
244
244
|
self.datasets.list_series_ids(),
|
245
|
-
target_category_column=self.target_cat_col
|
245
|
+
target_category_column=self.target_cat_col,
|
246
246
|
)
|
247
247
|
section_1 = rc.Block(
|
248
248
|
rc.Heading("Forecast Overview", level=2),
|
@@ -260,7 +260,9 @@ class AutoTSOperatorModel(ForecastOperatorBaseModel):
|
|
260
260
|
)
|
261
261
|
|
262
262
|
except KeyError:
|
263
|
-
logger.
|
263
|
+
logger.warning(
|
264
|
+
"Issue generating Model Parameters Table Section. Skipping"
|
265
|
+
)
|
264
266
|
sec2 = rc.Text("Error generating model parameters.")
|
265
267
|
|
266
268
|
section_2 = rc.Block(sec2_text, sec2)
|
@@ -268,7 +270,7 @@ class AutoTSOperatorModel(ForecastOperatorBaseModel):
|
|
268
270
|
all_sections = [section_1, section_2]
|
269
271
|
|
270
272
|
if self.spec.generate_explanations:
|
271
|
-
logger.
|
273
|
+
logger.warning("Explanations not yet supported for the AutoTS Module")
|
272
274
|
|
273
275
|
# Model Description
|
274
276
|
model_description = rc.Text(
|