oracle-ads 2.11.9__py3-none-any.whl → 2.11.11__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/__init__.py +1 -1
- ads/aqua/{base.py → app.py} +27 -7
- ads/aqua/cli.py +59 -17
- ads/aqua/common/__init__.py +5 -0
- ads/aqua/{decorator.py → common/decorator.py} +14 -8
- ads/aqua/common/enums.py +69 -0
- ads/aqua/{exception.py → common/errors.py} +28 -0
- ads/aqua/{utils.py → common/utils.py} +193 -95
- ads/aqua/config/config.py +18 -0
- ads/aqua/constants.py +51 -33
- ads/aqua/data.py +15 -26
- ads/aqua/evaluation/__init__.py +8 -0
- ads/aqua/evaluation/constants.py +53 -0
- ads/aqua/evaluation/entities.py +170 -0
- ads/aqua/evaluation/errors.py +71 -0
- ads/aqua/{evaluation.py → evaluation/evaluation.py} +122 -370
- ads/aqua/extension/__init__.py +2 -0
- ads/aqua/extension/aqua_ws_msg_handler.py +97 -0
- ads/aqua/extension/base_handler.py +0 -7
- ads/aqua/extension/common_handler.py +12 -6
- ads/aqua/extension/deployment_handler.py +70 -4
- ads/aqua/extension/errors.py +10 -0
- ads/aqua/extension/evaluation_handler.py +5 -3
- ads/aqua/extension/evaluation_ws_msg_handler.py +43 -0
- ads/aqua/extension/finetune_handler.py +41 -3
- ads/aqua/extension/model_handler.py +56 -4
- ads/aqua/extension/models/__init__.py +0 -0
- ads/aqua/extension/models/ws_models.py +69 -0
- ads/aqua/extension/ui_handler.py +65 -4
- ads/aqua/extension/ui_websocket_handler.py +124 -0
- ads/aqua/extension/utils.py +1 -1
- ads/aqua/finetuning/__init__.py +7 -0
- ads/aqua/finetuning/constants.py +17 -0
- ads/aqua/finetuning/entities.py +102 -0
- ads/aqua/{finetune.py → finetuning/finetuning.py} +170 -141
- ads/aqua/model/__init__.py +8 -0
- ads/aqua/model/constants.py +46 -0
- ads/aqua/model/entities.py +266 -0
- ads/aqua/model/enums.py +26 -0
- ads/aqua/{model.py → model/model.py} +405 -309
- ads/aqua/modeldeployment/__init__.py +8 -0
- ads/aqua/modeldeployment/constants.py +26 -0
- ads/aqua/{deployment.py → modeldeployment/deployment.py} +288 -227
- ads/aqua/modeldeployment/entities.py +142 -0
- ads/aqua/modeldeployment/inference.py +75 -0
- ads/aqua/ui.py +88 -8
- ads/cli.py +55 -7
- ads/common/decorator/threaded.py +97 -0
- ads/common/serializer.py +2 -2
- ads/config.py +5 -1
- ads/jobs/builders/infrastructure/dsc_job.py +49 -6
- ads/model/datascience_model.py +1 -1
- ads/model/deployment/model_deployment.py +11 -0
- ads/model/model_metadata.py +17 -6
- ads/opctl/operator/lowcode/anomaly/README.md +0 -2
- ads/opctl/operator/lowcode/anomaly/__main__.py +3 -3
- ads/opctl/operator/lowcode/anomaly/environment.yaml +0 -2
- ads/opctl/operator/lowcode/anomaly/model/automlx.py +2 -2
- ads/opctl/operator/lowcode/anomaly/model/autots.py +1 -1
- ads/opctl/operator/lowcode/anomaly/model/base_model.py +13 -17
- ads/opctl/operator/lowcode/anomaly/operator_config.py +2 -0
- ads/opctl/operator/lowcode/anomaly/schema.yaml +1 -2
- ads/opctl/operator/lowcode/anomaly/utils.py +3 -2
- ads/opctl/operator/lowcode/common/transformations.py +2 -1
- ads/opctl/operator/lowcode/common/utils.py +1 -1
- ads/opctl/operator/lowcode/forecast/README.md +1 -3
- ads/opctl/operator/lowcode/forecast/__main__.py +3 -18
- ads/opctl/operator/lowcode/forecast/const.py +2 -0
- ads/opctl/operator/lowcode/forecast/environment.yaml +1 -2
- ads/opctl/operator/lowcode/forecast/model/arima.py +1 -0
- ads/opctl/operator/lowcode/forecast/model/automlx.py +7 -4
- ads/opctl/operator/lowcode/forecast/model/autots.py +1 -0
- ads/opctl/operator/lowcode/forecast/model/base_model.py +38 -22
- ads/opctl/operator/lowcode/forecast/model/factory.py +33 -4
- ads/opctl/operator/lowcode/forecast/model/forecast_datasets.py +15 -1
- ads/opctl/operator/lowcode/forecast/model/ml_forecast.py +234 -0
- ads/opctl/operator/lowcode/forecast/model/neuralprophet.py +9 -1
- ads/opctl/operator/lowcode/forecast/model/prophet.py +1 -0
- ads/opctl/operator/lowcode/forecast/model_evaluator.py +147 -0
- ads/opctl/operator/lowcode/forecast/operator_config.py +2 -1
- ads/opctl/operator/lowcode/forecast/schema.yaml +7 -2
- ads/opctl/operator/lowcode/forecast/utils.py +18 -44
- {oracle_ads-2.11.9.dist-info → oracle_ads-2.11.11.dist-info}/METADATA +9 -12
- {oracle_ads-2.11.9.dist-info → oracle_ads-2.11.11.dist-info}/RECORD +87 -61
- ads/aqua/job.py +0 -29
- {oracle_ads-2.11.9.dist-info → oracle_ads-2.11.11.dist-info}/LICENSE.txt +0 -0
- {oracle_ads-2.11.9.dist-info → oracle_ads-2.11.11.dist-info}/WHEEL +0 -0
- {oracle_ads-2.11.9.dist-info → oracle_ads-2.11.11.dist-info}/entry_points.txt +0 -0
@@ -370,6 +370,17 @@ class ModelDeployment(Builder):
|
|
370
370
|
"""
|
371
371
|
return self.get_spec(self.CONST_ID, None)
|
372
372
|
|
373
|
+
@property
|
374
|
+
def id(self) -> str:
|
375
|
+
"""The model deployment ocid.
|
376
|
+
|
377
|
+
Returns
|
378
|
+
-------
|
379
|
+
str
|
380
|
+
The model deployment ocid.
|
381
|
+
"""
|
382
|
+
return self.get_spec(self.CONST_ID, None)
|
383
|
+
|
373
384
|
@property
|
374
385
|
def created_by(self) -> str:
|
375
386
|
"""The user that creates the model deployment.
|
ads/model/model_metadata.py
CHANGED
@@ -8,10 +8,10 @@ import json
|
|
8
8
|
import logging
|
9
9
|
import os
|
10
10
|
import sys
|
11
|
-
from abc import ABC,
|
11
|
+
from abc import ABC, abstractmethod
|
12
12
|
from dataclasses import dataclass, field, fields
|
13
13
|
from pathlib import Path
|
14
|
-
from typing import Dict, List, Tuple
|
14
|
+
from typing import Dict, List, Tuple, Union, Optional, Any
|
15
15
|
|
16
16
|
import ads.dataset.factory as factory
|
17
17
|
import fsspec
|
@@ -41,6 +41,8 @@ METADATA_DESCRIPTION_LENGTH_LIMIT = 255
|
|
41
41
|
_METADATA_EMPTY_VALUE = "NA"
|
42
42
|
CURRENT_WORKING_DIR = "."
|
43
43
|
|
44
|
+
_sentinel = object()
|
45
|
+
|
44
46
|
|
45
47
|
class MetadataSizeTooLarge(ValueError):
|
46
48
|
"""Maximum allowed size for model metadata has been exceeded.
|
@@ -727,13 +729,18 @@ class ModelMetadata(ABC):
|
|
727
729
|
"""Initializes Model Metadata."""
|
728
730
|
self._items = set()
|
729
731
|
|
730
|
-
def get(
|
732
|
+
def get(
|
733
|
+
self, key: str, value: Optional[Any] = _sentinel
|
734
|
+
) -> Union[ModelMetadataItem, Any]:
|
731
735
|
"""Returns the model metadata item by provided key.
|
732
736
|
|
733
737
|
Parameters
|
734
738
|
----------
|
735
739
|
key: str
|
736
740
|
The key of model metadata item.
|
741
|
+
value: (str, optional)
|
742
|
+
A value to return if the specified key does not exist. Defaults to `object()`.
|
743
|
+
If default value not specified, the ValueError will be returned.
|
737
744
|
|
738
745
|
Returns
|
739
746
|
-------
|
@@ -750,7 +757,11 @@ class ModelMetadata(ABC):
|
|
750
757
|
for item in self._items:
|
751
758
|
if item.key.lower() == key.lower():
|
752
759
|
return item
|
753
|
-
|
760
|
+
|
761
|
+
if value is _sentinel:
|
762
|
+
raise ValueError(f"The metadata with {key} not found.")
|
763
|
+
|
764
|
+
return value
|
754
765
|
|
755
766
|
def reset(self) -> None:
|
756
767
|
"""Resets all model metadata items to empty values.
|
@@ -952,7 +963,7 @@ class ModelMetadata(ABC):
|
|
952
963
|
def __len__(self):
|
953
964
|
return len(self._items)
|
954
965
|
|
955
|
-
@
|
966
|
+
@abstractmethod
|
956
967
|
def _from_oci_metadata(cls, metadata_list):
|
957
968
|
pass
|
958
969
|
|
@@ -967,7 +978,7 @@ class ModelMetadata(ABC):
|
|
967
978
|
"""
|
968
979
|
pass
|
969
980
|
|
970
|
-
@
|
981
|
+
@abstractmethod
|
971
982
|
def from_dict(cls, data: Dict) -> "ModelMetadata":
|
972
983
|
"""Constructs an instance of `ModelMetadata` from a dictionary.
|
973
984
|
|
@@ -37,8 +37,6 @@ To run anomaly detection locally, create and activate a new conda environment (`
|
|
37
37
|
```yaml
|
38
38
|
- report-creator
|
39
39
|
- cerberus
|
40
|
-
- oracle-automlx==23.4.1
|
41
|
-
- oracle-automlx[classic]==23.4.1
|
42
40
|
- "git+https://github.com/oracle/accelerated-data-science.git@feature/anomaly#egg=oracle-ads"
|
43
41
|
```
|
44
42
|
|
@@ -40,11 +40,11 @@ def operate(operator_config: AnomalyOperatorConfig) -> None:
|
|
40
40
|
AnomalyOperatorModelFactory.get_model(
|
41
41
|
operator_config, datasets
|
42
42
|
).generate_report()
|
43
|
-
except Exception as
|
43
|
+
except Exception as ee:
|
44
44
|
logger.debug(
|
45
|
-
f"Failed to backup forecast with error {
|
45
|
+
f"Failed to backup forecast with error {ee.args}. Raising original error."
|
46
46
|
)
|
47
|
-
raise
|
47
|
+
raise ee
|
48
48
|
else:
|
49
49
|
raise e
|
50
50
|
|
@@ -19,8 +19,8 @@ class AutoMLXOperatorModel(AnomalyOperatorBaseModel):
|
|
19
19
|
@runtime_dependency(
|
20
20
|
module="automlx",
|
21
21
|
err_msg=(
|
22
|
-
"Please run `pip3 install oracle-automlx
|
23
|
-
"`pip3 install oracle-automlx[classic]
|
22
|
+
"Please run `pip3 install oracle-automlx>=23.4.1` and "
|
23
|
+
"`pip3 install oracle-automlx[classic]>=23.4.1` "
|
24
24
|
"to install the required dependencies for automlx."
|
25
25
|
),
|
26
26
|
)
|
@@ -91,7 +91,7 @@ class AutoTSOperatorModel(AnomalyOperatorBaseModel):
|
|
91
91
|
),
|
92
92
|
]
|
93
93
|
model_description = rc.Text(
|
94
|
-
"The
|
94
|
+
"The autots model automatically pre-processes, selects and engineers "
|
95
95
|
"high-quality features in your dataset, which then given to an automatically "
|
96
96
|
"chosen and optimized machine learning model.."
|
97
97
|
)
|
@@ -4,33 +4,29 @@
|
|
4
4
|
# Copyright (c) 2023, 2024 Oracle and/or its affiliates.
|
5
5
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
6
6
|
|
7
|
+
import fsspec
|
8
|
+
import numpy as np
|
7
9
|
import os
|
10
|
+
import pandas as pd
|
8
11
|
import tempfile
|
9
12
|
import time
|
10
13
|
from abc import ABC, abstractmethod
|
11
|
-
from typing import Tuple
|
12
|
-
|
13
|
-
import fsspec
|
14
|
-
import pandas as pd
|
15
|
-
import numpy as np
|
16
14
|
from sklearn import linear_model
|
15
|
+
from typing import Tuple
|
17
16
|
|
17
|
+
from ads.common.object_storage_details import ObjectStorageDetails
|
18
18
|
from ads.opctl import logger
|
19
|
-
|
20
|
-
from ..operator_config import AnomalyOperatorConfig, AnomalyOperatorSpec
|
21
|
-
from .anomaly_dataset import AnomalyDatasets, AnomalyOutput, TestData
|
22
19
|
from ads.opctl.operator.lowcode.anomaly.const import OutputColumns, SupportedMetrics
|
23
|
-
from
|
20
|
+
from ads.opctl.operator.lowcode.anomaly.utils import _build_metrics_df, default_signer
|
24
21
|
from ads.opctl.operator.lowcode.common.utils import (
|
25
22
|
human_time_friendly,
|
26
23
|
enable_print,
|
27
24
|
disable_print,
|
28
25
|
write_data,
|
29
|
-
merge_category_columns,
|
30
|
-
find_output_dirname,
|
31
26
|
)
|
32
|
-
from
|
33
|
-
from
|
27
|
+
from .anomaly_dataset import AnomalyDatasets, AnomalyOutput, TestData
|
28
|
+
from ..const import SupportedModels
|
29
|
+
from ..operator_config import AnomalyOperatorConfig, AnomalyOperatorSpec
|
34
30
|
|
35
31
|
|
36
32
|
class AnomalyOperatorBaseModel(ABC):
|
@@ -246,7 +242,7 @@ class AnomalyOperatorBaseModel(ABC):
|
|
246
242
|
"""Saves resulting reports to the given folder."""
|
247
243
|
import report_creator as rc
|
248
244
|
|
249
|
-
unique_output_dir =
|
245
|
+
unique_output_dir = self.spec.output_directory.url
|
250
246
|
|
251
247
|
if ObjectStorageDetails.is_oci_path(unique_output_dir):
|
252
248
|
storage_options = default_signer()
|
@@ -320,11 +316,11 @@ class AnomalyOperatorBaseModel(ABC):
|
|
320
316
|
# Iterate over the full_data_dict items
|
321
317
|
for target, df in self.datasets.full_data_dict.items():
|
322
318
|
est = linear_model.SGDOneClassSVM(random_state=42)
|
323
|
-
est.fit(df[
|
319
|
+
est.fit(df[self.spec.target_column].fillna(0).values.reshape(-1, 1))
|
324
320
|
y_pred = np.vectorize(self.outlier_map.get)(
|
325
|
-
est.predict(df[
|
321
|
+
est.predict(df[self.spec.target_column].fillna(0).values.reshape(-1, 1))
|
326
322
|
)
|
327
|
-
scores = est.score_samples(df[
|
323
|
+
scores = est.score_samples(df[self.spec.target_column].fillna(0).values.reshape(-1, 1))
|
328
324
|
|
329
325
|
anomaly = pd.DataFrame(
|
330
326
|
{date_column: df[date_column], OutputColumns.ANOMALY_COL: y_pred}
|
@@ -16,6 +16,7 @@ from ads.opctl.operator.common.operator_config import (
|
|
16
16
|
InputData,
|
17
17
|
)
|
18
18
|
from .const import SupportedModels
|
19
|
+
from ads.opctl.operator.lowcode.common.utils import find_output_dirname
|
19
20
|
|
20
21
|
|
21
22
|
@dataclass(repr=True)
|
@@ -79,6 +80,7 @@ class AnomalyOperatorSpec(DataClassSerializable):
|
|
79
80
|
|
80
81
|
def __post_init__(self):
|
81
82
|
"""Adjusts the specification details."""
|
83
|
+
self.output_directory = self.output_directory or OutputDirectory(url=find_output_dirname(self.output_directory))
|
82
84
|
self.report_file_name = self.report_file_name or "report.html"
|
83
85
|
self.report_theme = self.report_theme or "light"
|
84
86
|
self.inliers_filename = self.inliers_filename or "inliers.csv"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
2
|
# -*- coding: utf-8 -*--
|
3
3
|
|
4
|
-
# Copyright (c) 2023 Oracle and/or its affiliates.
|
4
|
+
# Copyright (c) 2023, 2024 Oracle and/or its affiliates.
|
5
5
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
6
6
|
|
7
7
|
import os
|
@@ -77,5 +77,6 @@ def default_signer(**kwargs):
|
|
77
77
|
|
78
78
|
return default_signer(**kwargs)
|
79
79
|
|
80
|
+
|
80
81
|
def select_auto_model(datasets, operator_config):
|
81
|
-
return SupportedModels.
|
82
|
+
return SupportedModels.AutoTS
|
@@ -97,7 +97,8 @@ class Transformations(ABC):
|
|
97
97
|
for value in merged_values:
|
98
98
|
self._target_category_columns_map[value] = df[df[DataColumns.Series] == value][self.target_category_columns].drop_duplicates().iloc[0].to_dict()
|
99
99
|
|
100
|
-
|
100
|
+
if self.target_category_columns != [DataColumns.Series]:
|
101
|
+
df = df.drop(self.target_category_columns, axis=1)
|
101
102
|
return df
|
102
103
|
|
103
104
|
def _format_datetime_col(self, df):
|
@@ -38,9 +38,7 @@ To run forecasting locally, create and activate a new conda environment (`ads-fo
|
|
38
38
|
- report-creator
|
39
39
|
- cerberus
|
40
40
|
- sktime
|
41
|
-
- optuna
|
42
|
-
- oracle-automlx==23.4.1
|
43
|
-
- oracle-automlx[forecasting]==23.4.1
|
41
|
+
- optuna
|
44
42
|
- oracle-ads>=2.9.0
|
45
43
|
```
|
46
44
|
|
@@ -24,24 +24,9 @@ def operate(operator_config: ForecastOperatorConfig) -> None:
|
|
24
24
|
from .model.factory import ForecastOperatorModelFactory
|
25
25
|
|
26
26
|
datasets = ForecastDatasets(operator_config)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
).generate_report()
|
31
|
-
except Exception as e:
|
32
|
-
if operator_config.spec.model == "auto":
|
33
|
-
logger.debug(
|
34
|
-
f"Failed to forecast with error {e.args}. Trying again with model `prophet`."
|
35
|
-
)
|
36
|
-
operator_config.spec.model = "prophet"
|
37
|
-
operator_config.spec.model_kwargs = dict()
|
38
|
-
datasets = ForecastDatasets(operator_config)
|
39
|
-
ForecastOperatorModelFactory.get_model(
|
40
|
-
operator_config, datasets
|
41
|
-
).generate_report()
|
42
|
-
else:
|
43
|
-
raise
|
44
|
-
|
27
|
+
ForecastOperatorModelFactory.get_model(
|
28
|
+
operator_config, datasets
|
29
|
+
).generate_report()
|
45
30
|
|
46
31
|
def verify(spec: Dict, **kwargs: Dict) -> bool:
|
47
32
|
"""Verifies the forecasting operator config."""
|
@@ -14,6 +14,7 @@ class SupportedModels(str, metaclass=ExtendedEnumMeta):
|
|
14
14
|
Prophet = "prophet"
|
15
15
|
Arima = "arima"
|
16
16
|
NeuralProphet = "neuralprophet"
|
17
|
+
MLForecast = "mlforecast"
|
17
18
|
AutoMLX = "automlx"
|
18
19
|
AutoTS = "autots"
|
19
20
|
Auto = "auto"
|
@@ -86,3 +87,4 @@ DEFAULT_TRIALS = 10
|
|
86
87
|
SUMMARY_METRICS_HORIZON_LIMIT = 10
|
87
88
|
PROPHET_INTERNAL_DATE_COL = "ds"
|
88
89
|
RENDER_LIMIT = 5000
|
90
|
+
AUTO_SELECT = "auto-select"
|
@@ -8,6 +8,7 @@ dependencies:
|
|
8
8
|
- oracle-ads>=2.9.0
|
9
9
|
- prophet
|
10
10
|
- neuralprophet
|
11
|
+
- mlforecast
|
11
12
|
- pmdarima
|
12
13
|
- statsmodels
|
13
14
|
- report-creator
|
@@ -16,6 +17,4 @@ dependencies:
|
|
16
17
|
- shap
|
17
18
|
- autots[additional]
|
18
19
|
- optuna
|
19
|
-
- oracle-automlx>=23.4.1
|
20
|
-
- oracle-automlx[forecasting]>=23.4.1
|
21
20
|
- fire
|
@@ -125,6 +125,7 @@ class ArimaOperatorModel(ForecastOperatorBaseModel):
|
|
125
125
|
logger.debug("===========Done===========")
|
126
126
|
except Exception as e:
|
127
127
|
self.errors_dict[s_id] = {"model_name": self.spec.model, "error": str(e)}
|
128
|
+
logger.debug(f"Encountered Error: {e}. Skipping.")
|
128
129
|
|
129
130
|
def _build_model(self) -> pd.DataFrame:
|
130
131
|
full_data_dict = self.datasets.get_data_by_series()
|
@@ -62,8 +62,8 @@ class AutoMLXOperatorModel(ForecastOperatorBaseModel):
|
|
62
62
|
@runtime_dependency(
|
63
63
|
module="automlx",
|
64
64
|
err_msg=(
|
65
|
-
"Please run `pip3 install oracle-automlx
|
66
|
-
"`pip3 install oracle-automlx[forecasting]
|
65
|
+
"Please run `pip3 install oracle-automlx>=23.4.1` and "
|
66
|
+
"`pip3 install oracle-automlx[forecasting]>=23.4.1` "
|
67
67
|
"to install the required dependencies for automlx."
|
68
68
|
),
|
69
69
|
)
|
@@ -84,7 +84,7 @@ class AutoMLXOperatorModel(ForecastOperatorBaseModel):
|
|
84
84
|
loglevel=logging.CRITICAL,
|
85
85
|
)
|
86
86
|
except Exception as e:
|
87
|
-
logger.info("Ray already initialized")
|
87
|
+
logger.info(f"Error. Has Ray already been initialized? Skipping. {e}")
|
88
88
|
|
89
89
|
full_data_dict = self.datasets.get_data_by_series()
|
90
90
|
|
@@ -113,7 +113,9 @@ class AutoMLXOperatorModel(ForecastOperatorBaseModel):
|
|
113
113
|
data_i = self.drop_horizon(data)
|
114
114
|
X_pred = self.get_horizon(data).drop(target, axis=1)
|
115
115
|
|
116
|
-
logger.debug(
|
116
|
+
logger.debug(
|
117
|
+
f"Time Index Monotonic: {data_i.index.is_monotonic_increasing}"
|
118
|
+
)
|
117
119
|
|
118
120
|
if self.loaded_models is not None and s_id in self.loaded_models:
|
119
121
|
model = self.loaded_models[s_id]
|
@@ -166,6 +168,7 @@ class AutoMLXOperatorModel(ForecastOperatorBaseModel):
|
|
166
168
|
"model_name": self.spec.model,
|
167
169
|
"error": str(e),
|
168
170
|
}
|
171
|
+
logger.debug(f"Encountered Error: {e}. Skipping.")
|
169
172
|
|
170
173
|
logger.debug("===========Forecast Generated===========")
|
171
174
|
|
@@ -4,31 +4,19 @@
|
|
4
4
|
# Copyright (c) 2023, 2024 Oracle and/or its affiliates.
|
5
5
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
6
6
|
|
7
|
-
import
|
7
|
+
import fsspec
|
8
|
+
import numpy as np
|
8
9
|
import os
|
10
|
+
import pandas as pd
|
9
11
|
import tempfile
|
10
12
|
import time
|
13
|
+
import traceback
|
11
14
|
from abc import ABC, abstractmethod
|
12
15
|
from typing import Tuple
|
13
|
-
import traceback
|
14
|
-
|
15
|
-
import fsspec
|
16
|
-
import numpy as np
|
17
|
-
import pandas as pd
|
18
16
|
|
19
|
-
from ads.
|
20
|
-
default_signer,
|
21
|
-
evaluate_train_metrics,
|
22
|
-
get_forecast_plots,
|
23
|
-
_build_metrics_df,
|
24
|
-
_build_metrics_per_horizon,
|
25
|
-
load_pkl,
|
26
|
-
write_pkl,
|
27
|
-
_label_encode_dataframe,
|
28
|
-
)
|
17
|
+
from ads.common.decorator.runtime_dependency import runtime_dependency
|
29
18
|
from ads.common.object_storage_details import ObjectStorageDetails
|
30
19
|
from ads.opctl import logger
|
31
|
-
|
32
20
|
from ads.opctl.operator.lowcode.common.utils import (
|
33
21
|
human_time_friendly,
|
34
22
|
enable_print,
|
@@ -37,18 +25,28 @@ from ads.opctl.operator.lowcode.common.utils import (
|
|
37
25
|
merged_category_column_name,
|
38
26
|
datetime_to_seconds,
|
39
27
|
seconds_to_datetime,
|
40
|
-
find_output_dirname,
|
41
28
|
)
|
29
|
+
from ads.opctl.operator.lowcode.forecast.model.forecast_datasets import TestData
|
30
|
+
from ads.opctl.operator.lowcode.forecast.utils import (
|
31
|
+
default_signer,
|
32
|
+
evaluate_train_metrics,
|
33
|
+
get_forecast_plots,
|
34
|
+
get_auto_select_plot,
|
35
|
+
_build_metrics_df,
|
36
|
+
_build_metrics_per_horizon,
|
37
|
+
load_pkl,
|
38
|
+
write_pkl,
|
39
|
+
_label_encode_dataframe,
|
40
|
+
)
|
41
|
+
from .forecast_datasets import ForecastDatasets
|
42
42
|
from ..const import (
|
43
43
|
SUMMARY_METRICS_HORIZON_LIMIT,
|
44
44
|
SupportedMetrics,
|
45
45
|
SupportedModels,
|
46
46
|
SpeedAccuracyMode,
|
47
|
+
AUTO_SELECT
|
47
48
|
)
|
48
49
|
from ..operator_config import ForecastOperatorConfig, ForecastOperatorSpec
|
49
|
-
from ads.common.decorator.runtime_dependency import runtime_dependency
|
50
|
-
from .forecast_datasets import ForecastDatasets, ForecastOutput
|
51
|
-
from ads.opctl.operator.lowcode.forecast.model.forecast_datasets import TestData
|
52
50
|
|
53
51
|
|
54
52
|
class ForecastOperatorBaseModel(ABC):
|
@@ -250,6 +248,23 @@ class ForecastOperatorBaseModel(ABC):
|
|
250
248
|
sec9 = rc.DataTable(self.eval_metrics, index=True)
|
251
249
|
train_metrics_sections = [sec9_text, sec9]
|
252
250
|
|
251
|
+
backtest_sections = []
|
252
|
+
if self.spec.model == AUTO_SELECT:
|
253
|
+
output_dir = self.spec.output_directory.url
|
254
|
+
backtest_report_name = "backtest_stats.csv"
|
255
|
+
backtest_stats = pd.read_csv(f"{output_dir}/{backtest_report_name}")
|
256
|
+
average_dict = backtest_stats.mean().to_dict()
|
257
|
+
del average_dict['backtest']
|
258
|
+
best_model = min(average_dict, key=average_dict.get)
|
259
|
+
backtest_text = rc.Heading("Back Testing Metrics", level=2)
|
260
|
+
summary_text = rc.Text(
|
261
|
+
f"Overall, the average scores for the models are {average_dict}, with {best_model}"
|
262
|
+
f" being identified as the top-performing model during backtesting.")
|
263
|
+
backtest_table = rc.DataTable(backtest_stats, index=True)
|
264
|
+
liner_plot = get_auto_select_plot(backtest_stats)
|
265
|
+
backtest_sections = [backtest_text, backtest_table, summary_text, liner_plot]
|
266
|
+
|
267
|
+
|
253
268
|
forecast_plots = []
|
254
269
|
if len(self.forecast_output.list_series_ids()) > 0:
|
255
270
|
forecast_text = rc.Heading(
|
@@ -276,6 +291,7 @@ class ForecastOperatorBaseModel(ABC):
|
|
276
291
|
yaml_appendix = rc.Yaml(self.config.to_dict())
|
277
292
|
report_sections = (
|
278
293
|
[summary]
|
294
|
+
+ backtest_sections
|
279
295
|
+ forecast_plots
|
280
296
|
+ other_sections
|
281
297
|
+ test_metrics_sections
|
@@ -409,7 +425,7 @@ class ForecastOperatorBaseModel(ABC):
|
|
409
425
|
"""Saves resulting reports to the given folder."""
|
410
426
|
import report_creator as rc
|
411
427
|
|
412
|
-
unique_output_dir =
|
428
|
+
unique_output_dir = self.spec.output_directory.url
|
413
429
|
|
414
430
|
if ObjectStorageDetails.is_oci_path(unique_output_dir):
|
415
431
|
storage_options = default_signer()
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# Copyright (c) 2023 Oracle and/or its affiliates.
|
5
5
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
6
6
|
|
7
|
-
from ..const import SupportedModels
|
7
|
+
from ..const import SupportedModels, AUTO_SELECT
|
8
8
|
from ..operator_config import ForecastOperatorConfig
|
9
9
|
from .arima import ArimaOperatorModel
|
10
10
|
from .automlx import AutoMLXOperatorModel
|
@@ -12,8 +12,9 @@ from .autots import AutoTSOperatorModel
|
|
12
12
|
from .base_model import ForecastOperatorBaseModel
|
13
13
|
from .neuralprophet import NeuralProphetOperatorModel
|
14
14
|
from .prophet import ProphetOperatorModel
|
15
|
-
from ..utils import select_auto_model
|
16
15
|
from .forecast_datasets import ForecastDatasets
|
16
|
+
from .ml_forecast import MLForecastOperatorModel
|
17
|
+
from ..model_evaluator import ModelEvaluator
|
17
18
|
|
18
19
|
class UnSupportedModelError(Exception):
|
19
20
|
def __init__(self, model_type: str):
|
@@ -32,6 +33,7 @@ class ForecastOperatorModelFactory:
|
|
32
33
|
SupportedModels.Prophet: ProphetOperatorModel,
|
33
34
|
SupportedModels.Arima: ArimaOperatorModel,
|
34
35
|
SupportedModels.NeuralProphet: NeuralProphetOperatorModel,
|
36
|
+
SupportedModels.MLForecast: MLForecastOperatorModel,
|
35
37
|
SupportedModels.AutoMLX: AutoMLXOperatorModel,
|
36
38
|
SupportedModels.AutoTS: AutoTSOperatorModel
|
37
39
|
}
|
@@ -61,8 +63,35 @@ class ForecastOperatorModelFactory:
|
|
61
63
|
In case of not supported model.
|
62
64
|
"""
|
63
65
|
model_type = operator_config.spec.model
|
64
|
-
if model_type ==
|
65
|
-
model_type =
|
66
|
+
if model_type == AUTO_SELECT:
|
67
|
+
model_type = cls.auto_select_model(datasets, operator_config)
|
68
|
+
operator_config.spec.model_kwargs = dict()
|
66
69
|
if model_type not in cls._MAP:
|
67
70
|
raise UnSupportedModelError(model_type)
|
68
71
|
return cls._MAP[model_type](config=operator_config, datasets=datasets)
|
72
|
+
|
73
|
+
@classmethod
|
74
|
+
def auto_select_model(
|
75
|
+
cls, datasets: ForecastDatasets, operator_config: ForecastOperatorConfig
|
76
|
+
) -> str:
|
77
|
+
"""
|
78
|
+
Selects AutoMLX or Arima model based on column count.
|
79
|
+
|
80
|
+
If the number of columns is less than or equal to the maximum allowed for AutoMLX,
|
81
|
+
returns 'AutoMLX'. Otherwise, returns 'Arima'.
|
82
|
+
|
83
|
+
Parameters
|
84
|
+
------------
|
85
|
+
datasets: ForecastDatasets
|
86
|
+
Datasets for predictions
|
87
|
+
|
88
|
+
Returns
|
89
|
+
--------
|
90
|
+
str
|
91
|
+
The type of the model.
|
92
|
+
"""
|
93
|
+
all_models = operator_config.spec.model_kwargs.get("model_list", cls._MAP.keys())
|
94
|
+
num_backtests = operator_config.spec.model_kwargs.get("num_backtests", 5)
|
95
|
+
sample_ratio = operator_config.spec.model_kwargs.get("sample_ratio", 0.20)
|
96
|
+
model_evaluator = ModelEvaluator(all_models, num_backtests, sample_ratio)
|
97
|
+
return model_evaluator.find_best_model(datasets, operator_config)
|
@@ -86,7 +86,10 @@ class AdditionalData(AbstractData):
|
|
86
86
|
pd.date_range(
|
87
87
|
start=historical_data.get_max_time(),
|
88
88
|
periods=spec.horizon + 1,
|
89
|
-
freq=historical_data.freq
|
89
|
+
freq=historical_data.freq
|
90
|
+
or pd.infer_freq(
|
91
|
+
historical_data.data.reset_index()[spec.datetime_column.name][-5:]
|
92
|
+
),
|
90
93
|
),
|
91
94
|
name=spec.datetime_column.name,
|
92
95
|
)
|
@@ -135,6 +138,7 @@ class ForecastDatasets:
|
|
135
138
|
|
136
139
|
self._horizon = config.spec.horizon
|
137
140
|
self._datetime_column_name = config.spec.datetime_column.name
|
141
|
+
self._target_col = config.spec.target_column
|
138
142
|
self._load_data(config.spec)
|
139
143
|
|
140
144
|
def _load_data(self, spec):
|
@@ -158,6 +162,16 @@ class ForecastDatasets:
|
|
158
162
|
on=[self._datetime_column_name, ForecastOutputColumns.SERIES],
|
159
163
|
).reset_index()
|
160
164
|
|
165
|
+
def get_all_data_long_forecast_horizon(self):
|
166
|
+
"""Returns all data in long format for the forecast horizon."""
|
167
|
+
test_data = pd.merge(
|
168
|
+
self.historical_data.data,
|
169
|
+
self.additional_data.data,
|
170
|
+
how="outer",
|
171
|
+
on=[self._datetime_column_name, ForecastOutputColumns.SERIES],
|
172
|
+
).reset_index()
|
173
|
+
return test_data[test_data[self._target_col].isnull()].reset_index(drop=True)
|
174
|
+
|
161
175
|
def get_data_multi_indexed(self):
|
162
176
|
return pd.concat(
|
163
177
|
[
|