oracle-ads 2.10.0__py3-none-any.whl → 2.11.0__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 (117) hide show
  1. ads/aqua/__init__.py +12 -0
  2. ads/aqua/base.py +324 -0
  3. ads/aqua/cli.py +19 -0
  4. ads/aqua/config/deployment_config_defaults.json +9 -0
  5. ads/aqua/config/resource_limit_names.json +7 -0
  6. ads/aqua/constants.py +45 -0
  7. ads/aqua/data.py +40 -0
  8. ads/aqua/decorator.py +101 -0
  9. ads/aqua/deployment.py +643 -0
  10. ads/aqua/dummy_data/icon.txt +1 -0
  11. ads/aqua/dummy_data/oci_model_deployments.json +56 -0
  12. ads/aqua/dummy_data/oci_models.json +1 -0
  13. ads/aqua/dummy_data/readme.md +26 -0
  14. ads/aqua/evaluation.py +1751 -0
  15. ads/aqua/exception.py +82 -0
  16. ads/aqua/extension/__init__.py +40 -0
  17. ads/aqua/extension/base_handler.py +138 -0
  18. ads/aqua/extension/common_handler.py +21 -0
  19. ads/aqua/extension/deployment_handler.py +202 -0
  20. ads/aqua/extension/evaluation_handler.py +135 -0
  21. ads/aqua/extension/finetune_handler.py +66 -0
  22. ads/aqua/extension/model_handler.py +59 -0
  23. ads/aqua/extension/ui_handler.py +201 -0
  24. ads/aqua/extension/utils.py +23 -0
  25. ads/aqua/finetune.py +579 -0
  26. ads/aqua/job.py +29 -0
  27. ads/aqua/model.py +819 -0
  28. ads/aqua/training/__init__.py +4 -0
  29. ads/aqua/training/exceptions.py +459 -0
  30. ads/aqua/ui.py +453 -0
  31. ads/aqua/utils.py +715 -0
  32. ads/cli.py +37 -6
  33. ads/common/auth.py +7 -0
  34. ads/common/decorator/__init__.py +7 -3
  35. ads/common/decorator/require_nonempty_arg.py +65 -0
  36. ads/common/object_storage_details.py +166 -7
  37. ads/common/oci_client.py +18 -1
  38. ads/common/oci_logging.py +2 -2
  39. ads/common/oci_mixin.py +4 -5
  40. ads/common/serializer.py +34 -5
  41. ads/common/utils.py +75 -10
  42. ads/config.py +40 -1
  43. ads/dataset/correlation_plot.py +10 -12
  44. ads/jobs/ads_job.py +43 -25
  45. ads/jobs/builders/infrastructure/base.py +4 -2
  46. ads/jobs/builders/infrastructure/dsc_job.py +49 -39
  47. ads/jobs/builders/runtimes/base.py +71 -1
  48. ads/jobs/builders/runtimes/container_runtime.py +4 -4
  49. ads/jobs/builders/runtimes/pytorch_runtime.py +10 -63
  50. ads/jobs/templates/driver_pytorch.py +27 -10
  51. ads/model/artifact_downloader.py +84 -14
  52. ads/model/artifact_uploader.py +25 -23
  53. ads/model/datascience_model.py +388 -38
  54. ads/model/deployment/model_deployment.py +10 -2
  55. ads/model/generic_model.py +8 -0
  56. ads/model/model_file_description_schema.json +68 -0
  57. ads/model/model_metadata.py +1 -1
  58. ads/model/service/oci_datascience_model.py +34 -5
  59. ads/opctl/config/merger.py +2 -2
  60. ads/opctl/operator/__init__.py +3 -1
  61. ads/opctl/operator/cli.py +7 -1
  62. ads/opctl/operator/cmd.py +3 -3
  63. ads/opctl/operator/common/errors.py +2 -1
  64. ads/opctl/operator/common/operator_config.py +22 -3
  65. ads/opctl/operator/common/utils.py +16 -0
  66. ads/opctl/operator/lowcode/anomaly/MLoperator +15 -0
  67. ads/opctl/operator/lowcode/anomaly/README.md +209 -0
  68. ads/opctl/operator/lowcode/anomaly/__init__.py +5 -0
  69. ads/opctl/operator/lowcode/anomaly/__main__.py +104 -0
  70. ads/opctl/operator/lowcode/anomaly/cmd.py +35 -0
  71. ads/opctl/operator/lowcode/anomaly/const.py +88 -0
  72. ads/opctl/operator/lowcode/anomaly/environment.yaml +12 -0
  73. ads/opctl/operator/lowcode/anomaly/model/__init__.py +5 -0
  74. ads/opctl/operator/lowcode/anomaly/model/anomaly_dataset.py +147 -0
  75. ads/opctl/operator/lowcode/anomaly/model/automlx.py +89 -0
  76. ads/opctl/operator/lowcode/anomaly/model/autots.py +103 -0
  77. ads/opctl/operator/lowcode/anomaly/model/base_model.py +354 -0
  78. ads/opctl/operator/lowcode/anomaly/model/factory.py +67 -0
  79. ads/opctl/operator/lowcode/anomaly/model/tods.py +119 -0
  80. ads/opctl/operator/lowcode/anomaly/operator_config.py +105 -0
  81. ads/opctl/operator/lowcode/anomaly/schema.yaml +359 -0
  82. ads/opctl/operator/lowcode/anomaly/utils.py +81 -0
  83. ads/opctl/operator/lowcode/common/__init__.py +5 -0
  84. ads/opctl/operator/lowcode/common/const.py +10 -0
  85. ads/opctl/operator/lowcode/common/data.py +96 -0
  86. ads/opctl/operator/lowcode/common/errors.py +41 -0
  87. ads/opctl/operator/lowcode/common/transformations.py +191 -0
  88. ads/opctl/operator/lowcode/common/utils.py +250 -0
  89. ads/opctl/operator/lowcode/forecast/README.md +3 -2
  90. ads/opctl/operator/lowcode/forecast/__main__.py +18 -2
  91. ads/opctl/operator/lowcode/forecast/cmd.py +8 -7
  92. ads/opctl/operator/lowcode/forecast/const.py +17 -1
  93. ads/opctl/operator/lowcode/forecast/environment.yaml +3 -2
  94. ads/opctl/operator/lowcode/forecast/model/arima.py +106 -117
  95. ads/opctl/operator/lowcode/forecast/model/automlx.py +204 -180
  96. ads/opctl/operator/lowcode/forecast/model/autots.py +144 -253
  97. ads/opctl/operator/lowcode/forecast/model/base_model.py +326 -259
  98. ads/opctl/operator/lowcode/forecast/model/forecast_datasets.py +325 -176
  99. ads/opctl/operator/lowcode/forecast/model/neuralprophet.py +293 -237
  100. ads/opctl/operator/lowcode/forecast/model/prophet.py +191 -208
  101. ads/opctl/operator/lowcode/forecast/operator_config.py +24 -33
  102. ads/opctl/operator/lowcode/forecast/schema.yaml +116 -29
  103. ads/opctl/operator/lowcode/forecast/utils.py +186 -356
  104. ads/opctl/operator/lowcode/pii/model/guardrails.py +18 -15
  105. ads/opctl/operator/lowcode/pii/model/report.py +7 -7
  106. ads/opctl/operator/lowcode/pii/operator_config.py +1 -8
  107. ads/opctl/operator/lowcode/pii/utils.py +0 -82
  108. ads/opctl/operator/runtime/runtime.py +3 -2
  109. ads/telemetry/base.py +62 -0
  110. ads/telemetry/client.py +105 -0
  111. ads/telemetry/telemetry.py +6 -3
  112. {oracle_ads-2.10.0.dist-info → oracle_ads-2.11.0.dist-info}/METADATA +44 -7
  113. {oracle_ads-2.10.0.dist-info → oracle_ads-2.11.0.dist-info}/RECORD +116 -59
  114. ads/opctl/operator/lowcode/forecast/model/transformations.py +0 -125
  115. {oracle_ads-2.10.0.dist-info → oracle_ads-2.11.0.dist-info}/LICENSE.txt +0 -0
  116. {oracle_ads-2.10.0.dist-info → oracle_ads-2.11.0.dist-info}/WHEEL +0 -0
  117. {oracle_ads-2.10.0.dist-info → oracle_ads-2.11.0.dist-info}/entry_points.txt +0 -0
@@ -7,15 +7,17 @@
7
7
  import pandas as pd
8
8
  import numpy as np
9
9
  import pmdarima as pm
10
+ from joblib import Parallel, delayed
10
11
 
11
12
  from ads.opctl import logger
12
13
 
13
- from .. import utils
14
+ from ads.opctl.operator.lowcode.forecast.utils import _label_encode_dataframe
15
+ from ads.opctl.operator.lowcode.common.utils import seconds_to_datetime
14
16
  from .base_model import ForecastOperatorBaseModel
15
17
  from ..operator_config import ForecastOperatorConfig
16
18
  import traceback
17
19
  from .forecast_datasets import ForecastDatasets, ForecastOutput
18
- from ..const import ForecastOutputColumns
20
+ from ..const import ForecastOutputColumns, SupportedModels
19
21
 
20
22
 
21
23
  class ArimaOperatorModel(ForecastOperatorBaseModel):
@@ -25,13 +27,10 @@ class ArimaOperatorModel(ForecastOperatorBaseModel):
25
27
  super().__init__(config, datasets=datasets)
26
28
  self.global_explanation = {}
27
29
  self.local_explanation = {}
28
- self.train_metrics = True
29
30
  self.formatted_global_explanation = None
30
31
  self.formatted_local_explanation = None
31
32
 
32
- def _build_model(self) -> pd.DataFrame:
33
- full_data_dict = self.datasets.full_data_dict
34
-
33
+ def set_kwargs(self):
35
34
  # Extract the Confidence Interval Width and convert to arima's equivalent - alpha
36
35
  if self.spec.confidence_interval_width is None:
37
36
  self.spec.confidence_interval_width = 1 - self.spec.model_kwargs.get(
@@ -41,74 +40,57 @@ class ArimaOperatorModel(ForecastOperatorBaseModel):
41
40
  model_kwargs["alpha"] = 1 - self.spec.confidence_interval_width
42
41
  if "error_action" not in model_kwargs.keys():
43
42
  model_kwargs["error_action"] = "ignore"
43
+ return model_kwargs
44
44
 
45
- models = []
46
- self.datasets.datetime_col = self.spec.datetime_column.name
47
- self.forecast_output = ForecastOutput(
48
- confidence_interval_width=self.spec.confidence_interval_width
45
+ def preprocess(self, data, series_id): # TODO: re-use self.le for explanations
46
+ self.le[series_id], df_encoded = _label_encode_dataframe(
47
+ data,
48
+ no_encode={self.spec.datetime_column.name, self.original_target_column},
49
49
  )
50
+ return df_encoded.set_index(self.spec.datetime_column.name)
50
51
 
51
- outputs = dict()
52
- outputs_legacy = []
53
- fitted_values = dict()
54
- actual_values = dict()
55
- dt_columns = dict()
56
-
57
- for i, (target, df) in enumerate(full_data_dict.items()):
58
- # format the dataframe for this target. Dropping NA on target[df] will remove all future data
59
- le, df_encoded = utils._label_encode_dataframe(
60
- df, no_encode={self.spec.datetime_column.name, target}
61
- )
52
+ def _train_model(self, i, s_id, df, model_kwargs):
53
+ """Trains the ARIMA model for a given series of the dataset.
62
54
 
63
- df_encoded[self.spec.datetime_column.name] = pd.to_datetime(
64
- df_encoded[self.spec.datetime_column.name],
65
- format=self.spec.datetime_column.format,
66
- )
67
- df_clean = df_encoded.set_index(self.spec.datetime_column.name)
68
- data_i = df_clean[df_clean[target].notna()]
55
+ Parameters
56
+ ----------
57
+ i: int
58
+ The index of the series
59
+ s_id: str
60
+ The name of the series
61
+ df: pd.DataFrame
62
+ The dataframe containing the target data
63
+ """
64
+ try:
65
+ target = self.original_target_column
66
+ self.forecast_output.init_series_output(series_id=s_id, data_at_series=df)
69
67
 
70
- # Assume that all columns passed in should be used as additional data
71
- additional_regressors = set(data_i.columns) - {
72
- target,
73
- self.spec.datetime_column.name,
74
- }
75
- logger.debug(
76
- f"Additional Regressors Detected {list(additional_regressors)}"
77
- )
68
+ # format the dataframe for this target. Dropping NA on target[df] will remove all future data
69
+ data = self.preprocess(df, s_id)
70
+ data_i = self.drop_horizon(data)
78
71
 
79
72
  # Split data into X and y for arima tune method
80
73
  y = data_i[target]
81
- X_in = None
82
- if len(additional_regressors):
83
- X_in = data_i.drop(target, axis=1)
84
-
85
- # Build and fit model
86
- model = pm.auto_arima(y=y, X=X_in, **self.spec.model_kwargs)
87
-
88
- fitted_values[target] = model.predict_in_sample(X=X_in)
89
- actual_values[target] = y
90
- actual_values[target].index = pd.to_datetime(y.index)
91
-
92
- # Build future dataframe
93
- start_date = y.index.values[-1]
94
- n_periods = self.spec.horizon
95
- if len(additional_regressors):
96
- X = df_clean[df_clean[target].isnull()].drop(target, axis=1)
74
+ X_in = data_i.drop(target, axis=1) if len(data_i.columns) > 1 else None
75
+ X_pred = self.get_horizon(data).drop(target, axis=1)
76
+
77
+ if self.loaded_models is not None:
78
+ model = self.loaded_models[s_id]
97
79
  else:
98
- X = pd.date_range(
99
- start=start_date, periods=n_periods, freq=self.spec.freq
100
- )
80
+ # Build and fit model
81
+ model = pm.auto_arima(y=y, X=X_in, **model_kwargs)
82
+
83
+ fitted_values = model.predict_in_sample(X=X_in).values
101
84
 
102
85
  # Predict and format forecast
103
86
  yhat, conf_int = model.predict(
104
- n_periods=n_periods,
105
- X=X,
87
+ n_periods=self.spec.horizon,
88
+ X=X_pred,
106
89
  return_conf_int=True,
107
90
  alpha=model_kwargs["alpha"],
108
91
  )
109
92
  yhat_clean = pd.DataFrame(yhat, index=yhat.index, columns=["yhat"])
110
93
 
111
- dt_columns[target] = df_encoded[self.spec.datetime_column.name]
112
94
  conf_int_clean = pd.DataFrame(
113
95
  conf_int, index=yhat.index, columns=["yhat_lower", "yhat_upper"]
114
96
  )
@@ -116,43 +98,47 @@ class ArimaOperatorModel(ForecastOperatorBaseModel):
116
98
  logger.debug(f"-----------------Model {i}----------------------")
117
99
  logger.debug(forecast[["yhat", "yhat_lower", "yhat_upper"]].tail())
118
100
 
119
- # Collect all outputs
120
- models.append(model)
121
- outputs_legacy.append(
122
- forecast.reset_index().rename(columns={"index": "ds"})
123
- )
124
- outputs[target] = forecast
125
-
126
- self.models = models
127
-
128
- logger.debug("===========Done===========")
129
-
130
- # Merge the outputs from each model into 1 df with all outputs by target and category
131
- col = self.original_target_column
132
- output_col = pd.DataFrame()
133
- yhat_upper_name = ForecastOutputColumns.UPPER_BOUND
134
- yhat_lower_name = ForecastOutputColumns.LOWER_BOUND
135
- for cat in self.categories:
136
- output_i = pd.DataFrame()
137
- output_i["Date"] = dt_columns[f"{col}_{cat}"]
138
- output_i["Series"] = cat
139
- output_i = output_i.set_index("Date")
140
-
141
- output_i["input_value"] = actual_values[f"{col}_{cat}"]
142
- output_i["fitted_value"] = fitted_values[f"{col}_{cat}"]
143
- output_i["forecast_value"] = outputs[f"{col}_{cat}"]["yhat"]
144
- output_i[yhat_upper_name] = outputs[f"{col}_{cat}"]["yhat_upper"]
145
- output_i[yhat_lower_name] = outputs[f"{col}_{cat}"]["yhat_lower"]
146
-
147
- output_i = output_i.reset_index(drop=False)
148
- output_col = pd.concat([output_col, output_i])
149
- self.forecast_output.add_category(
150
- category=cat, target_category_column=f"{col}_{cat}", forecast=output_i
101
+ self.forecast_output.populate_series_output(
102
+ series_id=s_id,
103
+ fit_val=fitted_values,
104
+ forecast_val=self.get_horizon(forecast["yhat"]).values,
105
+ upper_bound=self.get_horizon(forecast["yhat_upper"]).values,
106
+ lower_bound=self.get_horizon(forecast["yhat_lower"]).values,
151
107
  )
152
108
 
153
- output_col = output_col.reset_index(drop=True)
109
+ self.models[s_id] = model
110
+
111
+ params = vars(model).copy()
112
+ for param in ["arima_res_", "endog_index_"]:
113
+ if param in params:
114
+ params.pop(param)
115
+ self.model_parameters[s_id] = {
116
+ "framework": SupportedModels.Arima,
117
+ **params,
118
+ }
154
119
 
155
- return output_col
120
+ logger.debug("===========Done===========")
121
+ except Exception as e:
122
+ self.errors_dict[s_id] = {"model_name": self.spec.model, "error": str(e)}
123
+
124
+ def _build_model(self) -> pd.DataFrame:
125
+ full_data_dict = self.datasets.get_data_by_series()
126
+ self.models = dict()
127
+ self.additional_regressors = self.datasets.get_additional_data_column_names()
128
+ model_kwargs = self.set_kwargs()
129
+ self.forecast_output = ForecastOutput(
130
+ confidence_interval_width=self.spec.confidence_interval_width,
131
+ horizon=self.spec.horizon,
132
+ target_column=self.original_target_column,
133
+ dt_column=self.spec.datetime_column.name,
134
+ )
135
+
136
+ Parallel(n_jobs=-1, require="sharedmem")(
137
+ delayed(self._train_model)(i, s_id, df, model_kwargs.copy())
138
+ for (i, (s_id, df)) in enumerate(full_data_dict.items())
139
+ )
140
+
141
+ return self.forecast_output.get_forecast_long()
156
142
 
157
143
  def _generate_report(self):
158
144
  """The method that needs to be implemented on the particular model level."""
@@ -160,8 +146,11 @@ class ArimaOperatorModel(ForecastOperatorBaseModel):
160
146
 
161
147
  sec5_text = dp.Text(f"## ARIMA Model Parameters")
162
148
  blocks = [
163
- dp.HTML(m.summary().as_html(), label=self.target_columns[i])
164
- for i, m in enumerate(self.models)
149
+ dp.HTML(
150
+ m.summary().as_html(),
151
+ label=s_id,
152
+ )
153
+ for i, (s_id, m) in enumerate(self.models.items())
165
154
  ]
166
155
  sec5 = dp.Select(blocks=blocks) if len(blocks) > 1 else blocks[0]
167
156
  all_sections = [sec5_text, sec5]
@@ -169,11 +158,7 @@ class ArimaOperatorModel(ForecastOperatorBaseModel):
169
158
  if self.spec.generate_explanations:
170
159
  try:
171
160
  # If the key is present, call the "explain_model" method
172
- self.explain_model(
173
- datetime_col_name=self.spec.datetime_column.name,
174
- explain_predict_fn=self._custom_predict_arima,
175
- )
176
-
161
+ self.explain_model()
177
162
  # Create a markdown text block for the global explanation section
178
163
  global_explanation_text = dp.Text(
179
164
  f"## Global Explanation of Models \n "
@@ -186,6 +171,12 @@ class ArimaOperatorModel(ForecastOperatorBaseModel):
186
171
  self.formatted_global_explanation = (
187
172
  global_explanation_df / global_explanation_df.sum(axis=0) * 100
188
173
  )
174
+ self.formatted_global_explanation = (
175
+ self.formatted_global_explanation.rename(
176
+ {self.spec.datetime_column.name: ForecastOutputColumns.DATE},
177
+ axis=1,
178
+ )
179
+ )
189
180
 
190
181
  # Create a markdown section for the global explainability
191
182
  global_explanation_section = dp.Blocks(
@@ -238,23 +229,21 @@ class ArimaOperatorModel(ForecastOperatorBaseModel):
238
229
  other_sections,
239
230
  )
240
231
 
241
- def _custom_predict_arima(self, data):
242
- """
243
- Custom prediction function for ARIMA models.
244
-
245
- Parameters
246
- ----------
247
- data (array-like): The input data to be predicted.
248
-
249
- Returns
250
- -------
251
- array-like: The predicted values.
252
-
253
- """
254
- # Get the index of the current series id
255
- series_index = self.target_columns.index(self.series_id)
256
-
257
- # Use the ARIMA model to predict the values
258
- predictions = self.models[series_index].predict(X=data, n_periods=len(data))
232
+ def get_explain_predict_fn(self, series_id):
233
+ def _custom_predict(
234
+ data,
235
+ model=self.models[series_id],
236
+ dt_column_name=self.datasets._datetime_column_name,
237
+ target_col=self.original_target_column,
238
+ ):
239
+ """
240
+ data: ForecastDatasets.get_data_at_series(s_id)
241
+ """
242
+ data = data.drop([target_col], axis=1)
243
+ data[dt_column_name] = seconds_to_datetime(
244
+ data[dt_column_name], dt_format=self.spec.datetime_column.format
245
+ )
246
+ data = self.preprocess(data, series_id)
247
+ return model.predict(X=data, n_periods=len(data))
259
248
 
260
- return predictions
249
+ return _custom_predict