oracle-ads 2.13.6__py3-none-any.whl → 2.13.8__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 +0 -5
- ads/aqua/app.py +133 -20
- ads/aqua/cli.py +2 -15
- ads/aqua/common/utils.py +12 -83
- ads/aqua/config/container_config.py +105 -69
- ads/aqua/config/evaluation/evaluation_service_config.py +40 -0
- ads/aqua/constants.py +22 -20
- ads/aqua/evaluation/evaluation.py +98 -32
- ads/aqua/extension/common_handler.py +3 -12
- ads/aqua/extension/common_ws_msg_handler.py +3 -24
- ads/aqua/extension/model_handler.py +59 -6
- ads/aqua/extension/models/ws_models.py +2 -0
- ads/aqua/extension/models_ws_msg_handler.py +1 -0
- ads/aqua/extension/utils.py +11 -24
- ads/aqua/finetuning/entities.py +23 -1
- ads/aqua/finetuning/finetuning.py +26 -10
- ads/aqua/model/constants.py +8 -0
- ads/aqua/model/entities.py +8 -1
- ads/aqua/model/model.py +278 -113
- ads/aqua/modeldeployment/deployment.py +51 -47
- ads/aqua/modeldeployment/utils.py +23 -5
- ads/aqua/ui.py +3 -4
- ads/config.py +2 -2
- ads/model/datascience_model.py +29 -0
- ads/model/service/oci_datascience_model.py +1 -1
- ads/opctl/operator/lowcode/anomaly/model/anomaly_dataset.py +8 -6
- ads/opctl/operator/lowcode/anomaly/model/base_model.py +1 -1
- ads/opctl/operator/lowcode/anomaly/operator_config.py +5 -3
- ads/opctl/operator/lowcode/common/transformations.py +2 -0
- ads/opctl/operator/lowcode/forecast/model/automlx.py +29 -0
- ads/type_discovery/typed_feature.py +32 -34
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.8.dist-info}/METADATA +1 -1
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.8.dist-info}/RECORD +36 -37
- ads/aqua/config/config.py +0 -31
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.8.dist-info}/WHEEL +0 -0
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.8.dist-info}/entry_points.txt +0 -0
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.8.dist-info}/licenses/LICENSE.txt +0 -0
@@ -16,16 +16,14 @@ from ads.aqua.common.entities import (
|
|
16
16
|
AquaMultiModelRef,
|
17
17
|
ComputeShapeSummary,
|
18
18
|
ContainerPath,
|
19
|
-
ContainerSpec,
|
20
19
|
)
|
21
20
|
from ads.aqua.common.enums import InferenceContainerTypeFamily, ModelFormat, Tags
|
22
21
|
from ads.aqua.common.errors import AquaRuntimeError, AquaValueError
|
23
22
|
from ads.aqua.common.utils import (
|
23
|
+
DEFINED_METADATA_TO_FILE_MAP,
|
24
24
|
build_params_string,
|
25
25
|
build_pydantic_error_message,
|
26
26
|
get_combined_params,
|
27
|
-
get_container_config,
|
28
|
-
get_container_image,
|
29
27
|
get_container_params_type,
|
30
28
|
get_model_by_reference_paths,
|
31
29
|
get_ocid_substring,
|
@@ -50,7 +48,7 @@ from ads.aqua.constants import (
|
|
50
48
|
from ads.aqua.data import AquaResourceIdentifier
|
51
49
|
from ads.aqua.finetuning.finetuning import FineTuneCustomMetadata
|
52
50
|
from ads.aqua.model import AquaModelApp
|
53
|
-
from ads.aqua.model.constants import ModelCustomMetadataFields
|
51
|
+
from ads.aqua.model.constants import AquaModelMetadataKeys, ModelCustomMetadataFields
|
54
52
|
from ads.aqua.modeldeployment.entities import (
|
55
53
|
AquaDeployment,
|
56
54
|
AquaDeploymentConfig,
|
@@ -67,7 +65,6 @@ from ads.config import (
|
|
67
65
|
AQUA_DEPLOYMENT_CONTAINER_CMD_VAR_METADATA_NAME,
|
68
66
|
AQUA_DEPLOYMENT_CONTAINER_METADATA_NAME,
|
69
67
|
AQUA_DEPLOYMENT_CONTAINER_URI_METADATA_NAME,
|
70
|
-
AQUA_MODEL_DEPLOYMENT_CONFIG,
|
71
68
|
COMPARTMENT_OCID,
|
72
69
|
PROJECT_OCID,
|
73
70
|
)
|
@@ -182,7 +179,7 @@ class AquaDeploymentApp(AquaApp):
|
|
182
179
|
available_shapes = [
|
183
180
|
shape.name.lower()
|
184
181
|
for shape in self.list_shapes(
|
185
|
-
compartment_id=
|
182
|
+
compartment_id=compartment_id
|
186
183
|
)
|
187
184
|
]
|
188
185
|
|
@@ -193,7 +190,7 @@ class AquaDeploymentApp(AquaApp):
|
|
193
190
|
)
|
194
191
|
|
195
192
|
# Get container config
|
196
|
-
container_config = get_container_config()
|
193
|
+
container_config = self.get_container_config()
|
197
194
|
|
198
195
|
# Create an AquaModelApp instance once to perform the deployment creation.
|
199
196
|
model_app = AquaModelApp()
|
@@ -228,17 +225,13 @@ class AquaDeploymentApp(AquaApp):
|
|
228
225
|
except ConfigValidationError as err:
|
229
226
|
raise AquaValueError(f"{err}") from err
|
230
227
|
|
231
|
-
service_inference_containers = (
|
232
|
-
AquaContainerConfig.from_container_index_json(
|
233
|
-
config=container_config
|
234
|
-
).inference.values()
|
235
|
-
)
|
228
|
+
service_inference_containers = container_config.inference.values()
|
236
229
|
|
237
230
|
supported_container_families = [
|
238
231
|
container_config_item.family
|
239
232
|
for container_config_item in service_inference_containers
|
240
233
|
if any(
|
241
|
-
usage in container_config_item.usages
|
234
|
+
usage.upper() in container_config_item.usages
|
242
235
|
for usage in [Usage.MULTI_MODEL, Usage.OTHER]
|
243
236
|
)
|
244
237
|
]
|
@@ -409,7 +402,7 @@ class AquaDeploymentApp(AquaApp):
|
|
409
402
|
|
410
403
|
container_image_uri = (
|
411
404
|
create_deployment_details.container_image_uri
|
412
|
-
or get_container_image(container_type=container_type_key)
|
405
|
+
or self.get_container_image(container_type=container_type_key)
|
413
406
|
)
|
414
407
|
if not container_image_uri:
|
415
408
|
try:
|
@@ -475,22 +468,21 @@ class AquaDeploymentApp(AquaApp):
|
|
475
468
|
env_var.update({"BASE_MODEL_FILE": f"{model_file}"})
|
476
469
|
tags.update({Tags.MODEL_ARTIFACT_FILE: model_file})
|
477
470
|
|
478
|
-
# todo: use AquaContainerConfig.from_container_index_json instead.
|
479
471
|
# Fetch the startup cli command for the container
|
480
472
|
# container_index.json will have "containerSpec" section which will provide the cli params for
|
481
473
|
# a given container family
|
482
|
-
|
483
|
-
|
484
|
-
|
474
|
+
container_config = self.get_container_config_item(container_type_key)
|
475
|
+
|
476
|
+
container_spec = container_config.spec if container_config else UNKNOWN
|
485
477
|
# these params cannot be overridden for Aqua deployments
|
486
|
-
params = container_spec.
|
487
|
-
server_port = create_deployment_details.server_port or
|
488
|
-
|
489
|
-
)
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
)
|
478
|
+
params = container_spec.cli_param if container_spec else UNKNOWN
|
479
|
+
server_port = create_deployment_details.server_port or (
|
480
|
+
container_spec.server_port if container_spec else None
|
481
|
+
)
|
482
|
+
# Give precendece to the input parameter
|
483
|
+
health_check_port = create_deployment_details.health_check_port or (
|
484
|
+
container_spec.health_check_port if container_spec else None
|
485
|
+
)
|
494
486
|
|
495
487
|
deployment_config = self.get_deployment_config(model_id=config_source_id)
|
496
488
|
|
@@ -527,9 +519,10 @@ class AquaDeploymentApp(AquaApp):
|
|
527
519
|
params = f"{params} {deployment_params}".strip()
|
528
520
|
if params:
|
529
521
|
env_var.update({"PARAMS": params})
|
530
|
-
|
531
|
-
for env in
|
522
|
+
env_vars = container_spec.env_vars if container_spec else []
|
523
|
+
for env in env_vars:
|
532
524
|
if isinstance(env, dict):
|
525
|
+
env = {k: v for k, v in env.items() if v}
|
533
526
|
for key, _ in env.items():
|
534
527
|
if key not in env_var:
|
535
528
|
env_var.update(env)
|
@@ -559,7 +552,7 @@ class AquaDeploymentApp(AquaApp):
|
|
559
552
|
aqua_model: DataScienceModel,
|
560
553
|
model_config_summary: ModelDeploymentConfigSummary,
|
561
554
|
create_deployment_details: CreateModelDeploymentDetails,
|
562
|
-
container_config:
|
555
|
+
container_config: AquaContainerConfig,
|
563
556
|
) -> AquaDeployment:
|
564
557
|
"""Builds the environment variables required by multi deployment container and creates the deployment.
|
565
558
|
|
@@ -587,11 +580,10 @@ class AquaDeploymentApp(AquaApp):
|
|
587
580
|
model=aqua_model,
|
588
581
|
container_family=create_deployment_details.container_family,
|
589
582
|
)
|
590
|
-
|
591
|
-
|
592
|
-
).get(container_type_key, UNKNOWN_DICT)
|
583
|
+
container_config = self.get_container_config_item(container_type_key)
|
584
|
+
container_spec = container_config.spec if container_config else UNKNOWN
|
593
585
|
|
594
|
-
container_params = container_spec.
|
586
|
+
container_params = container_spec.cli_param if container_spec else UNKNOWN
|
595
587
|
|
596
588
|
for model in create_deployment_details.models:
|
597
589
|
user_params = build_params_string(model.env_var)
|
@@ -658,8 +650,10 @@ class AquaDeploymentApp(AquaApp):
|
|
658
650
|
|
659
651
|
env_var.update({AQUA_MULTI_MODEL_CONFIG: json.dumps({"models": model_config})})
|
660
652
|
|
661
|
-
|
653
|
+
env_vars = container_spec.env_vars if container_spec else []
|
654
|
+
for env in env_vars:
|
662
655
|
if isinstance(env, dict):
|
656
|
+
env = {k: v for k, v in env.items() if v}
|
663
657
|
for key, _ in env.items():
|
664
658
|
if key not in env_var:
|
665
659
|
env_var.update(env)
|
@@ -668,14 +662,13 @@ class AquaDeploymentApp(AquaApp):
|
|
668
662
|
|
669
663
|
container_image_uri = (
|
670
664
|
create_deployment_details.container_image_uri
|
671
|
-
or get_container_image(container_type=container_type_key)
|
665
|
+
or self.get_container_image(container_type=container_type_key)
|
672
666
|
)
|
673
|
-
server_port = create_deployment_details.server_port or
|
674
|
-
|
667
|
+
server_port = create_deployment_details.server_port or (
|
668
|
+
container_spec.server_port if container_spec else None
|
675
669
|
)
|
676
|
-
health_check_port = (
|
677
|
-
|
678
|
-
or container_spec.get(ContainerSpec.HEALTH_CHECK_PORT)
|
670
|
+
health_check_port = create_deployment_details.health_check_port or (
|
671
|
+
container_spec.health_check_port if container_spec else None
|
679
672
|
)
|
680
673
|
tags = {
|
681
674
|
Tags.AQUA_MODEL_ID_TAG: aqua_model.id,
|
@@ -1054,7 +1047,20 @@ class AquaDeploymentApp(AquaApp):
|
|
1054
1047
|
AquaDeploymentConfig:
|
1055
1048
|
An instance of AquaDeploymentConfig.
|
1056
1049
|
"""
|
1057
|
-
config = self.
|
1050
|
+
config = self.get_config_from_metadata(
|
1051
|
+
model_id, AquaModelMetadataKeys.DEPLOYMENT_CONFIGURATION
|
1052
|
+
).config
|
1053
|
+
if config:
|
1054
|
+
logger.info(
|
1055
|
+
f"Fetched {AquaModelMetadataKeys.DEPLOYMENT_CONFIGURATION} from defined metadata for model: {model_id}."
|
1056
|
+
)
|
1057
|
+
return AquaDeploymentConfig(**(config or UNKNOWN_DICT))
|
1058
|
+
config = self.get_config(
|
1059
|
+
model_id,
|
1060
|
+
DEFINED_METADATA_TO_FILE_MAP.get(
|
1061
|
+
AquaModelMetadataKeys.DEPLOYMENT_CONFIGURATION.lower()
|
1062
|
+
),
|
1063
|
+
).config
|
1058
1064
|
if not config:
|
1059
1065
|
logger.debug(
|
1060
1066
|
f"Deployment config for custom model: {model_id} is not available. Use defaults."
|
@@ -1079,7 +1085,7 @@ class AquaDeploymentApp(AquaApp):
|
|
1079
1085
|
https://github.com/oracle-samples/oci-data-science-ai-samples/blob/main/ai-quick-actions/multimodel-deployment-tips.md#get_multimodel_deployment_config
|
1080
1086
|
|
1081
1087
|
CLI example:
|
1082
|
-
ads aqua deployment get_multimodel_deployment_config --model_ids '["
|
1088
|
+
ads aqua deployment get_multimodel_deployment_config --model_ids '["md_ocid1","md_ocid2"]'
|
1083
1089
|
|
1084
1090
|
If a primary model ID is provided, GPU allocation will prioritize that model
|
1085
1091
|
when selecting compatible shapes.
|
@@ -1230,11 +1236,9 @@ class AquaDeploymentApp(AquaApp):
|
|
1230
1236
|
model=model, container_family=container_family
|
1231
1237
|
)
|
1232
1238
|
|
1233
|
-
container_config =
|
1234
|
-
container_spec = container_config.
|
1235
|
-
|
1236
|
-
)
|
1237
|
-
cli_params = container_spec.get(ContainerSpec.CLI_PARM, "")
|
1239
|
+
container_config = self.get_container_config_item(container_type_key)
|
1240
|
+
container_spec = container_config.spec if container_config else UNKNOWN
|
1241
|
+
cli_params = container_spec.cli_param if container_spec else UNKNOWN
|
1238
1242
|
|
1239
1243
|
restricted_params = self._find_restricted_params(
|
1240
1244
|
cli_params, params, container_type_key
|
@@ -11,7 +11,8 @@ from concurrent.futures import ThreadPoolExecutor
|
|
11
11
|
from typing import Dict, List, Optional
|
12
12
|
|
13
13
|
from ads.aqua.app import AquaApp
|
14
|
-
from ads.aqua.common.entities import ComputeShapeSummary
|
14
|
+
from ads.aqua.common.entities import ComputeShapeSummary, ModelConfigResult
|
15
|
+
from ads.aqua.model.constants import AquaModelMetadataKeys
|
15
16
|
from ads.aqua.modeldeployment.entities import (
|
16
17
|
AquaDeploymentConfig,
|
17
18
|
ConfigurationItem,
|
@@ -183,17 +184,34 @@ class MultiModelDeploymentConfigLoader:
|
|
183
184
|
"""Fetches deployment configurations in parallel using ThreadPoolExecutor."""
|
184
185
|
with ThreadPoolExecutor(max_workers=self.MAX_WORKERS) as executor:
|
185
186
|
results = executor.map(
|
186
|
-
|
187
|
-
model_id, AQUA_MODEL_DEPLOYMENT_CONFIG
|
188
|
-
).config,
|
187
|
+
self._fetch_deployment_config_from_metadata_and_oss,
|
189
188
|
model_ids,
|
190
189
|
)
|
191
190
|
|
192
191
|
return {
|
193
|
-
model_id: AquaDeploymentConfig(**config)
|
192
|
+
model_id: AquaDeploymentConfig(**config.config)
|
194
193
|
for model_id, config in zip(model_ids, results)
|
195
194
|
}
|
196
195
|
|
196
|
+
def _fetch_deployment_config_from_metadata_and_oss(
|
197
|
+
self, model_id
|
198
|
+
) -> ModelConfigResult:
|
199
|
+
config = self.deployment_app.get_config_from_metadata(
|
200
|
+
model_id, AquaModelMetadataKeys.DEPLOYMENT_CONFIGURATION
|
201
|
+
)
|
202
|
+
if config:
|
203
|
+
logger.info(
|
204
|
+
f"Fetched metadata key '{AquaModelMetadataKeys.DEPLOYMENT_CONFIGURATION}' from defined metadata for model '{model_id}'"
|
205
|
+
)
|
206
|
+
return config
|
207
|
+
else:
|
208
|
+
logger.info(
|
209
|
+
f"Fetching '{AquaModelMetadataKeys.DEPLOYMENT_CONFIGURATION}' from object storage bucket for {model_id}'"
|
210
|
+
)
|
211
|
+
return self.deployment_app.get_config(
|
212
|
+
model_id, AQUA_MODEL_DEPLOYMENT_CONFIG
|
213
|
+
)
|
214
|
+
|
197
215
|
def _extract_model_shape_gpu(
|
198
216
|
self,
|
199
217
|
deployment_configs: Dict[str, AquaDeploymentConfig],
|
ads/aqua/ui.py
CHANGED
@@ -13,7 +13,7 @@ from ads.aqua import logger
|
|
13
13
|
from ads.aqua.app import AquaApp
|
14
14
|
from ads.aqua.common.enums import Tags
|
15
15
|
from ads.aqua.common.errors import AquaResourceAccessError, AquaValueError
|
16
|
-
from ads.aqua.common.utils import
|
16
|
+
from ads.aqua.common.utils import sanitize_response
|
17
17
|
from ads.aqua.config.container_config import AquaContainerConfig
|
18
18
|
from ads.aqua.constants import PRIVATE_ENDPOINT_TYPE
|
19
19
|
from ads.common import oci_client as oc
|
@@ -494,7 +494,6 @@ class AquaUIApp(AquaApp):
|
|
494
494
|
AquaContainerConfig
|
495
495
|
The AQUA containers configurations.
|
496
496
|
"""
|
497
|
-
return AquaContainerConfig.
|
498
|
-
|
499
|
-
enable_spec=True,
|
497
|
+
return AquaContainerConfig.from_service_config(
|
498
|
+
service_containers=self.list_service_containers()
|
500
499
|
)
|
ads/config.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
2
|
|
3
|
-
# Copyright (c) 2020,
|
3
|
+
# Copyright (c) 2020, 2025 Oracle and/or its affiliates.
|
4
4
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
5
5
|
|
6
6
|
import contextlib
|
@@ -56,6 +56,7 @@ AQUA_MODEL_FINETUNING_CONFIG = os.environ.get(
|
|
56
56
|
AQUA_CONTAINER_INDEX_CONFIG = os.environ.get(
|
57
57
|
"AQUA_CONTAINER_INDEX_CONFIG", "container_index.json"
|
58
58
|
)
|
59
|
+
AQUA_SERVICE_MODELS = "aqua-service-models-compartment"
|
59
60
|
AQUA_DEPLOYMENT_CONTAINER_METADATA_NAME = "deployment-container"
|
60
61
|
AQUA_FINETUNING_CONTAINER_METADATA_NAME = "finetune-container"
|
61
62
|
AQUA_EVALUATION_CONTAINER_METADATA_NAME = "evaluation-container"
|
@@ -84,7 +85,6 @@ USER = "USER"
|
|
84
85
|
SERVICE = "SERVICE"
|
85
86
|
|
86
87
|
|
87
|
-
|
88
88
|
THREADED_DEFAULT_TIMEOUT = 5
|
89
89
|
try:
|
90
90
|
THREADED_DEFAULT_TIMEOUT = int(
|
ads/model/datascience_model.py
CHANGED
@@ -2240,6 +2240,35 @@ class DataScienceModel(Builder):
|
|
2240
2240
|
# model found case
|
2241
2241
|
self.model_file_description["models"].pop(modelSearchIdx)
|
2242
2242
|
|
2243
|
+
def if_model_custom_metadata_artifact_exist(
|
2244
|
+
self, metadata_key_name: str, **kwargs
|
2245
|
+
) -> bool:
|
2246
|
+
"""Checks if the custom metadata artifact exists for the model.
|
2247
|
+
|
2248
|
+
Parameters
|
2249
|
+
----------
|
2250
|
+
metadata_key_name: str
|
2251
|
+
Custom metadata key name
|
2252
|
+
**kwargs :
|
2253
|
+
Additional keyword arguments passed in head_model_artifact.
|
2254
|
+
|
2255
|
+
Returns
|
2256
|
+
-------
|
2257
|
+
bool
|
2258
|
+
Whether the artifact exists.
|
2259
|
+
"""
|
2260
|
+
|
2261
|
+
try:
|
2262
|
+
response = self.dsc_model.head_custom_metadata_artifact(
|
2263
|
+
metadata_key_name=metadata_key_name, **kwargs
|
2264
|
+
)
|
2265
|
+
return int(response.status) == 200
|
2266
|
+
except Exception as ex:
|
2267
|
+
logger.info(
|
2268
|
+
f"Error fetching custom metadata: {metadata_key_name} for model {self.id}. {ex}"
|
2269
|
+
)
|
2270
|
+
return False
|
2271
|
+
|
2243
2272
|
def create_custom_metadata_artifact(
|
2244
2273
|
self,
|
2245
2274
|
metadata_key_name: str,
|
@@ -110,7 +110,7 @@ def check_for_model_id(msg: str = MODEL_NEEDS_TO_BE_SAVED):
|
|
110
110
|
def convert_model_metadata_response(
|
111
111
|
headers: Union[Dict, CaseInsensitiveDict], status: int
|
112
112
|
) -> ModelMetadataArtifactDetails:
|
113
|
-
return ModelMetadataArtifactDetails(headers=headers, status=str(status))
|
113
|
+
return ModelMetadataArtifactDetails(headers=dict(headers), status=str(status))
|
114
114
|
|
115
115
|
|
116
116
|
class OCIDataScienceModel(
|
@@ -4,16 +4,18 @@
|
|
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
|
-
|
7
|
+
import pandas as pd
|
8
|
+
|
9
|
+
from ads.opctl import logger
|
10
|
+
from ads.opctl.operator.lowcode.anomaly.const import OutputColumns
|
11
|
+
from ads.opctl.operator.lowcode.anomaly.utils import get_frequency_of_datetime
|
12
|
+
from ads.opctl.operator.lowcode.common.data import AbstractData
|
8
13
|
from ads.opctl.operator.lowcode.common.utils import (
|
9
14
|
default_signer,
|
10
15
|
merge_category_columns,
|
11
16
|
)
|
12
|
-
|
13
|
-
from
|
14
|
-
from ads.opctl import logger
|
15
|
-
import pandas as pd
|
16
|
-
from ads.opctl.operator.lowcode.anomaly.const import OutputColumns
|
17
|
+
|
18
|
+
from ..operator_config import AnomalyOperatorSpec
|
17
19
|
|
18
20
|
|
19
21
|
class AnomalyData(AbstractData):
|
@@ -53,6 +53,7 @@ class AnomalyOperatorBaseModel(ABC):
|
|
53
53
|
self.config: AnomalyOperatorConfig = config
|
54
54
|
self.spec: AnomalyOperatorSpec = config.spec
|
55
55
|
self.datasets = datasets
|
56
|
+
|
56
57
|
if self.spec.validation_data is not None:
|
57
58
|
self.X_valid_dict = self.datasets.valid_data.X_valid_dict
|
58
59
|
self.y_valid_dict = self.datasets.valid_data.y_valid_dict
|
@@ -74,7 +75,6 @@ class AnomalyOperatorBaseModel(ABC):
|
|
74
75
|
logger.warning(f"Found exception: {e}")
|
75
76
|
if self.spec.datetime_column:
|
76
77
|
anomaly_output = self._fallback_build_model()
|
77
|
-
raise e
|
78
78
|
|
79
79
|
elapsed_time = time.time() - start_time
|
80
80
|
|
@@ -9,15 +9,16 @@ from dataclasses import dataclass, field
|
|
9
9
|
from typing import Dict, List
|
10
10
|
|
11
11
|
from ads.common.serializer import DataClassSerializable
|
12
|
-
from ads.opctl.operator.common.utils import _load_yaml_from_uri
|
13
12
|
from ads.opctl.operator.common.operator_config import (
|
13
|
+
InputData,
|
14
14
|
OperatorConfig,
|
15
15
|
OutputDirectory,
|
16
|
-
InputData,
|
17
16
|
)
|
18
|
-
from .
|
17
|
+
from ads.opctl.operator.common.utils import _load_yaml_from_uri
|
19
18
|
from ads.opctl.operator.lowcode.common.utils import find_output_dirname
|
20
19
|
|
20
|
+
from .const import SupportedModels
|
21
|
+
|
21
22
|
|
22
23
|
@dataclass(repr=True)
|
23
24
|
class ValidationData(InputData):
|
@@ -61,6 +62,7 @@ class AnomalyOperatorSpec(DataClassSerializable):
|
|
61
62
|
test_data: TestData = field(default_factory=TestData)
|
62
63
|
validation_data: ValidationData = field(default_factory=ValidationData)
|
63
64
|
output_directory: OutputDirectory = field(default_factory=OutputDirectory)
|
65
|
+
preprocessing: DataPreprocessor = field(default_factory=DataPreprocessor)
|
64
66
|
report_file_name: str = None
|
65
67
|
report_title: str = None
|
66
68
|
report_theme: str = None
|
@@ -91,6 +91,8 @@ class Transformations(ABC):
|
|
91
91
|
logger.info("Skipping outlier treatment because it is disabled")
|
92
92
|
elif self.name == "additional_data":
|
93
93
|
clean_df = self._missing_value_imputation_add(clean_df)
|
94
|
+
elif self.name == "input_data" and self.preprocessing.steps.missing_value_imputation:
|
95
|
+
clean_df = self._fill_na(clean_df)
|
94
96
|
else:
|
95
97
|
logger.info(
|
96
98
|
"Skipping all preprocessing steps because preprocessing is disabled"
|
@@ -159,6 +159,7 @@ class AutoMLXOperatorModel(ForecastOperatorBaseModel):
|
|
159
159
|
self.models[s_id] = {}
|
160
160
|
self.models[s_id]["model"] = model
|
161
161
|
self.models[s_id]["le"] = self.le[s_id]
|
162
|
+
self.models[s_id]["score"] = self.get_validation_score_and_metric(model)
|
162
163
|
|
163
164
|
# In case of Naive model, model.forecast function call does not return confidence intervals.
|
164
165
|
if f"{target}_ci_upper" not in summary_frame:
|
@@ -511,3 +512,31 @@ class AutoMLXOperatorModel(ForecastOperatorBaseModel):
|
|
511
512
|
f"Failed to generate explanations for series {s_id} with error: {e}."
|
512
513
|
)
|
513
514
|
logger.debug(f"Full Traceback: {traceback.format_exc()}")
|
515
|
+
|
516
|
+
def get_validation_score_and_metric(self, model):
|
517
|
+
trials = model.completed_trials_summary_
|
518
|
+
model_params = model.selected_model_params_
|
519
|
+
if len(trials) > 0:
|
520
|
+
score_col = [col for col in trials.columns if "Score" in col][0]
|
521
|
+
validation_score = trials[trials.Hyperparameters == model_params][score_col].iloc[0]
|
522
|
+
else:
|
523
|
+
validation_score = 0
|
524
|
+
return -1 * validation_score
|
525
|
+
|
526
|
+
def generate_train_metrics(self) -> pd.DataFrame:
|
527
|
+
"""
|
528
|
+
Generate Training Metrics when fitted data is not available.
|
529
|
+
"""
|
530
|
+
total_metrics = pd.DataFrame()
|
531
|
+
for s_id in self.forecast_output.list_series_ids():
|
532
|
+
try:
|
533
|
+
metrics = {self.spec.metric.upper(): self.models[s_id]["score"]}
|
534
|
+
metrics_df = pd.DataFrame.from_dict(metrics, orient="index", columns=[s_id])
|
535
|
+
logger.warning("AutoMLX failed to generate training metrics. Recovering validation loss instead")
|
536
|
+
total_metrics = pd.concat([total_metrics, metrics_df], axis=1)
|
537
|
+
except Exception as e:
|
538
|
+
logger.debug(
|
539
|
+
f"Failed to generate training metrics for target_series: {s_id}"
|
540
|
+
)
|
541
|
+
logger.debug(f"Error: {e}")
|
542
|
+
return total_metrics
|