oracle-ads 2.11.17__py3-none-any.whl → 2.11.18__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/common/auth.py +4 -4
- ads/jobs/builders/infrastructure/dsc_job.py +11 -5
- ads/jobs/builders/infrastructure/dsc_job_runtime.py +12 -25
- ads/jobs/builders/runtimes/artifact.py +0 -5
- ads/jobs/builders/runtimes/container_runtime.py +26 -3
- ads/opctl/conda/cmds.py +100 -42
- ads/opctl/conda/pack.py +3 -2
- ads/opctl/operator/lowcode/anomaly/const.py +1 -0
- ads/opctl/operator/lowcode/anomaly/model/base_model.py +58 -37
- ads/opctl/operator/lowcode/anomaly/model/factory.py +2 -0
- ads/opctl/operator/lowcode/anomaly/model/randomcutforest.py +116 -0
- ads/opctl/operator/lowcode/anomaly/schema.yaml +1 -0
- ads/opctl/operator/lowcode/forecast/const.py +1 -1
- ads/opctl/operator/lowcode/forecast/model/arima.py +6 -2
- ads/opctl/operator/lowcode/forecast/model/automlx.py +6 -1
- ads/opctl/operator/lowcode/forecast/model/autots.py +3 -1
- ads/opctl/operator/lowcode/forecast/model/factory.py +1 -1
- ads/opctl/operator/lowcode/forecast/model/ml_forecast.py +24 -15
- ads/opctl/operator/lowcode/forecast/model/neuralprophet.py +6 -1
- ads/opctl/operator/lowcode/forecast/model/prophet.py +3 -1
- ads/opctl/operator/lowcode/forecast/schema.yaml +1 -1
- {oracle_ads-2.11.17.dist-info → oracle_ads-2.11.18.dist-info}/METADATA +4 -1
- {oracle_ads-2.11.17.dist-info → oracle_ads-2.11.18.dist-info}/RECORD +26 -25
- {oracle_ads-2.11.17.dist-info → oracle_ads-2.11.18.dist-info}/LICENSE.txt +0 -0
- {oracle_ads-2.11.17.dist-info → oracle_ads-2.11.18.dist-info}/WHEEL +0 -0
- {oracle_ads-2.11.17.dist-info → oracle_ads-2.11.18.dist-info}/entry_points.txt +0 -0
ads/common/auth.py
CHANGED
@@ -73,7 +73,7 @@ class AuthState(metaclass=SingletonMeta):
|
|
73
73
|
self.oci_key_profile = self.oci_key_profile or os.environ.get(
|
74
74
|
"OCI_CONFIG_PROFILE", DEFAULT_PROFILE
|
75
75
|
)
|
76
|
-
self.oci_config = self.oci_config or {}
|
76
|
+
self.oci_config = self.oci_config or {"region": os.environ["OCI_RESOURCE_REGION"]} if os.environ.get("OCI_RESOURCE_REGION") else {}
|
77
77
|
self.oci_signer_kwargs = self.oci_signer_kwargs or {}
|
78
78
|
self.oci_client_kwargs = self.oci_client_kwargs or {}
|
79
79
|
|
@@ -82,7 +82,7 @@ def set_auth(
|
|
82
82
|
auth: Optional[str] = AuthType.API_KEY,
|
83
83
|
oci_config_location: Optional[str] = DEFAULT_LOCATION,
|
84
84
|
profile: Optional[str] = DEFAULT_PROFILE,
|
85
|
-
config: Optional[Dict] = {},
|
85
|
+
config: Optional[Dict] = {"region": os.environ["OCI_RESOURCE_REGION"]} if os.environ.get("OCI_RESOURCE_REGION") else {},
|
86
86
|
signer: Optional[Any] = None,
|
87
87
|
signer_callable: Optional[Callable] = None,
|
88
88
|
signer_kwargs: Optional[Dict] = {},
|
@@ -678,7 +678,7 @@ class ResourcePrincipal(AuthSignerGenerator):
|
|
678
678
|
>>> signer_generator = AuthFactory().signerGenerator(AuthType.RESOURCE_PRINCIPAL)
|
679
679
|
>>> signer_generator(signer_args).create_signer()
|
680
680
|
"""
|
681
|
-
configuration = ads.telemetry.update_oci_client_config()
|
681
|
+
configuration = ads.telemetry.update_oci_client_config(AuthState().oci_config)
|
682
682
|
signer_dict = {
|
683
683
|
"config": configuration,
|
684
684
|
"signer": oci.auth.signers.get_resource_principals_signer(),
|
@@ -739,7 +739,7 @@ class InstancePrincipal(AuthSignerGenerator):
|
|
739
739
|
>>> signer_generator = AuthFactory().signerGenerator(AuthType.INSTANCE_PRINCIPAL)
|
740
740
|
>>> signer_generator(signer_args).create_signer()
|
741
741
|
"""
|
742
|
-
configuration = ads.telemetry.update_oci_client_config()
|
742
|
+
configuration = ads.telemetry.update_oci_client_config(AuthState().oci_config)
|
743
743
|
signer_dict = {
|
744
744
|
"config": configuration,
|
745
745
|
"signer": oci.auth.signers.InstancePrincipalsSecurityTokenSigner(
|
@@ -312,7 +312,7 @@ class DSCJob(OCIDataScienceMixin, oci.data_science.models.Job):
|
|
312
312
|
logger.debug(oci_model)
|
313
313
|
res = self.client.create_job(oci_model)
|
314
314
|
self.update_from_oci_model(res.data)
|
315
|
-
if self.
|
315
|
+
if not self.artifact:
|
316
316
|
return
|
317
317
|
try:
|
318
318
|
if issubclass(self.artifact.__class__, Artifact):
|
@@ -487,7 +487,9 @@ class DSCJob(OCIDataScienceMixin, oci.data_science.models.Job):
|
|
487
487
|
oci.data_science.models.DefaultJobConfigurationDetails().swagger_types.keys()
|
488
488
|
)
|
489
489
|
env_config_swagger_types = {}
|
490
|
-
if hasattr(
|
490
|
+
if hasattr(
|
491
|
+
oci.data_science.models, "OcirContainerJobEnvironmentConfigurationDetails"
|
492
|
+
):
|
491
493
|
env_config_swagger_types = (
|
492
494
|
oci.data_science.models.OcirContainerJobEnvironmentConfigurationDetails().swagger_types.keys()
|
493
495
|
)
|
@@ -501,7 +503,7 @@ class DSCJob(OCIDataScienceMixin, oci.data_science.models.Job):
|
|
501
503
|
value = kwargs.pop(key)
|
502
504
|
if key in [
|
503
505
|
ContainerRuntime.CONST_CMD,
|
504
|
-
ContainerRuntime.CONST_ENTRYPOINT
|
506
|
+
ContainerRuntime.CONST_ENTRYPOINT,
|
505
507
|
] and isinstance(value, str):
|
506
508
|
value = ContainerRuntimeHandler.split_args(value)
|
507
509
|
env_config_kwargs[key] = value
|
@@ -535,9 +537,13 @@ class DSCJob(OCIDataScienceMixin, oci.data_science.models.Job):
|
|
535
537
|
|
536
538
|
if env_config_kwargs:
|
537
539
|
env_config_kwargs["jobEnvironmentType"] = "OCIR_CONTAINER"
|
538
|
-
env_config_override = kwargs.get(
|
540
|
+
env_config_override = kwargs.get(
|
541
|
+
"job_environment_configuration_override_details", {}
|
542
|
+
)
|
539
543
|
env_config_override.update(env_config_kwargs)
|
540
|
-
kwargs["job_environment_configuration_override_details"] =
|
544
|
+
kwargs["job_environment_configuration_override_details"] = (
|
545
|
+
env_config_override
|
546
|
+
)
|
541
547
|
|
542
548
|
wait = kwargs.pop("wait", False)
|
543
549
|
run = DataScienceJobRun(**kwargs, **self.auth).create()
|
@@ -181,9 +181,9 @@ class RuntimeHandler:
|
|
181
181
|
"jobType": self.data_science_job.job_type,
|
182
182
|
}
|
183
183
|
if runtime.maximum_runtime_in_minutes:
|
184
|
-
job_configuration_details[
|
185
|
-
|
186
|
-
|
184
|
+
job_configuration_details["maximum_runtime_in_minutes"] = (
|
185
|
+
runtime.maximum_runtime_in_minutes
|
186
|
+
)
|
187
187
|
job_configuration_details["environment_variables"] = self._translate_env(
|
188
188
|
runtime
|
189
189
|
)
|
@@ -310,7 +310,7 @@ class RuntimeHandler:
|
|
310
310
|
for extraction in extractions:
|
311
311
|
runtime_spec.update(extraction(dsc_job))
|
312
312
|
return self.RUNTIME_CLASS(self._format_env_var(runtime_spec))
|
313
|
-
|
313
|
+
|
314
314
|
def _extract_properties(self, dsc_job) -> dict:
|
315
315
|
"""Extract the job runtime properties from data science job.
|
316
316
|
|
@@ -968,23 +968,10 @@ class ContainerRuntimeHandler(RuntimeHandler):
|
|
968
968
|
payload["job_environment_configuration_details"] = job_env_config
|
969
969
|
return payload
|
970
970
|
|
971
|
-
def _translate_artifact(self, runtime:
|
972
|
-
"""
|
973
|
-
runtime
|
974
|
-
|
975
|
-
Parameters
|
976
|
-
----------
|
977
|
-
runtime : Runtime
|
978
|
-
This is not used.
|
979
|
-
|
980
|
-
Returns
|
981
|
-
-------
|
982
|
-
str
|
983
|
-
Path to the dummy script.
|
984
|
-
"""
|
985
|
-
return os.path.join(
|
986
|
-
os.path.dirname(__file__), "../../templates", "container.py"
|
987
|
-
)
|
971
|
+
def _translate_artifact(self, runtime: ContainerRuntime):
|
972
|
+
"""Additional artifact for the container"""
|
973
|
+
if runtime.artifact_uri:
|
974
|
+
return ScriptArtifact(runtime.artifact_uri, runtime)
|
988
975
|
|
989
976
|
def _translate_env_config(self, runtime: Runtime) -> dict:
|
990
977
|
"""Converts runtime properties to ``OcirContainerJobEnvironmentConfigurationDetails`` payload required by OCI Data Science job.
|
@@ -1007,7 +994,7 @@ class ContainerRuntimeHandler(RuntimeHandler):
|
|
1007
994
|
property = runtime.get_spec(key, None)
|
1008
995
|
if key in [
|
1009
996
|
ContainerRuntime.CONST_CMD,
|
1010
|
-
ContainerRuntime.CONST_ENTRYPOINT
|
997
|
+
ContainerRuntime.CONST_ENTRYPOINT,
|
1011
998
|
] and isinstance(property, str):
|
1012
999
|
property = self.split_args(property)
|
1013
1000
|
if property is not None:
|
@@ -1063,7 +1050,7 @@ class ContainerRuntimeHandler(RuntimeHandler):
|
|
1063
1050
|
spec[ContainerRuntime.CONST_ENV_VAR] = envs
|
1064
1051
|
|
1065
1052
|
return spec
|
1066
|
-
|
1053
|
+
|
1067
1054
|
def _extract_properties(self, dsc_job) -> dict:
|
1068
1055
|
"""Extract the runtime properties from data science job.
|
1069
1056
|
|
@@ -1078,10 +1065,10 @@ class ContainerRuntimeHandler(RuntimeHandler):
|
|
1078
1065
|
A runtime specification dictionary for initializing a runtime.
|
1079
1066
|
"""
|
1080
1067
|
spec = super()._extract_envs(dsc_job)
|
1081
|
-
|
1068
|
+
|
1082
1069
|
job_env_config = getattr(dsc_job, "job_environment_configuration_details", None)
|
1083
1070
|
job_env_type = getattr(job_env_config, "job_environment_type", None)
|
1084
|
-
|
1071
|
+
|
1085
1072
|
if not (job_env_config and job_env_type == "OCIR_CONTAINER"):
|
1086
1073
|
raise IncompatibleRuntime()
|
1087
1074
|
|
@@ -183,11 +183,6 @@ class ScriptArtifact(Artifact):
|
|
183
183
|
if os.path.isdir(source):
|
184
184
|
basename = os.path.basename(str(source).rstrip("/"))
|
185
185
|
source = str(source).rstrip("/")
|
186
|
-
# Runtime must have entrypoint if the source is a directory
|
187
|
-
if self.runtime and not self.runtime.entrypoint:
|
188
|
-
raise ValueError(
|
189
|
-
"Please specify entrypoint when script source is a directory."
|
190
|
-
)
|
191
186
|
output = os.path.join(self.temp_dir.name, basename)
|
192
187
|
shutil.make_archive(
|
193
188
|
output, "zip", os.path.dirname(source), base_dir=basename
|
@@ -56,6 +56,7 @@ class ContainerRuntime(MultiNodeRuntime):
|
|
56
56
|
CONST_CMD = "cmd"
|
57
57
|
CONST_IMAGE_DIGEST = "imageDigest"
|
58
58
|
CONST_IMAGE_SIGNATURE_ID = "imageSignatureId"
|
59
|
+
CONST_SCRIPT_PATH = "scriptPathURI"
|
59
60
|
attribute_map = {
|
60
61
|
CONST_IMAGE: CONST_IMAGE,
|
61
62
|
CONST_ENTRYPOINT: CONST_ENTRYPOINT,
|
@@ -121,7 +122,7 @@ class ContainerRuntime(MultiNodeRuntime):
|
|
121
122
|
def image_digest(self) -> str:
|
122
123
|
"""The container image digest."""
|
123
124
|
return self.get_spec(self.CONST_IMAGE_DIGEST)
|
124
|
-
|
125
|
+
|
125
126
|
def with_image_digest(self, image_digest: str) -> "ContainerRuntime":
|
126
127
|
"""Sets the digest of custom image.
|
127
128
|
|
@@ -136,12 +137,12 @@ class ContainerRuntime(MultiNodeRuntime):
|
|
136
137
|
The runtime instance.
|
137
138
|
"""
|
138
139
|
return self.set_spec(self.CONST_IMAGE_DIGEST, image_digest)
|
139
|
-
|
140
|
+
|
140
141
|
@property
|
141
142
|
def image_signature_id(self) -> str:
|
142
143
|
"""The container image signature id."""
|
143
144
|
return self.get_spec(self.CONST_IMAGE_SIGNATURE_ID)
|
144
|
-
|
145
|
+
|
145
146
|
def with_image_signature_id(self, image_signature_id: str) -> "ContainerRuntime":
|
146
147
|
"""Sets the signature id of custom image.
|
147
148
|
|
@@ -217,3 +218,25 @@ class ContainerRuntime(MultiNodeRuntime):
|
|
217
218
|
entrypoint=["bash", "--login", "-c"],
|
218
219
|
cmd="{Container CMD. For MLflow and Operator will be auto generated}",
|
219
220
|
)
|
221
|
+
|
222
|
+
@property
|
223
|
+
def artifact_uri(self) -> str:
|
224
|
+
"""The URI of the source code"""
|
225
|
+
return self.get_spec(self.CONST_SCRIPT_PATH)
|
226
|
+
|
227
|
+
def with_artifact(self, uri: str):
|
228
|
+
"""Specifies the artifact to be added to the container.
|
229
|
+
|
230
|
+
Parameters
|
231
|
+
----------
|
232
|
+
uri : str
|
233
|
+
URI to the source code script, which can be any URI supported by fsspec,
|
234
|
+
including http://, https:// and OCI object storage.
|
235
|
+
For example: oci://your_bucket@your_namespace/path/to/script.py
|
236
|
+
|
237
|
+
Returns
|
238
|
+
-------
|
239
|
+
self
|
240
|
+
The runtime instance.
|
241
|
+
"""
|
242
|
+
return self.set_spec(self.CONST_SCRIPT_PATH, uri)
|
ads/opctl/conda/cmds.py
CHANGED
@@ -80,7 +80,7 @@ def _check_job_image_exists(gpu: bool) -> None:
|
|
80
80
|
def _get_name(name: str, env_file: str) -> str:
|
81
81
|
if not name and env_file:
|
82
82
|
with open(env_file) as f:
|
83
|
-
name = yaml.safe_load(f.read()).get("name", None)
|
83
|
+
name = yaml.safe_load(f.read()).get("manifest").get("name", None)
|
84
84
|
if not name:
|
85
85
|
raise ValueError(
|
86
86
|
"Either specify environment name in environment yaml or with `--name`."
|
@@ -146,7 +146,14 @@ def _create(
|
|
146
146
|
if not os.path.exists(env_file):
|
147
147
|
raise FileNotFoundError(f"Environment file {env_file} is not found.")
|
148
148
|
|
149
|
-
|
149
|
+
conda_dep = None
|
150
|
+
with open(env_file) as mfile:
|
151
|
+
conda_dep = yaml.safe_load(mfile.read())
|
152
|
+
# If manifest exists in the environment.yaml file, use that
|
153
|
+
manifest = conda_dep.get("manifest", {})
|
154
|
+
slug = manifest.get(
|
155
|
+
"slug", f"{name}_v{version}".replace(" ", "").replace(".", "_").lower()
|
156
|
+
)
|
150
157
|
pack_folder_path = os.path.join(
|
151
158
|
os.path.abspath(os.path.expanduser(conda_pack_folder)), slug
|
152
159
|
)
|
@@ -171,27 +178,46 @@ def _create(
|
|
171
178
|
|
172
179
|
os.makedirs(pack_folder_path, exist_ok=True)
|
173
180
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
181
|
+
logger.info(
|
182
|
+
f"Preparing manifest. Manifest in the environment: {conda_dep.get('manifest')}"
|
183
|
+
)
|
184
|
+
manifest_template = _fetch_manifest_template()
|
185
|
+
if "name" not in manifest:
|
186
|
+
manifest_template["manifest"]["name"] = name
|
187
|
+
manifest_template["manifest"]["slug"] = slug
|
188
|
+
if "type" not in manifest:
|
189
|
+
logger.info("Setting manifest to published")
|
190
|
+
manifest_template["manifest"]["type"] = "published"
|
191
|
+
if "version" not in manifest:
|
192
|
+
manifest_template["manifest"]["version"] = version
|
193
|
+
manifest_template["manifest"]["arch_type"] = "GPU" if gpu else "CPU"
|
194
|
+
|
195
|
+
manifest_template["manifest"]["create_date"] = datetime.utcnow().strftime(
|
182
196
|
"%a, %b %d, %Y, %H:%M:%S %Z UTC"
|
183
197
|
)
|
184
|
-
|
198
|
+
|
199
|
+
if not "manifest_version" in manifest:
|
200
|
+
manifest_template["manifest"]["manifest_version"] = "1.0"
|
185
201
|
|
186
202
|
logger.info(f"Creating conda environment {slug}")
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
203
|
+
manifest_dict = {
|
204
|
+
k: manifest_template["manifest"][k]
|
205
|
+
for k in manifest_template["manifest"]
|
206
|
+
if manifest_template["manifest"][k]
|
207
|
+
}
|
208
|
+
if "manifest" in conda_dep:
|
209
|
+
conda_dep["manifest"].update(manifest_dict)
|
210
|
+
else:
|
211
|
+
conda_dep["manifest"] = manifest_dict
|
212
|
+
logger.info(f"Updated conda environment manifest: {conda_dep.get('manifest')}")
|
191
213
|
|
192
214
|
if is_in_notebook_session() or NO_CONTAINER:
|
193
215
|
command = f"conda env create --prefix {pack_folder_path} --file {os.path.abspath(os.path.expanduser(env_file))}"
|
194
|
-
run_command(command, shell=True)
|
216
|
+
proc = run_command(command, shell=True)
|
217
|
+
if proc.returncode != 0:
|
218
|
+
raise RuntimeError(
|
219
|
+
f"Failed to create conda environment. (exit code {proc.returncode})"
|
220
|
+
)
|
195
221
|
else:
|
196
222
|
_check_job_image_exists(gpu)
|
197
223
|
docker_pack_folder_path = os.path.join(DEFAULT_IMAGE_HOME_DIR, slug)
|
@@ -200,13 +226,12 @@ def _create(
|
|
200
226
|
)
|
201
227
|
|
202
228
|
create_command = f"conda env create --prefix {docker_pack_folder_path} --file {docker_env_file_path}"
|
203
|
-
|
229
|
+
|
204
230
|
volumes = {
|
205
231
|
pack_folder_path: {"bind": docker_pack_folder_path},
|
206
232
|
os.path.abspath(os.path.expanduser(env_file)): {
|
207
233
|
"bind": docker_env_file_path
|
208
234
|
},
|
209
|
-
|
210
235
|
}
|
211
236
|
|
212
237
|
if gpu:
|
@@ -217,26 +242,42 @@ def _create(
|
|
217
242
|
if prepare_publish:
|
218
243
|
tmp_file = tempfile.NamedTemporaryFile(suffix=".yaml")
|
219
244
|
# Save the manifest in the temp file that can be mounted inside the container so that archiving will work
|
220
|
-
with open(tmp_file.name,
|
221
|
-
yaml.safe_dump(conda_dep, f)
|
245
|
+
with open(tmp_file.name, "w") as f:
|
246
|
+
yaml.safe_dump(conda_dep, f)
|
222
247
|
|
223
|
-
pack_script = os.path.join(
|
248
|
+
pack_script = os.path.join(
|
249
|
+
os.path.dirname(os.path.abspath(__file__)), "pack.py"
|
250
|
+
)
|
224
251
|
pack_command = f"python {os.path.join(DEFAULT_IMAGE_HOME_DIR, 'pack.py')} --conda-path {docker_pack_folder_path} --manifest-location {os.path.join(DEFAULT_IMAGE_HOME_DIR, 'manifest.yaml')}"
|
225
252
|
|
226
253
|
# add pack script and manifest file to the mount so that archive can be created in the same container run
|
227
254
|
condapack_script = {
|
228
|
-
pack_script: {
|
229
|
-
|
255
|
+
pack_script: {
|
256
|
+
"bind": os.path.join(DEFAULT_IMAGE_HOME_DIR, "pack.py")
|
257
|
+
},
|
258
|
+
tmp_file.name: {
|
259
|
+
"bind": os.path.join(DEFAULT_IMAGE_HOME_DIR, "manifest.yaml")
|
260
|
+
},
|
230
261
|
}
|
231
|
-
volumes = {
|
262
|
+
volumes = {
|
263
|
+
**volumes,
|
264
|
+
**condapack_script,
|
265
|
+
} # | not supported in python 3.8
|
232
266
|
|
233
267
|
run_container(
|
234
|
-
image=image,
|
268
|
+
image=image,
|
269
|
+
bind_volumes=volumes,
|
270
|
+
entrypoint="/bin/bash -c ",
|
271
|
+
env_vars={},
|
272
|
+
command=f" '{create_command} && {pack_command}'",
|
235
273
|
)
|
236
274
|
else:
|
237
275
|
run_container(
|
238
|
-
image=image,
|
239
|
-
|
276
|
+
image=image,
|
277
|
+
bind_volumes=volumes,
|
278
|
+
env_vars={},
|
279
|
+
command=create_command,
|
280
|
+
)
|
240
281
|
except Exception:
|
241
282
|
if os.path.exists(pack_folder_path):
|
242
283
|
shutil.rmtree(pack_folder_path)
|
@@ -507,9 +548,11 @@ def publish(**kwargs) -> None:
|
|
507
548
|
conda_pack_folder=exec_config["conda_pack_folder"],
|
508
549
|
gpu=exec_config.get("gpu", False),
|
509
550
|
overwrite=exec_config["overwrite"],
|
510
|
-
prepare_publish=True
|
551
|
+
prepare_publish=True,
|
552
|
+
)
|
553
|
+
skip_archive = (
|
554
|
+
True # The conda pack archive is already created during create process.
|
511
555
|
)
|
512
|
-
skip_archive = True # The conda pack archive is already created during create process.
|
513
556
|
else:
|
514
557
|
slug = exec_config.get("slug")
|
515
558
|
if not slug:
|
@@ -526,10 +569,10 @@ def publish(**kwargs) -> None:
|
|
526
569
|
oci_profile=exec_config.get("oci_profile"),
|
527
570
|
overwrite=exec_config["overwrite"],
|
528
571
|
auth_type=exec_config["auth"],
|
529
|
-
skip_archive=skip_archive
|
572
|
+
skip_archive=skip_archive,
|
530
573
|
)
|
531
574
|
|
532
|
-
|
575
|
+
|
533
576
|
def _publish(
|
534
577
|
conda_slug: str,
|
535
578
|
conda_uri_prefix: str,
|
@@ -538,7 +581,7 @@ def _publish(
|
|
538
581
|
oci_profile: str,
|
539
582
|
overwrite: bool,
|
540
583
|
auth_type: str,
|
541
|
-
skip_archive: bool = False
|
584
|
+
skip_archive: bool = False,
|
542
585
|
) -> None:
|
543
586
|
"""Publish a local conda pack to object storage location
|
544
587
|
|
@@ -616,8 +659,16 @@ def _publish(
|
|
616
659
|
pack_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), "pack.py")
|
617
660
|
if not skip_archive:
|
618
661
|
if is_in_notebook_session() or NO_CONTAINER:
|
662
|
+
# Set the CONDA_PUBLISH_TYPE environment variable so that the `type` attribute inside the manifest is not changed
|
663
|
+
publish_type = os.environ.get("CONDA_PUBLISH_TYPE")
|
619
664
|
command = f"python {pack_script} --conda-path {pack_folder_path}"
|
620
|
-
|
665
|
+
if publish_type:
|
666
|
+
command = f"CONDA_PUBLISH_TYPE={publish_type} {command}"
|
667
|
+
proc = run_command(command, shell=True)
|
668
|
+
if proc.returncode != 0:
|
669
|
+
raise RuntimeError(
|
670
|
+
f"Failed to archive the conda environment. (exit code {proc.returncode})"
|
671
|
+
)
|
621
672
|
else:
|
622
673
|
volumes = {
|
623
674
|
pack_folder_path: {
|
@@ -641,7 +692,9 @@ def _publish(
|
|
641
692
|
NOT_ALLOWED_CHARS = "@#$%^&*/"
|
642
693
|
|
643
694
|
if any(chr in conda_slug for chr in NOT_ALLOWED_CHARS):
|
644
|
-
raise ValueError(
|
695
|
+
raise ValueError(
|
696
|
+
f"Invalid conda_slug. Found {NOT_ALLOWED_CHARS} in slug name. Please use a different slug name."
|
697
|
+
)
|
645
698
|
pack_file = os.path.join(pack_folder_path, f"{conda_slug}.tar.gz")
|
646
699
|
if not os.path.exists(pack_file):
|
647
700
|
raise RuntimeError(f"Pack {pack_file} was not created.")
|
@@ -664,14 +717,19 @@ def _publish(
|
|
664
717
|
str(manifest["version"]),
|
665
718
|
publish_slug,
|
666
719
|
)
|
667
|
-
|
668
|
-
|
669
|
-
manifest
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
720
|
+
if os.environ.get("CONDA_PUBLISH_TYPE") != "service":
|
721
|
+
# Set these values only for published conda pack
|
722
|
+
manifest["pack_path"] = os.path.join(
|
723
|
+
prefix,
|
724
|
+
manifest.get("arch_type", "CPU").lower(),
|
725
|
+
manifest["name"],
|
726
|
+
str(manifest["version"]),
|
727
|
+
publish_slug,
|
728
|
+
)
|
729
|
+
manifest["pack_uri"] = pack_uri
|
730
|
+
else:
|
731
|
+
manifest["type"] = "published"
|
732
|
+
|
675
733
|
with open(manifest_location, "w") as f:
|
676
734
|
yaml.safe_dump(env, f)
|
677
735
|
if pack_size > 100:
|
ads/opctl/conda/pack.py
CHANGED
@@ -20,7 +20,6 @@ import argparse
|
|
20
20
|
|
21
21
|
|
22
22
|
def main(pack_folder_path, manifest_file=None):
|
23
|
-
slug = os.path.basename(pack_folder_path)
|
24
23
|
manifest_path = (
|
25
24
|
manifest_file or glob.glob(os.path.join(pack_folder_path, "*_manifest.yaml"))[0]
|
26
25
|
)
|
@@ -47,7 +46,9 @@ def main(pack_folder_path, manifest_file=None):
|
|
47
46
|
raise e
|
48
47
|
|
49
48
|
manifest = env["manifest"]
|
50
|
-
|
49
|
+
slug = manifest.get("slug", os.path.basename(pack_folder_path))
|
50
|
+
if os.environ.get("CONDA_PUBLISH_TYPE") != "service":
|
51
|
+
manifest["type"] = "published"
|
51
52
|
new_env_info["manifest"] = manifest
|
52
53
|
with open(manifest_path, "w") as f:
|
53
54
|
yaml.safe_dump(new_env_info, f)
|
@@ -16,7 +16,11 @@ from sklearn import linear_model
|
|
16
16
|
|
17
17
|
from ads.common.object_storage_details import ObjectStorageDetails
|
18
18
|
from ads.opctl import logger
|
19
|
-
from ads.opctl.operator.lowcode.anomaly.const import
|
19
|
+
from ads.opctl.operator.lowcode.anomaly.const import (
|
20
|
+
SUBSAMPLE_THRESHOLD,
|
21
|
+
OutputColumns,
|
22
|
+
SupportedMetrics,
|
23
|
+
)
|
20
24
|
from ads.opctl.operator.lowcode.anomaly.utils import _build_metrics_df, default_signer
|
21
25
|
from ads.opctl.operator.lowcode.common.utils import (
|
22
26
|
disable_print,
|
@@ -55,6 +59,7 @@ class AnomalyOperatorBaseModel(ABC):
|
|
55
59
|
def generate_report(self):
|
56
60
|
"""Generates the report."""
|
57
61
|
import matplotlib.pyplot as plt
|
62
|
+
plt.rcParams.update({'figure.max_open_warning': 0})
|
58
63
|
import report_creator as rc
|
59
64
|
|
60
65
|
start_time = time.time()
|
@@ -87,43 +92,59 @@ class AnomalyOperatorBaseModel(ABC):
|
|
87
92
|
self.spec.datetime_column.name if self.spec.datetime_column else "index"
|
88
93
|
)
|
89
94
|
|
95
|
+
(
|
96
|
+
model_description,
|
97
|
+
other_sections,
|
98
|
+
) = self._generate_report()
|
99
|
+
|
90
100
|
blocks = []
|
91
101
|
for target, df in self.datasets.full_data_dict.items():
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
if
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
for
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
102
|
+
if target in anomaly_output.list_categories():
|
103
|
+
figure_blocks = []
|
104
|
+
time_col = df[date_column].reset_index(drop=True)
|
105
|
+
anomaly_col = anomaly_output.get_anomalies_by_cat(category=target)[
|
106
|
+
OutputColumns.ANOMALY_COL
|
107
|
+
]
|
108
|
+
anomaly_indices = [
|
109
|
+
i for i, index in enumerate(anomaly_col) if index == 1
|
110
|
+
]
|
111
|
+
downsampled_time_col = time_col
|
112
|
+
selected_indices = list(range(len(time_col)))
|
113
|
+
if self.spec.subsample_report_data:
|
114
|
+
non_anomaly_indices = [
|
115
|
+
i for i in range(len(time_col)) if i not in anomaly_indices
|
116
|
+
]
|
117
|
+
# Downsample non-anomalous data if it exceeds the threshold (1000)
|
118
|
+
if len(non_anomaly_indices) > SUBSAMPLE_THRESHOLD:
|
119
|
+
downsampled_non_anomaly_indices = non_anomaly_indices[
|
120
|
+
:: len(non_anomaly_indices) // SUBSAMPLE_THRESHOLD
|
121
|
+
]
|
122
|
+
selected_indices = (
|
123
|
+
anomaly_indices + downsampled_non_anomaly_indices
|
124
|
+
)
|
125
|
+
selected_indices.sort()
|
126
|
+
downsampled_time_col = time_col[selected_indices]
|
127
|
+
|
128
|
+
columns = set(df.columns).difference({date_column})
|
129
|
+
for col in columns:
|
130
|
+
y = df[col].reset_index(drop=True)
|
131
|
+
|
132
|
+
downsampled_y = y[selected_indices]
|
133
|
+
|
134
|
+
fig, ax = plt.subplots(figsize=(8, 3), layout="constrained")
|
135
|
+
ax.grid()
|
136
|
+
ax.plot(downsampled_time_col, downsampled_y, color="black")
|
137
|
+
# Plot anomalies
|
138
|
+
for i in anomaly_indices:
|
139
|
+
ax.scatter(time_col[i], y[i], color="red", marker="o")
|
140
|
+
plt.xlabel(date_column)
|
141
|
+
plt.ylabel(col)
|
142
|
+
plt.title(f"`{col}` with reference to anomalies")
|
143
|
+
figure_blocks.append(rc.Widget(ax))
|
144
|
+
else:
|
145
|
+
figure_blocks = None
|
146
|
+
|
147
|
+
blocks.append(rc.Group(*figure_blocks, label=target)) if figure_blocks else None
|
127
148
|
plots = rc.Select(blocks)
|
128
149
|
|
129
150
|
report_sections = []
|
@@ -133,7 +154,7 @@ class AnomalyOperatorBaseModel(ABC):
|
|
133
154
|
yaml_appendix = rc.Yaml(self.config.to_dict())
|
134
155
|
summary = rc.Block(
|
135
156
|
rc.Group(
|
136
|
-
rc.Text(f"You selected the **`{self.spec.model}`** model."),
|
157
|
+
rc.Text(f"You selected the **`{self.spec.model}`** model.\n{model_description.text}\n"),
|
137
158
|
rc.Text(
|
138
159
|
"Based on your dataset, you could have also selected "
|
139
160
|
f"any of the models: `{'`, `'.join(SupportedModels.keys() if self.spec.datetime_column else NonTimeADSupportedModels.keys())}`."
|
@@ -15,6 +15,7 @@ from .autots import AutoTSOperatorModel
|
|
15
15
|
from .base_model import AnomalyOperatorBaseModel
|
16
16
|
from .isolationforest import IsolationForestOperatorModel
|
17
17
|
from .oneclasssvm import OneClassSVMOperatorModel
|
18
|
+
from .randomcutforest import RandomCutForestOperatorModel
|
18
19
|
|
19
20
|
|
20
21
|
class UnSupportedModelError(Exception):
|
@@ -52,6 +53,7 @@ class AnomalyOperatorModelFactory:
|
|
52
53
|
_NonTime_MAP = {
|
53
54
|
NonTimeADSupportedModels.OneClassSVM: OneClassSVMOperatorModel,
|
54
55
|
NonTimeADSupportedModels.IsolationForest: IsolationForestOperatorModel,
|
56
|
+
NonTimeADSupportedModels.RandomCutForest: RandomCutForestOperatorModel,
|
55
57
|
# TODO: Add DBScan model for non time based anomaly
|
56
58
|
# NonTimeADSupportedModels.DBScan: DBScanOperatorModel,
|
57
59
|
}
|
@@ -0,0 +1,116 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
|
3
|
+
# Copyright (c) 2023, 2024 Oracle and/or its affiliates.
|
4
|
+
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
5
|
+
|
6
|
+
import numpy as np
|
7
|
+
import pandas as pd
|
8
|
+
|
9
|
+
from ads.common.decorator.runtime_dependency import runtime_dependency
|
10
|
+
from ads.opctl import logger
|
11
|
+
from ads.opctl.operator.lowcode.anomaly.const import OutputColumns
|
12
|
+
|
13
|
+
from .anomaly_dataset import AnomalyOutput
|
14
|
+
from .base_model import AnomalyOperatorBaseModel
|
15
|
+
|
16
|
+
|
17
|
+
class RandomCutForestOperatorModel(AnomalyOperatorBaseModel):
|
18
|
+
"""
|
19
|
+
Class representing Random Cut Forest Anomaly Detection operator model.
|
20
|
+
"""
|
21
|
+
|
22
|
+
@runtime_dependency(
|
23
|
+
module="rrcf",
|
24
|
+
err_msg=(
|
25
|
+
"Please run `pip install rrcf` to "
|
26
|
+
"install the required dependencies for RandomCutForest."
|
27
|
+
),
|
28
|
+
)
|
29
|
+
def _build_model(self) -> AnomalyOutput:
|
30
|
+
from rrcf import RCTree
|
31
|
+
|
32
|
+
model_kwargs = self.spec.model_kwargs
|
33
|
+
|
34
|
+
anomaly_output = AnomalyOutput(date_column="index")
|
35
|
+
|
36
|
+
# Set tree parameters
|
37
|
+
num_trees = model_kwargs.get("num_trees", 200)
|
38
|
+
shingle_size = model_kwargs.get("shingle_size", None)
|
39
|
+
anomaly_threshold = model_kwargs.get("anamoly_threshold", 95)
|
40
|
+
|
41
|
+
for target, df in self.datasets.full_data_dict.items():
|
42
|
+
try:
|
43
|
+
if df.shape[0] == 1:
|
44
|
+
raise ValueError("Dataset size must be greater than 1")
|
45
|
+
df_values = df[self.spec.target_column].astype(float).values
|
46
|
+
|
47
|
+
cal_shingle_size = (
|
48
|
+
shingle_size
|
49
|
+
if shingle_size
|
50
|
+
else int(2 ** np.floor(np.log2(df.shape[0])) / 2)
|
51
|
+
)
|
52
|
+
points = np.vstack(list(rrcf.shingle(df_values, size=cal_shingle_size)))
|
53
|
+
|
54
|
+
sample_size_range = (1, points.shape[0])
|
55
|
+
n = points.shape[0]
|
56
|
+
avg_codisp = pd.Series(0.0, index=np.arange(n))
|
57
|
+
index = np.zeros(n)
|
58
|
+
|
59
|
+
forest = []
|
60
|
+
while len(forest) < num_trees:
|
61
|
+
ixs = np.random.choice(n, size=sample_size_range, replace=False)
|
62
|
+
trees = [rrcf.RCTree(points[ix], index_labels=ix) for ix in ixs]
|
63
|
+
forest.extend(trees)
|
64
|
+
|
65
|
+
for tree in forest:
|
66
|
+
codisp = pd.Series(
|
67
|
+
{leaf: tree.codisp(leaf) for leaf in tree.leaves}
|
68
|
+
)
|
69
|
+
avg_codisp[codisp.index] += codisp
|
70
|
+
np.add.at(index, codisp.index.values, 1)
|
71
|
+
|
72
|
+
avg_codisp /= index
|
73
|
+
avg_codisp.index = df.iloc[(cal_shingle_size - 1) :].index
|
74
|
+
avg_codisp = (avg_codisp - avg_codisp.min()) / (
|
75
|
+
avg_codisp.max() - avg_codisp.min()
|
76
|
+
)
|
77
|
+
|
78
|
+
y_pred = (
|
79
|
+
avg_codisp > np.percentile(avg_codisp, anomaly_threshold)
|
80
|
+
).astype(int)
|
81
|
+
|
82
|
+
index_col = df.columns[0]
|
83
|
+
|
84
|
+
anomaly = pd.DataFrame(
|
85
|
+
{index_col: y_pred.index, OutputColumns.ANOMALY_COL: y_pred}
|
86
|
+
).reset_index(drop=True)
|
87
|
+
score = pd.DataFrame(
|
88
|
+
{"index": avg_codisp.index, OutputColumns.SCORE_COL: avg_codisp}
|
89
|
+
).reset_index(drop=True)
|
90
|
+
|
91
|
+
anomaly_output.add_output(target, anomaly, score)
|
92
|
+
except Exception as e:
|
93
|
+
logger.warn(f"Encountered Error: {e}. Skipping series {target}.")
|
94
|
+
|
95
|
+
return anomaly_output
|
96
|
+
|
97
|
+
def _generate_report(self):
|
98
|
+
"""Generates the report."""
|
99
|
+
import report_creator as rc
|
100
|
+
|
101
|
+
other_sections = [
|
102
|
+
rc.Heading("Selected Models Overview", level=2),
|
103
|
+
rc.Text(
|
104
|
+
"The following tables provide information regarding the chosen model."
|
105
|
+
),
|
106
|
+
]
|
107
|
+
|
108
|
+
model_description = rc.Text(
|
109
|
+
"The Random Cut Forest (RCF) is an unsupervised machine learning algorithm that is used for anomaly detection."
|
110
|
+
" It works by building an ensemble of binary trees (random cut trees) and using them to compute anomaly scores for data points."
|
111
|
+
)
|
112
|
+
|
113
|
+
return (
|
114
|
+
model_description,
|
115
|
+
other_sections,
|
116
|
+
)
|
@@ -126,8 +126,12 @@ class ArimaOperatorModel(ForecastOperatorBaseModel):
|
|
126
126
|
|
127
127
|
logger.debug("===========Done===========")
|
128
128
|
except Exception as e:
|
129
|
-
self.errors_dict[s_id] = {
|
130
|
-
|
129
|
+
self.errors_dict[s_id] = {
|
130
|
+
"model_name": self.spec.model,
|
131
|
+
"error": str(e),
|
132
|
+
"error_trace": traceback.format_exc()}
|
133
|
+
logger.warn(f"Encountered Error: {e}. Skipping.")
|
134
|
+
logger.warn(traceback.format_exc())
|
131
135
|
|
132
136
|
def _build_model(self) -> pd.DataFrame:
|
133
137
|
full_data_dict = self.datasets.get_data_by_series()
|
@@ -149,6 +149,9 @@ class AutoMLXOperatorModel(ForecastOperatorBaseModel):
|
|
149
149
|
if f"{target}_ci_lower" not in summary_frame:
|
150
150
|
summary_frame[f"{target}_ci_lower"] = np.NAN
|
151
151
|
|
152
|
+
if summary_frame[target].isna().all():
|
153
|
+
raise ValueError("The forecasts are completely NaN")
|
154
|
+
|
152
155
|
self.forecast_output.populate_series_output(
|
153
156
|
series_id=s_id,
|
154
157
|
fit_val=fitted_values,
|
@@ -167,8 +170,10 @@ class AutoMLXOperatorModel(ForecastOperatorBaseModel):
|
|
167
170
|
self.errors_dict[s_id] = {
|
168
171
|
"model_name": self.spec.model,
|
169
172
|
"error": str(e),
|
173
|
+
"error_trace": traceback.format_exc()
|
170
174
|
}
|
171
|
-
logger.
|
175
|
+
logger.warn(f"Encountered Error: {e}. Skipping.")
|
176
|
+
logger.warn(traceback.format_exc())
|
172
177
|
|
173
178
|
logger.debug("===========Forecast Generated===========")
|
174
179
|
|
@@ -208,8 +208,10 @@ class AutoTSOperatorModel(ForecastOperatorBaseModel):
|
|
208
208
|
self.errors_dict[s_id] = {
|
209
209
|
"model_name": self.spec.model,
|
210
210
|
"error": str(e),
|
211
|
+
"error_trace": traceback.format_exc()
|
211
212
|
}
|
212
|
-
logger.
|
213
|
+
logger.warn(f"Encountered Error: {e}. Skipping.")
|
214
|
+
logger.warn(traceback.format_exc())
|
213
215
|
|
214
216
|
logger.debug("===========Done===========")
|
215
217
|
|
@@ -33,7 +33,7 @@ class ForecastOperatorModelFactory:
|
|
33
33
|
SupportedModels.Prophet: ProphetOperatorModel,
|
34
34
|
SupportedModels.Arima: ArimaOperatorModel,
|
35
35
|
SupportedModels.NeuralProphet: NeuralProphetOperatorModel,
|
36
|
-
SupportedModels.
|
36
|
+
SupportedModels.LGBForecast: MLForecastOperatorModel,
|
37
37
|
SupportedModels.AutoMLX: AutoMLXOperatorModel,
|
38
38
|
SupportedModels.AutoTS: AutoTSOperatorModel
|
39
39
|
}
|
@@ -1,18 +1,18 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
|
-
# -*- coding: utf-8 -*--
|
3
2
|
|
4
3
|
# Copyright (c) 2024 Oracle and/or its affiliates.
|
5
4
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
6
|
-
import pandas as pd
|
7
5
|
import numpy as np
|
6
|
+
import pandas as pd
|
8
7
|
|
9
|
-
from ads.opctl import logger
|
10
8
|
from ads.common.decorator import runtime_dependency
|
9
|
+
from ads.opctl import logger
|
11
10
|
from ads.opctl.operator.lowcode.forecast.utils import _select_plot_list
|
11
|
+
|
12
|
+
from ..const import ForecastOutputColumns, SupportedModels
|
13
|
+
from ..operator_config import ForecastOperatorConfig
|
12
14
|
from .base_model import ForecastOperatorBaseModel
|
13
15
|
from .forecast_datasets import ForecastDatasets, ForecastOutput
|
14
|
-
from ..operator_config import ForecastOperatorConfig
|
15
|
-
from ..const import ForecastOutputColumns, SupportedModels
|
16
16
|
|
17
17
|
|
18
18
|
class MLForecastOperatorModel(ForecastOperatorBaseModel):
|
@@ -58,18 +58,25 @@ class MLForecastOperatorModel(ForecastOperatorBaseModel):
|
|
58
58
|
from mlforecast.target_transforms import Differences
|
59
59
|
|
60
60
|
lgb_params = {
|
61
|
-
"verbosity": -1,
|
62
|
-
"num_leaves": 512,
|
61
|
+
"verbosity": model_kwargs.get("verbosity", -1),
|
62
|
+
"num_leaves": model_kwargs.get("num_leaves", 512),
|
63
63
|
}
|
64
64
|
additional_data_params = {}
|
65
65
|
if len(self.datasets.get_additional_data_column_names()) > 0:
|
66
66
|
additional_data_params = {
|
67
|
-
"target_transforms": [
|
67
|
+
"target_transforms": [
|
68
|
+
Differences([model_kwargs.get("Differences", 12)])
|
69
|
+
],
|
68
70
|
"lags": model_kwargs.get("lags", [1, 6, 12]),
|
69
71
|
"lag_transforms": (
|
70
72
|
{
|
71
73
|
1: [ExpandingMean()],
|
72
|
-
12: [
|
74
|
+
12: [
|
75
|
+
RollingMean(
|
76
|
+
window_size=model_kwargs.get("RollingMean", 24),
|
77
|
+
min_samples=1,
|
78
|
+
)
|
79
|
+
],
|
73
80
|
}
|
74
81
|
),
|
75
82
|
}
|
@@ -147,7 +154,7 @@ class MLForecastOperatorModel(ForecastOperatorBaseModel):
|
|
147
154
|
)
|
148
155
|
|
149
156
|
self.model_parameters[s_id] = {
|
150
|
-
"framework": SupportedModels.
|
157
|
+
"framework": SupportedModels.LGBForecast,
|
151
158
|
**lgb_params,
|
152
159
|
}
|
153
160
|
|
@@ -157,8 +164,10 @@ class MLForecastOperatorModel(ForecastOperatorBaseModel):
|
|
157
164
|
self.errors_dict[self.spec.model] = {
|
158
165
|
"model_name": self.spec.model,
|
159
166
|
"error": str(e),
|
167
|
+
"error_trace": traceback.format_exc()
|
160
168
|
}
|
161
|
-
logger.
|
169
|
+
logger.warn(f"Encountered Error: {e}. Skipping.")
|
170
|
+
logger.warn(traceback.format_exc())
|
162
171
|
raise e
|
163
172
|
|
164
173
|
def _build_model(self) -> pd.DataFrame:
|
@@ -204,10 +213,10 @@ class MLForecastOperatorModel(ForecastOperatorBaseModel):
|
|
204
213
|
self.datasets.list_series_ids(),
|
205
214
|
)
|
206
215
|
|
207
|
-
# Section 2:
|
216
|
+
# Section 2: LGBForecast Model Parameters
|
208
217
|
sec2_text = rc.Block(
|
209
|
-
rc.Heading("
|
210
|
-
rc.Text("These are the parameters used for the
|
218
|
+
rc.Heading("LGBForecast Model Parameters", level=2),
|
219
|
+
rc.Text("These are the parameters used for the LGBForecast model."),
|
211
220
|
)
|
212
221
|
|
213
222
|
blocks = [
|
@@ -221,7 +230,7 @@ class MLForecastOperatorModel(ForecastOperatorBaseModel):
|
|
221
230
|
|
222
231
|
all_sections = [sec1_text, sec_1, sec2_text, sec_2]
|
223
232
|
model_description = rc.Text(
|
224
|
-
"
|
233
|
+
"LGBForecast uses mlforecast framework to perform time series forecasting using machine learning models"
|
225
234
|
"with the option to scale to massive amounts of data using remote clusters."
|
226
235
|
"Fastest implementations of feature engineering for time series forecasting in Python."
|
227
236
|
"Support for exogenous variables and static covariates."
|
@@ -217,7 +217,12 @@ class NeuralProphetOperatorModel(ForecastOperatorBaseModel):
|
|
217
217
|
|
218
218
|
logger.debug("===========Done===========")
|
219
219
|
except Exception as e:
|
220
|
-
self.errors_dict[s_id] = {
|
220
|
+
self.errors_dict[s_id] = {
|
221
|
+
"model_name": self.spec.model,
|
222
|
+
"error": str(e),
|
223
|
+
"error_trace": traceback.format_exc()
|
224
|
+
}
|
225
|
+
logger.warn(traceback.format_exc())
|
221
226
|
raise e
|
222
227
|
|
223
228
|
def _build_model(self) -> pd.DataFrame:
|
@@ -130,8 +130,10 @@ class ProphetOperatorModel(ForecastOperatorBaseModel):
|
|
130
130
|
self.errors_dict[series_id] = {
|
131
131
|
"model_name": self.spec.model,
|
132
132
|
"error": str(e),
|
133
|
+
"error_trace": traceback.format_exc()
|
133
134
|
}
|
134
|
-
logger.
|
135
|
+
logger.warn(f"Encountered Error: {e}. Skipping.")
|
136
|
+
logger.warn(traceback.format_exc())
|
135
137
|
|
136
138
|
def _build_model(self) -> pd.DataFrame:
|
137
139
|
full_data_dict = self.datasets.get_data_by_series()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: oracle_ads
|
3
|
-
Version: 2.11.
|
3
|
+
Version: 2.11.18
|
4
4
|
Summary: Oracle Accelerated Data Science SDK
|
5
5
|
Keywords: Oracle Cloud Infrastructure,OCI,Machine Learning,ML,Artificial Intelligence,AI,Data Science,Cloud,Oracle
|
6
6
|
Author: Oracle Data Science
|
@@ -37,6 +37,8 @@ Requires-Dist: oracle_ads[opctl] ; extra == "anomaly"
|
|
37
37
|
Requires-Dist: autots ; extra == "anomaly"
|
38
38
|
Requires-Dist: oracledb ; extra == "anomaly"
|
39
39
|
Requires-Dist: report-creator==1.0.9 ; extra == "anomaly"
|
40
|
+
Requires-Dist: rrcf==0.4.4 ; extra == "anomaly"
|
41
|
+
Requires-Dist: scikit-learn ; extra == "anomaly"
|
40
42
|
Requires-Dist: jupyter_server ; extra == "aqua"
|
41
43
|
Requires-Dist: hdfs[kerberos] ; extra == "bds"
|
42
44
|
Requires-Dist: ibis-framework[impala] ; extra == "bds"
|
@@ -75,6 +77,7 @@ Requires-Dist: plotly ; extra == "forecast"
|
|
75
77
|
Requires-Dist: oracledb ; extra == "forecast"
|
76
78
|
Requires-Dist: report-creator==1.0.9 ; extra == "forecast"
|
77
79
|
Requires-Dist: geopandas<1.0.0 ; extra == "geo"
|
80
|
+
Requires-Dist: fiona<=1.9.6 ; extra == "geo"
|
78
81
|
Requires-Dist: oracle_ads[viz] ; extra == "geo"
|
79
82
|
Requires-Dist: transformers ; extra == "huggingface"
|
80
83
|
Requires-Dist: tf-keras ; extra == "huggingface"
|
@@ -72,7 +72,7 @@ ads/catalog/project.py,sha256=eiCBOu9bHyQUH9SquSi880PDQftyRy3dONO_Qxtdeyk,16092
|
|
72
72
|
ads/catalog/summary.py,sha256=Zy_koBb5FTsP64zyNbqmQZJEWqtoV0lOvI-ZRCQSXa4,5790
|
73
73
|
ads/common/__init__.py,sha256=NBFa_nDAtft8NSiHIfDh5yfxbcJnXISamVH6DrJR_50,293
|
74
74
|
ads/common/analyzer.py,sha256=MrFxBNJwFJwv_kbuJheqvOTz537z7ITE3Il244l3eZU,1893
|
75
|
-
ads/common/auth.py,sha256=
|
75
|
+
ads/common/auth.py,sha256=xU9R_WwtOhe9x815lgmdn0Q2lXlxaY6RDCcfjyjhhFI,45961
|
76
76
|
ads/common/card_identifier.py,sha256=csCCSQNka8wpHE90IGUJqFmFvjbFd42eEIlmUZuOwMA,2458
|
77
77
|
ads/common/config.py,sha256=5QNJaJ5A2tMrDRJemJt62jxZ0pSGRz4bPkn9HGA__N0,20253
|
78
78
|
ads/common/data.py,sha256=jQHf9Kc7llzdnQjseGgMhVuR0XLRafBvEQVk0OY2s_8,6939
|
@@ -417,13 +417,13 @@ ads/jobs/builders/base.py,sha256=o_njFwWQpGY755KbYwpYhvup7UGdcDnN06RdVtAbOkM,483
|
|
417
417
|
ads/jobs/builders/infrastructure/__init__.py,sha256=SgpGnF6ppE6LneSPWysGVdBrYMvVd-jYZD8oQfqtR34,246
|
418
418
|
ads/jobs/builders/infrastructure/base.py,sha256=cm4QXdQ-3Qk3Jz-oVzmeKqLaWW06HgSpc4Q9P3vIHFQ,4405
|
419
419
|
ads/jobs/builders/infrastructure/dataflow.py,sha256=XTuDhcz96vqskE5dFXWqzic1YcYcD5qPlKGhP4J82J0,39281
|
420
|
-
ads/jobs/builders/infrastructure/dsc_job.py,sha256=
|
421
|
-
ads/jobs/builders/infrastructure/dsc_job_runtime.py,sha256=
|
420
|
+
ads/jobs/builders/infrastructure/dsc_job.py,sha256=xnFAP-vH20UraYndQPniHnvC7grZ8BmmctQynkeoua8,65028
|
421
|
+
ads/jobs/builders/infrastructure/dsc_job_runtime.py,sha256=uY_HsBIA5fdfUKIQPdrXq_iu_ZJ32zrVzk-oNV0BWDA,46294
|
422
422
|
ads/jobs/builders/infrastructure/utils.py,sha256=SfGvKiIUsbnMnYFxmMnRtmCDkaiJR0_CuRenP94iQyI,1623
|
423
423
|
ads/jobs/builders/runtimes/__init__.py,sha256=-aGtuFul2fJIMa7xNoOKNFaBAQeBNcZk71hf6dVSohA,204
|
424
|
-
ads/jobs/builders/runtimes/artifact.py,sha256=
|
424
|
+
ads/jobs/builders/runtimes/artifact.py,sha256=7RPm-7hd8zG15iCJDIBbfMr7d003Bed9_0ioM-mu5nE,12555
|
425
425
|
ads/jobs/builders/runtimes/base.py,sha256=KcZMZnyL4eA7EVawYCfa7M11f6lvGbuXZRnqsaVFZBQ,10436
|
426
|
-
ads/jobs/builders/runtimes/container_runtime.py,sha256=
|
426
|
+
ads/jobs/builders/runtimes/container_runtime.py,sha256=T_M7uQW-2tTd9taYC6kz5OD1dG_urIkhNhpQPbatO00,7598
|
427
427
|
ads/jobs/builders/runtimes/python_runtime.py,sha256=lr4XIAfJ-c_cuewf8E-qq-gSNgT2C2qFG57VNwCLODY,35568
|
428
428
|
ads/jobs/builders/runtimes/pytorch_runtime.py,sha256=jQ7iIS3juvzkK9qAPuQdMM_YVk4QepM14e8P6RY0D4E,7238
|
429
429
|
ads/jobs/schema/__init__.py,sha256=xMyuwB5xsIEW9MFmvyjmF1YnRarsIjeFe2Ib-aprCG4,210
|
@@ -561,11 +561,11 @@ ads/opctl/backend/marketplace/models/marketplace_type.py,sha256=Uy_trT3jTlzMINFE
|
|
561
561
|
ads/opctl/backend/marketplace/models/ocir_details.py,sha256=SHCCMXUR1Bn3IdcIW5rrJ48XXF50bGNYjVUQKGjZU8w,1606
|
562
562
|
ads/opctl/conda/__init__.py,sha256=DwYupQz6SOfMLmmAjJ9danchK0shQRJKTGPU--naQgY,204
|
563
563
|
ads/opctl/conda/cli.py,sha256=D6PPHebEXS4srO9dEBTE4YGUJjQvwx0w9v2M5VWs27A,4873
|
564
|
-
ads/opctl/conda/cmds.py,sha256=
|
564
|
+
ads/opctl/conda/cmds.py,sha256=grUBw6CI4bzSixtZhaYwKjM7HnFRoD9ewFpmw4kX5gk,26334
|
565
565
|
ads/opctl/conda/config.yaml,sha256=yDg1cQOCxG2-BvHLfIuc1YT9adlm9kDqDpe4Q882ngY,1026
|
566
566
|
ads/opctl/conda/manifest_template.yaml,sha256=V_uxOhe_eGgsV92u_6onPK-w0rKTLHL_tIhZ9FKqmAI,194
|
567
567
|
ads/opctl/conda/multipart_uploader.py,sha256=1R09ajToBYZsQjgM3-ASnheIOsnZf7sYCHIcBoCjB30,6180
|
568
|
-
ads/opctl/conda/pack.py,sha256=
|
568
|
+
ads/opctl/conda/pack.py,sha256=ghv-mudoS2KVZ2qbEjW7cK1bRu6R3Hto1_3bga0HCMQ,2921
|
569
569
|
ads/opctl/config/__init__.py,sha256=DwYupQz6SOfMLmmAjJ9danchK0shQRJKTGPU--naQgY,204
|
570
570
|
ads/opctl/config/base.py,sha256=R4Grgdjjnax7LLNiNC90VzeUHtsPPjbOcOs1WN5Tlxs,1472
|
571
571
|
ads/opctl/config/merger.py,sha256=DMSTnZj7OOmbO_QM4uKrWUjS9REvMn8zkK8V0uZHO1I,11332
|
@@ -631,19 +631,20 @@ ads/opctl/operator/lowcode/anomaly/README.md,sha256=E3vpyc5iKvIq8iuvGj8ZvLq3i_Q5
|
|
631
631
|
ads/opctl/operator/lowcode/anomaly/__init__.py,sha256=sAqmLhogrLXb3xI7dPOj9HmSkpTnLh9wkzysuGd8AXk,204
|
632
632
|
ads/opctl/operator/lowcode/anomaly/__main__.py,sha256=q7TSFpSmLSAXlwjWNMi_M5y9ndF86RPd7KJ_kanltjM,3328
|
633
633
|
ads/opctl/operator/lowcode/anomaly/cmd.py,sha256=e6ATBJcPXEdZ85hlSb7aWselA-8LlvtpI0AuO4Yw6Iw,1002
|
634
|
-
ads/opctl/operator/lowcode/anomaly/const.py,sha256=
|
634
|
+
ads/opctl/operator/lowcode/anomaly/const.py,sha256=nNZqjH-YNB2GVsk890v3B88pml15xrSOPjvfW2P5M1o,2930
|
635
635
|
ads/opctl/operator/lowcode/anomaly/environment.yaml,sha256=J6KiIHOb5a2AcgZm1sisMgbjABlizyYRUq_aYZBk228,156
|
636
636
|
ads/opctl/operator/lowcode/anomaly/operator_config.py,sha256=A1LBD0n3_M6M_2NuFQ6FrLq4vukUL47iPbPDBkIS3OY,4328
|
637
|
-
ads/opctl/operator/lowcode/anomaly/schema.yaml,sha256=
|
637
|
+
ads/opctl/operator/lowcode/anomaly/schema.yaml,sha256=jMSoCqb58Dz4_LeB55LO9_NRQ8TKPeVdl5VkGZHlqYs,9200
|
638
638
|
ads/opctl/operator/lowcode/anomaly/utils.py,sha256=Uj98FO5oM-sLjoqsOnoBmgSMF7iJiL0XX-gvphw9yiU,2746
|
639
639
|
ads/opctl/operator/lowcode/anomaly/model/__init__.py,sha256=sAqmLhogrLXb3xI7dPOj9HmSkpTnLh9wkzysuGd8AXk,204
|
640
640
|
ads/opctl/operator/lowcode/anomaly/model/anomaly_dataset.py,sha256=zpRRAtbjRgX9HPJb_7-eZ96c1AGQgDjjs-CsLTvYtuY,5402
|
641
641
|
ads/opctl/operator/lowcode/anomaly/model/automlx.py,sha256=Zn4ySrGfLbaKW0KIduwdnY0-YK8XAprCcMhElA4g-Vc,3401
|
642
642
|
ads/opctl/operator/lowcode/anomaly/model/autots.py,sha256=WlA39DA3GeQfW5HYiBLCArVQBXGzIVQH3D09cZYGjtg,3689
|
643
|
-
ads/opctl/operator/lowcode/anomaly/model/base_model.py,sha256=
|
644
|
-
ads/opctl/operator/lowcode/anomaly/model/factory.py,sha256=
|
643
|
+
ads/opctl/operator/lowcode/anomaly/model/base_model.py,sha256=bq2VgRxLIRFov8pEoYCPGw3AXUmTJktA2nszQN8La2c,15365
|
644
|
+
ads/opctl/operator/lowcode/anomaly/model/factory.py,sha256=XEh5bdnWDjIEBswrOb36CeTmRcWQ2uUGDrC3e3iJVxY,3264
|
645
645
|
ads/opctl/operator/lowcode/anomaly/model/isolationforest.py,sha256=Kjsuio7cM-dKv63p58B9Jj0XPly6Z0hqfghs5nnXepA,2671
|
646
646
|
ads/opctl/operator/lowcode/anomaly/model/oneclasssvm.py,sha256=eQpNyax1hnufLHhL8Rbzee28comD2fF7TLn3TpzMrs8,2583
|
647
|
+
ads/opctl/operator/lowcode/anomaly/model/randomcutforest.py,sha256=HUyWQOFjfLkIWsnmhfEn9354slKStlv6jIwQi5xzVj0,4270
|
647
648
|
ads/opctl/operator/lowcode/anomaly/model/tods.py,sha256=_v0KkdTKD3nqzOu3P5tE7bSV63Jy91h6Hr88Eequ0RU,4175
|
648
649
|
ads/opctl/operator/lowcode/common/__init__.py,sha256=rZrmh1nho40OCeabXCNWtze-mXi-PGKetcZdxZSn3_0,204
|
649
650
|
ads/opctl/operator/lowcode/common/const.py,sha256=1dUhgup4L_U0s6BSYmgLPpZAe6xqfSHPPoLqW0j46U8,265
|
@@ -670,23 +671,23 @@ ads/opctl/operator/lowcode/forecast/README.md,sha256=kbCCEdo-0pwKlZp9ctnWUK6Z31n
|
|
670
671
|
ads/opctl/operator/lowcode/forecast/__init__.py,sha256=sAqmLhogrLXb3xI7dPOj9HmSkpTnLh9wkzysuGd8AXk,204
|
671
672
|
ads/opctl/operator/lowcode/forecast/__main__.py,sha256=5Vh-kClwxTsvZLEuECyQBvbZFfH37HQW2G09RwX11Kw,2503
|
672
673
|
ads/opctl/operator/lowcode/forecast/cmd.py,sha256=Q-R3yfK7aPfE4-0zIqzLFSjnz1tVMxJ1bbvrCirVZHQ,1246
|
673
|
-
ads/opctl/operator/lowcode/forecast/const.py,sha256=
|
674
|
+
ads/opctl/operator/lowcode/forecast/const.py,sha256=PBEhOGZaFWzkd5H9Vw687lq2A5q5RZNlS6Mj6ZelOuw,2618
|
674
675
|
ads/opctl/operator/lowcode/forecast/environment.yaml,sha256=eVMf9pcjADI14_GRGdZOB_gK5_MyG_-cX037TXqzFho,330
|
675
676
|
ads/opctl/operator/lowcode/forecast/errors.py,sha256=X9zuV2Lqb5N9FuBHHshOFYyhvng5r9KGLHnQijZ5b8c,911
|
676
677
|
ads/opctl/operator/lowcode/forecast/model_evaluator.py,sha256=dSV1aj25wzv0V3y72YdYj4rCPjXAog13ppxYDNY9HQU,8913
|
677
678
|
ads/opctl/operator/lowcode/forecast/operator_config.py,sha256=XskXuOWtZZb6_EcR_t6XAEdr6jt1wT30oBcWt-8zeWA,6396
|
678
|
-
ads/opctl/operator/lowcode/forecast/schema.yaml,sha256=
|
679
|
+
ads/opctl/operator/lowcode/forecast/schema.yaml,sha256=Zfhh_wfWxNeTtN4bqAe623Vf0HbQWCLyNx8LkiCTCgo,10138
|
679
680
|
ads/opctl/operator/lowcode/forecast/utils.py,sha256=oc6eBH9naYg4BB14KS2HL0uFdZHMgKsxx9vG28dJrXA,14347
|
680
681
|
ads/opctl/operator/lowcode/forecast/model/__init__.py,sha256=sAqmLhogrLXb3xI7dPOj9HmSkpTnLh9wkzysuGd8AXk,204
|
681
|
-
ads/opctl/operator/lowcode/forecast/model/arima.py,sha256=
|
682
|
-
ads/opctl/operator/lowcode/forecast/model/automlx.py,sha256=
|
683
|
-
ads/opctl/operator/lowcode/forecast/model/autots.py,sha256=
|
682
|
+
ads/opctl/operator/lowcode/forecast/model/arima.py,sha256=6ZXtzXcqoEMVF9DChzX0cnTJ-9tXKdbPiiSPQq4a9oM,10914
|
683
|
+
ads/opctl/operator/lowcode/forecast/model/automlx.py,sha256=nMqljeHnhuYGMmRa8e0PkDtx-ClSclQeJVowBIkq0Sk,14848
|
684
|
+
ads/opctl/operator/lowcode/forecast/model/autots.py,sha256=QxU24eZeaRpnC5rTqBFe6-5ylMorPN0sCamHUiNQVaE,13162
|
684
685
|
ads/opctl/operator/lowcode/forecast/model/base_model.py,sha256=s4_lvasasCqvrj49ubD0H_2wA9pvh16_f5BiivqvL20,30876
|
685
|
-
ads/opctl/operator/lowcode/forecast/model/factory.py,sha256=
|
686
|
+
ads/opctl/operator/lowcode/forecast/model/factory.py,sha256=NV_m2sEgj3byHHqLs9Vbth7d5yfvFuXj8QI3-y9x2Po,3488
|
686
687
|
ads/opctl/operator/lowcode/forecast/model/forecast_datasets.py,sha256=d9rDmrIAbKTStOVroIKZkTEP1FP2AP0dq9XDEWt6w2c,16968
|
687
|
-
ads/opctl/operator/lowcode/forecast/model/ml_forecast.py,sha256=
|
688
|
-
ads/opctl/operator/lowcode/forecast/model/neuralprophet.py,sha256=
|
689
|
-
ads/opctl/operator/lowcode/forecast/model/prophet.py,sha256=
|
688
|
+
ads/opctl/operator/lowcode/forecast/model/ml_forecast.py,sha256=EOFZR5wjZcpKACW3ZNnxd31Okz_ehOSaO5_dKL-Ktgw,9558
|
689
|
+
ads/opctl/operator/lowcode/forecast/model/neuralprophet.py,sha256=pRmhLHjP027gmPbkgqzR2SZYKvj1rG9Heev2P8mSZ_k,19347
|
690
|
+
ads/opctl/operator/lowcode/forecast/model/prophet.py,sha256=0OBnyVP9bFpo1zSAqA5qtobZxICRTLVT9mwPOlHb3sM,14554
|
690
691
|
ads/opctl/operator/lowcode/pii/MLoperator,sha256=GKCuiXRwfGLyBqELbtgtg-kJPtNWNVA-kSprYTqhF64,6406
|
691
692
|
ads/opctl/operator/lowcode/pii/README.md,sha256=2P3tpKv6v__Eehj6iLfTXgyDhS4lmi1BTfEdmJhT0K4,9237
|
692
693
|
ads/opctl/operator/lowcode/pii/__init__.py,sha256=sAqmLhogrLXb3xI7dPOj9HmSkpTnLh9wkzysuGd8AXk,204
|
@@ -804,8 +805,8 @@ ads/type_discovery/unknown_detector.py,sha256=yZuYQReO7PUyoWZE7onhhtYaOg6088wf1y
|
|
804
805
|
ads/type_discovery/zipcode_detector.py,sha256=3AlETg_ZF4FT0u914WXvTT3F3Z6Vf51WiIt34yQMRbw,1421
|
805
806
|
ads/vault/__init__.py,sha256=x9tMdDAOdF5iDHk9u2di_K-ze5Nq068x25EWOBoWwqY,245
|
806
807
|
ads/vault/vault.py,sha256=hFBkpYE-Hfmzu1L0sQwUfYcGxpWmgG18JPndRl0NOXI,8624
|
807
|
-
oracle_ads-2.11.
|
808
|
-
oracle_ads-2.11.
|
809
|
-
oracle_ads-2.11.
|
810
|
-
oracle_ads-2.11.
|
811
|
-
oracle_ads-2.11.
|
808
|
+
oracle_ads-2.11.18.dist-info/entry_points.txt,sha256=9VFnjpQCsMORA4rVkvN8eH6D3uHjtegb9T911t8cqV0,35
|
809
|
+
oracle_ads-2.11.18.dist-info/LICENSE.txt,sha256=zoGmbfD1IdRKx834U0IzfFFFo5KoFK71TND3K9xqYqo,1845
|
810
|
+
oracle_ads-2.11.18.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
811
|
+
oracle_ads-2.11.18.dist-info/METADATA,sha256=iFxKKVAC8wzz6V79zwLCYZHHPx741I_hEsdXY4fKjpo,16037
|
812
|
+
oracle_ads-2.11.18.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|