oracle-ads 2.13.9rc0__py3-none-any.whl → 2.13.10rc0__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 +40 -0
- ads/aqua/app.py +507 -0
- ads/aqua/cli.py +96 -0
- ads/aqua/client/__init__.py +3 -0
- ads/aqua/client/client.py +836 -0
- ads/aqua/client/openai_client.py +305 -0
- ads/aqua/common/__init__.py +5 -0
- ads/aqua/common/decorator.py +125 -0
- ads/aqua/common/entities.py +274 -0
- ads/aqua/common/enums.py +134 -0
- ads/aqua/common/errors.py +109 -0
- ads/aqua/common/utils.py +1295 -0
- ads/aqua/config/__init__.py +4 -0
- ads/aqua/config/container_config.py +247 -0
- ads/aqua/config/evaluation/__init__.py +4 -0
- ads/aqua/config/evaluation/evaluation_service_config.py +147 -0
- ads/aqua/config/utils/__init__.py +4 -0
- ads/aqua/config/utils/serializer.py +339 -0
- ads/aqua/constants.py +116 -0
- ads/aqua/data.py +14 -0
- ads/aqua/dummy_data/icon.txt +1 -0
- ads/aqua/dummy_data/oci_model_deployments.json +56 -0
- ads/aqua/dummy_data/oci_models.json +1 -0
- ads/aqua/dummy_data/readme.md +26 -0
- ads/aqua/evaluation/__init__.py +8 -0
- ads/aqua/evaluation/constants.py +53 -0
- ads/aqua/evaluation/entities.py +186 -0
- ads/aqua/evaluation/errors.py +70 -0
- ads/aqua/evaluation/evaluation.py +1814 -0
- ads/aqua/extension/__init__.py +42 -0
- ads/aqua/extension/aqua_ws_msg_handler.py +76 -0
- ads/aqua/extension/base_handler.py +90 -0
- ads/aqua/extension/common_handler.py +121 -0
- ads/aqua/extension/common_ws_msg_handler.py +36 -0
- ads/aqua/extension/deployment_handler.py +381 -0
- ads/aqua/extension/deployment_ws_msg_handler.py +54 -0
- ads/aqua/extension/errors.py +30 -0
- ads/aqua/extension/evaluation_handler.py +129 -0
- ads/aqua/extension/evaluation_ws_msg_handler.py +61 -0
- ads/aqua/extension/finetune_handler.py +96 -0
- ads/aqua/extension/model_handler.py +390 -0
- ads/aqua/extension/models/__init__.py +0 -0
- ads/aqua/extension/models/ws_models.py +145 -0
- ads/aqua/extension/models_ws_msg_handler.py +50 -0
- ads/aqua/extension/ui_handler.py +300 -0
- ads/aqua/extension/ui_websocket_handler.py +130 -0
- ads/aqua/extension/utils.py +133 -0
- ads/aqua/finetuning/__init__.py +7 -0
- ads/aqua/finetuning/constants.py +23 -0
- ads/aqua/finetuning/entities.py +181 -0
- ads/aqua/finetuning/finetuning.py +749 -0
- ads/aqua/model/__init__.py +8 -0
- ads/aqua/model/constants.py +60 -0
- ads/aqua/model/entities.py +385 -0
- ads/aqua/model/enums.py +32 -0
- ads/aqua/model/model.py +2134 -0
- ads/aqua/model/utils.py +52 -0
- ads/aqua/modeldeployment/__init__.py +6 -0
- ads/aqua/modeldeployment/constants.py +10 -0
- ads/aqua/modeldeployment/deployment.py +1315 -0
- ads/aqua/modeldeployment/entities.py +653 -0
- ads/aqua/modeldeployment/utils.py +543 -0
- ads/aqua/resources/gpu_shapes_index.json +94 -0
- ads/aqua/server/__init__.py +4 -0
- ads/aqua/server/__main__.py +24 -0
- ads/aqua/server/app.py +47 -0
- ads/aqua/server/aqua_spec.yml +1291 -0
- ads/aqua/training/__init__.py +4 -0
- ads/aqua/training/exceptions.py +476 -0
- ads/aqua/ui.py +519 -0
- ads/automl/__init__.py +9 -0
- ads/automl/driver.py +330 -0
- ads/automl/provider.py +975 -0
- ads/bds/__init__.py +5 -0
- ads/bds/auth.py +127 -0
- ads/bds/big_data_service.py +255 -0
- ads/catalog/__init__.py +19 -0
- ads/catalog/model.py +1576 -0
- ads/catalog/notebook.py +461 -0
- ads/catalog/project.py +468 -0
- ads/catalog/summary.py +178 -0
- ads/common/__init__.py +11 -0
- ads/common/analyzer.py +65 -0
- ads/common/artifact/.model-ignore +63 -0
- ads/common/artifact/__init__.py +10 -0
- ads/common/auth.py +1122 -0
- ads/common/card_identifier.py +83 -0
- ads/common/config.py +647 -0
- ads/common/data.py +165 -0
- ads/common/decorator/__init__.py +9 -0
- ads/common/decorator/argument_to_case.py +88 -0
- ads/common/decorator/deprecate.py +69 -0
- ads/common/decorator/require_nonempty_arg.py +65 -0
- ads/common/decorator/runtime_dependency.py +178 -0
- ads/common/decorator/threaded.py +97 -0
- ads/common/decorator/utils.py +35 -0
- ads/common/dsc_file_system.py +303 -0
- ads/common/error.py +14 -0
- ads/common/extended_enum.py +81 -0
- ads/common/function/__init__.py +5 -0
- ads/common/function/fn_util.py +142 -0
- ads/common/function/func_conf.yaml +25 -0
- ads/common/ipython.py +76 -0
- ads/common/model.py +679 -0
- ads/common/model_artifact.py +1759 -0
- ads/common/model_artifact_schema.json +107 -0
- ads/common/model_export_util.py +664 -0
- ads/common/model_metadata.py +24 -0
- ads/common/object_storage_details.py +296 -0
- ads/common/oci_client.py +179 -0
- ads/common/oci_datascience.py +46 -0
- ads/common/oci_logging.py +1144 -0
- ads/common/oci_mixin.py +957 -0
- ads/common/oci_resource.py +136 -0
- ads/common/serializer.py +559 -0
- ads/common/utils.py +1852 -0
- ads/common/word_lists.py +1491 -0
- ads/common/work_request.py +189 -0
- ads/config.py +1 -0
- ads/data_labeling/__init__.py +13 -0
- ads/data_labeling/boundingbox.py +253 -0
- ads/data_labeling/constants.py +47 -0
- ads/data_labeling/data_labeling_service.py +244 -0
- ads/data_labeling/interface/__init__.py +5 -0
- ads/data_labeling/interface/loader.py +16 -0
- ads/data_labeling/interface/parser.py +16 -0
- ads/data_labeling/interface/reader.py +23 -0
- ads/data_labeling/loader/__init__.py +5 -0
- ads/data_labeling/loader/file_loader.py +241 -0
- ads/data_labeling/metadata.py +110 -0
- ads/data_labeling/mixin/__init__.py +5 -0
- ads/data_labeling/mixin/data_labeling.py +232 -0
- ads/data_labeling/ner.py +129 -0
- ads/data_labeling/parser/__init__.py +5 -0
- ads/data_labeling/parser/dls_record_parser.py +388 -0
- ads/data_labeling/parser/export_metadata_parser.py +94 -0
- ads/data_labeling/parser/export_record_parser.py +473 -0
- ads/data_labeling/reader/__init__.py +5 -0
- ads/data_labeling/reader/dataset_reader.py +574 -0
- ads/data_labeling/reader/dls_record_reader.py +121 -0
- ads/data_labeling/reader/export_record_reader.py +62 -0
- ads/data_labeling/reader/jsonl_reader.py +75 -0
- ads/data_labeling/reader/metadata_reader.py +203 -0
- ads/data_labeling/reader/record_reader.py +263 -0
- ads/data_labeling/record.py +52 -0
- ads/data_labeling/visualizer/__init__.py +5 -0
- ads/data_labeling/visualizer/image_visualizer.py +525 -0
- ads/data_labeling/visualizer/text_visualizer.py +357 -0
- ads/database/__init__.py +5 -0
- ads/database/connection.py +338 -0
- ads/dataset/__init__.py +10 -0
- ads/dataset/capabilities.md +51 -0
- ads/dataset/classification_dataset.py +339 -0
- ads/dataset/correlation.py +226 -0
- ads/dataset/correlation_plot.py +563 -0
- ads/dataset/dask_series.py +173 -0
- ads/dataset/dataframe_transformer.py +110 -0
- ads/dataset/dataset.py +1979 -0
- ads/dataset/dataset_browser.py +360 -0
- ads/dataset/dataset_with_target.py +995 -0
- ads/dataset/exception.py +25 -0
- ads/dataset/factory.py +987 -0
- ads/dataset/feature_engineering_transformer.py +35 -0
- ads/dataset/feature_selection.py +107 -0
- ads/dataset/forecasting_dataset.py +26 -0
- ads/dataset/helper.py +1450 -0
- ads/dataset/label_encoder.py +99 -0
- ads/dataset/mixin/__init__.py +5 -0
- ads/dataset/mixin/dataset_accessor.py +134 -0
- ads/dataset/pipeline.py +58 -0
- ads/dataset/plot.py +710 -0
- ads/dataset/progress.py +86 -0
- ads/dataset/recommendation.py +297 -0
- ads/dataset/recommendation_transformer.py +502 -0
- ads/dataset/regression_dataset.py +14 -0
- ads/dataset/sampled_dataset.py +1050 -0
- ads/dataset/target.py +98 -0
- ads/dataset/timeseries.py +18 -0
- ads/dbmixin/__init__.py +5 -0
- ads/dbmixin/db_pandas_accessor.py +153 -0
- ads/environment/__init__.py +9 -0
- ads/environment/ml_runtime.py +66 -0
- ads/evaluations/README.md +14 -0
- ads/evaluations/__init__.py +109 -0
- ads/evaluations/evaluation_plot.py +983 -0
- ads/evaluations/evaluator.py +1334 -0
- ads/evaluations/statistical_metrics.py +543 -0
- ads/experiments/__init__.py +9 -0
- ads/experiments/capabilities.md +0 -0
- ads/explanations/__init__.py +21 -0
- ads/explanations/base_explainer.py +142 -0
- ads/explanations/capabilities.md +83 -0
- ads/explanations/explainer.py +190 -0
- ads/explanations/mlx_global_explainer.py +1050 -0
- ads/explanations/mlx_interface.py +386 -0
- ads/explanations/mlx_local_explainer.py +287 -0
- ads/explanations/mlx_whatif_explainer.py +201 -0
- ads/feature_engineering/__init__.py +20 -0
- ads/feature_engineering/accessor/__init__.py +5 -0
- ads/feature_engineering/accessor/dataframe_accessor.py +535 -0
- ads/feature_engineering/accessor/mixin/__init__.py +5 -0
- ads/feature_engineering/accessor/mixin/correlation.py +166 -0
- ads/feature_engineering/accessor/mixin/eda_mixin.py +266 -0
- ads/feature_engineering/accessor/mixin/eda_mixin_series.py +85 -0
- ads/feature_engineering/accessor/mixin/feature_types_mixin.py +211 -0
- ads/feature_engineering/accessor/mixin/utils.py +65 -0
- ads/feature_engineering/accessor/series_accessor.py +431 -0
- ads/feature_engineering/adsimage/__init__.py +5 -0
- ads/feature_engineering/adsimage/image.py +192 -0
- ads/feature_engineering/adsimage/image_reader.py +170 -0
- ads/feature_engineering/adsimage/interface/__init__.py +5 -0
- ads/feature_engineering/adsimage/interface/reader.py +19 -0
- ads/feature_engineering/adsstring/__init__.py +7 -0
- ads/feature_engineering/adsstring/oci_language/__init__.py +8 -0
- ads/feature_engineering/adsstring/string/__init__.py +8 -0
- ads/feature_engineering/data_schema.json +57 -0
- ads/feature_engineering/dataset/__init__.py +5 -0
- ads/feature_engineering/dataset/zip_code_data.py +42062 -0
- ads/feature_engineering/exceptions.py +40 -0
- ads/feature_engineering/feature_type/__init__.py +133 -0
- ads/feature_engineering/feature_type/address.py +184 -0
- ads/feature_engineering/feature_type/adsstring/__init__.py +5 -0
- ads/feature_engineering/feature_type/adsstring/common_regex_mixin.py +164 -0
- ads/feature_engineering/feature_type/adsstring/oci_language.py +93 -0
- ads/feature_engineering/feature_type/adsstring/parsers/__init__.py +5 -0
- ads/feature_engineering/feature_type/adsstring/parsers/base.py +47 -0
- ads/feature_engineering/feature_type/adsstring/parsers/nltk_parser.py +96 -0
- ads/feature_engineering/feature_type/adsstring/parsers/spacy_parser.py +221 -0
- ads/feature_engineering/feature_type/adsstring/string.py +258 -0
- ads/feature_engineering/feature_type/base.py +58 -0
- ads/feature_engineering/feature_type/boolean.py +183 -0
- ads/feature_engineering/feature_type/category.py +146 -0
- ads/feature_engineering/feature_type/constant.py +137 -0
- ads/feature_engineering/feature_type/continuous.py +151 -0
- ads/feature_engineering/feature_type/creditcard.py +314 -0
- ads/feature_engineering/feature_type/datetime.py +190 -0
- ads/feature_engineering/feature_type/discrete.py +134 -0
- ads/feature_engineering/feature_type/document.py +43 -0
- ads/feature_engineering/feature_type/gis.py +251 -0
- ads/feature_engineering/feature_type/handler/__init__.py +5 -0
- ads/feature_engineering/feature_type/handler/feature_validator.py +524 -0
- ads/feature_engineering/feature_type/handler/feature_warning.py +319 -0
- ads/feature_engineering/feature_type/handler/warnings.py +128 -0
- ads/feature_engineering/feature_type/integer.py +142 -0
- ads/feature_engineering/feature_type/ip_address.py +144 -0
- ads/feature_engineering/feature_type/ip_address_v4.py +138 -0
- ads/feature_engineering/feature_type/ip_address_v6.py +138 -0
- ads/feature_engineering/feature_type/lat_long.py +256 -0
- ads/feature_engineering/feature_type/object.py +43 -0
- ads/feature_engineering/feature_type/ordinal.py +132 -0
- ads/feature_engineering/feature_type/phone_number.py +135 -0
- ads/feature_engineering/feature_type/string.py +171 -0
- ads/feature_engineering/feature_type/text.py +93 -0
- ads/feature_engineering/feature_type/unknown.py +43 -0
- ads/feature_engineering/feature_type/zip_code.py +164 -0
- ads/feature_engineering/feature_type_manager.py +406 -0
- ads/feature_engineering/schema.py +795 -0
- ads/feature_engineering/utils.py +245 -0
- ads/feature_store/.readthedocs.yaml +19 -0
- ads/feature_store/README.md +65 -0
- ads/feature_store/__init__.py +9 -0
- ads/feature_store/common/__init__.py +0 -0
- ads/feature_store/common/enums.py +339 -0
- ads/feature_store/common/exceptions.py +18 -0
- ads/feature_store/common/spark_session_singleton.py +125 -0
- ads/feature_store/common/utils/__init__.py +0 -0
- ads/feature_store/common/utils/base64_encoder_decoder.py +72 -0
- ads/feature_store/common/utils/feature_schema_mapper.py +283 -0
- ads/feature_store/common/utils/transformation_utils.py +82 -0
- ads/feature_store/common/utils/utility.py +403 -0
- ads/feature_store/data_validation/__init__.py +0 -0
- ads/feature_store/data_validation/great_expectation.py +129 -0
- ads/feature_store/dataset.py +1230 -0
- ads/feature_store/dataset_job.py +530 -0
- ads/feature_store/docs/Dockerfile +7 -0
- ads/feature_store/docs/Makefile +44 -0
- ads/feature_store/docs/conf.py +28 -0
- ads/feature_store/docs/requirements.txt +14 -0
- ads/feature_store/docs/source/ads.feature_store.query.rst +20 -0
- ads/feature_store/docs/source/cicd.rst +137 -0
- ads/feature_store/docs/source/conf.py +86 -0
- ads/feature_store/docs/source/data_versioning.rst +33 -0
- ads/feature_store/docs/source/dataset.rst +388 -0
- ads/feature_store/docs/source/dataset_job.rst +27 -0
- ads/feature_store/docs/source/demo.rst +70 -0
- ads/feature_store/docs/source/entity.rst +78 -0
- ads/feature_store/docs/source/feature_group.rst +624 -0
- ads/feature_store/docs/source/feature_group_job.rst +29 -0
- ads/feature_store/docs/source/feature_store.rst +122 -0
- ads/feature_store/docs/source/feature_store_class.rst +123 -0
- ads/feature_store/docs/source/feature_validation.rst +66 -0
- ads/feature_store/docs/source/figures/cicd.png +0 -0
- ads/feature_store/docs/source/figures/data_validation.png +0 -0
- ads/feature_store/docs/source/figures/data_versioning.png +0 -0
- ads/feature_store/docs/source/figures/dataset.gif +0 -0
- ads/feature_store/docs/source/figures/dataset.png +0 -0
- ads/feature_store/docs/source/figures/dataset_lineage.png +0 -0
- ads/feature_store/docs/source/figures/dataset_statistics.png +0 -0
- ads/feature_store/docs/source/figures/dataset_statistics_viz.png +0 -0
- ads/feature_store/docs/source/figures/dataset_validation_results.png +0 -0
- ads/feature_store/docs/source/figures/dataset_validation_summary.png +0 -0
- ads/feature_store/docs/source/figures/drift_monitoring.png +0 -0
- ads/feature_store/docs/source/figures/entity.png +0 -0
- ads/feature_store/docs/source/figures/feature_group.png +0 -0
- ads/feature_store/docs/source/figures/feature_group_lineage.png +0 -0
- ads/feature_store/docs/source/figures/feature_group_statistics_viz.png +0 -0
- ads/feature_store/docs/source/figures/feature_store_deployment.png +0 -0
- ads/feature_store/docs/source/figures/feature_store_overview.png +0 -0
- ads/feature_store/docs/source/figures/featuregroup.gif +0 -0
- ads/feature_store/docs/source/figures/lineage_d1.png +0 -0
- ads/feature_store/docs/source/figures/lineage_d2.png +0 -0
- ads/feature_store/docs/source/figures/lineage_fg.png +0 -0
- ads/feature_store/docs/source/figures/logo-dark-mode.png +0 -0
- ads/feature_store/docs/source/figures/logo-light-mode.png +0 -0
- ads/feature_store/docs/source/figures/overview.png +0 -0
- ads/feature_store/docs/source/figures/resource_manager.png +0 -0
- ads/feature_store/docs/source/figures/resource_manager_feature_store_stack.png +0 -0
- ads/feature_store/docs/source/figures/resource_manager_home.png +0 -0
- ads/feature_store/docs/source/figures/stats_1.png +0 -0
- ads/feature_store/docs/source/figures/stats_2.png +0 -0
- ads/feature_store/docs/source/figures/stats_d.png +0 -0
- ads/feature_store/docs/source/figures/stats_fg.png +0 -0
- ads/feature_store/docs/source/figures/transformation.png +0 -0
- ads/feature_store/docs/source/figures/transformations.gif +0 -0
- ads/feature_store/docs/source/figures/validation.png +0 -0
- ads/feature_store/docs/source/figures/validation_fg.png +0 -0
- ads/feature_store/docs/source/figures/validation_results.png +0 -0
- ads/feature_store/docs/source/figures/validation_summary.png +0 -0
- ads/feature_store/docs/source/index.rst +81 -0
- ads/feature_store/docs/source/module.rst +8 -0
- ads/feature_store/docs/source/notebook.rst +94 -0
- ads/feature_store/docs/source/overview.rst +47 -0
- ads/feature_store/docs/source/quickstart.rst +176 -0
- ads/feature_store/docs/source/release_notes.rst +194 -0
- ads/feature_store/docs/source/setup_feature_store.rst +81 -0
- ads/feature_store/docs/source/statistics.rst +58 -0
- ads/feature_store/docs/source/transformation.rst +199 -0
- ads/feature_store/docs/source/ui.rst +65 -0
- ads/feature_store/docs/source/user_guides.setup.feature_store_operator.rst +66 -0
- ads/feature_store/docs/source/user_guides.setup.helm_chart.rst +192 -0
- ads/feature_store/docs/source/user_guides.setup.terraform.rst +338 -0
- ads/feature_store/entity.py +718 -0
- ads/feature_store/execution_strategy/__init__.py +0 -0
- ads/feature_store/execution_strategy/delta_lake/__init__.py +0 -0
- ads/feature_store/execution_strategy/delta_lake/delta_lake_service.py +375 -0
- ads/feature_store/execution_strategy/engine/__init__.py +0 -0
- ads/feature_store/execution_strategy/engine/spark_engine.py +316 -0
- ads/feature_store/execution_strategy/execution_strategy.py +113 -0
- ads/feature_store/execution_strategy/execution_strategy_provider.py +47 -0
- ads/feature_store/execution_strategy/spark/__init__.py +0 -0
- ads/feature_store/execution_strategy/spark/spark_execution.py +618 -0
- ads/feature_store/feature.py +192 -0
- ads/feature_store/feature_group.py +1494 -0
- ads/feature_store/feature_group_expectation.py +346 -0
- ads/feature_store/feature_group_job.py +602 -0
- ads/feature_store/feature_lineage/__init__.py +0 -0
- ads/feature_store/feature_lineage/graphviz_service.py +180 -0
- ads/feature_store/feature_option_details.py +50 -0
- ads/feature_store/feature_statistics/__init__.py +0 -0
- ads/feature_store/feature_statistics/statistics_service.py +99 -0
- ads/feature_store/feature_store.py +699 -0
- ads/feature_store/feature_store_registrar.py +518 -0
- ads/feature_store/input_feature_detail.py +149 -0
- ads/feature_store/mixin/__init__.py +4 -0
- ads/feature_store/mixin/oci_feature_store.py +145 -0
- ads/feature_store/model_details.py +73 -0
- ads/feature_store/query/__init__.py +0 -0
- ads/feature_store/query/filter.py +266 -0
- ads/feature_store/query/generator/__init__.py +0 -0
- ads/feature_store/query/generator/query_generator.py +298 -0
- ads/feature_store/query/join.py +161 -0
- ads/feature_store/query/query.py +403 -0
- ads/feature_store/query/validator/__init__.py +0 -0
- ads/feature_store/query/validator/query_validator.py +57 -0
- ads/feature_store/response/__init__.py +0 -0
- ads/feature_store/response/response_builder.py +68 -0
- ads/feature_store/service/__init__.py +0 -0
- ads/feature_store/service/oci_dataset.py +139 -0
- ads/feature_store/service/oci_dataset_job.py +199 -0
- ads/feature_store/service/oci_entity.py +125 -0
- ads/feature_store/service/oci_feature_group.py +164 -0
- ads/feature_store/service/oci_feature_group_job.py +214 -0
- ads/feature_store/service/oci_feature_store.py +182 -0
- ads/feature_store/service/oci_lineage.py +87 -0
- ads/feature_store/service/oci_transformation.py +104 -0
- ads/feature_store/statistics/__init__.py +0 -0
- ads/feature_store/statistics/abs_feature_value.py +49 -0
- ads/feature_store/statistics/charts/__init__.py +0 -0
- ads/feature_store/statistics/charts/abstract_feature_plot.py +37 -0
- ads/feature_store/statistics/charts/box_plot.py +148 -0
- ads/feature_store/statistics/charts/frequency_distribution.py +65 -0
- ads/feature_store/statistics/charts/probability_distribution.py +68 -0
- ads/feature_store/statistics/charts/top_k_frequent_elements.py +98 -0
- ads/feature_store/statistics/feature_stat.py +126 -0
- ads/feature_store/statistics/generic_feature_value.py +33 -0
- ads/feature_store/statistics/statistics.py +41 -0
- ads/feature_store/statistics_config.py +101 -0
- ads/feature_store/templates/feature_store_template.yaml +45 -0
- ads/feature_store/transformation.py +499 -0
- ads/feature_store/validation_output.py +57 -0
- ads/hpo/__init__.py +9 -0
- ads/hpo/_imports.py +91 -0
- ads/hpo/ads_search_space.py +439 -0
- ads/hpo/distributions.py +325 -0
- ads/hpo/objective.py +280 -0
- ads/hpo/search_cv.py +1657 -0
- ads/hpo/stopping_criterion.py +75 -0
- ads/hpo/tuner_artifact.py +413 -0
- ads/hpo/utils.py +91 -0
- ads/hpo/validation.py +140 -0
- ads/hpo/visualization/__init__.py +5 -0
- ads/hpo/visualization/_contour.py +23 -0
- ads/hpo/visualization/_edf.py +20 -0
- ads/hpo/visualization/_intermediate_values.py +21 -0
- ads/hpo/visualization/_optimization_history.py +25 -0
- ads/hpo/visualization/_parallel_coordinate.py +169 -0
- ads/hpo/visualization/_param_importances.py +26 -0
- ads/jobs/__init__.py +53 -0
- ads/jobs/ads_job.py +663 -0
- ads/jobs/builders/__init__.py +5 -0
- ads/jobs/builders/base.py +156 -0
- ads/jobs/builders/infrastructure/__init__.py +6 -0
- ads/jobs/builders/infrastructure/base.py +165 -0
- ads/jobs/builders/infrastructure/dataflow.py +1252 -0
- ads/jobs/builders/infrastructure/dsc_job.py +1894 -0
- ads/jobs/builders/infrastructure/dsc_job_runtime.py +1233 -0
- ads/jobs/builders/infrastructure/utils.py +65 -0
- ads/jobs/builders/runtimes/__init__.py +5 -0
- ads/jobs/builders/runtimes/artifact.py +338 -0
- ads/jobs/builders/runtimes/base.py +325 -0
- ads/jobs/builders/runtimes/container_runtime.py +242 -0
- ads/jobs/builders/runtimes/python_runtime.py +1016 -0
- ads/jobs/builders/runtimes/pytorch_runtime.py +204 -0
- ads/jobs/cli.py +104 -0
- ads/jobs/env_var_parser.py +131 -0
- ads/jobs/extension.py +160 -0
- ads/jobs/schema/__init__.py +5 -0
- ads/jobs/schema/infrastructure_schema.json +116 -0
- ads/jobs/schema/job_schema.json +42 -0
- ads/jobs/schema/runtime_schema.json +183 -0
- ads/jobs/schema/validator.py +141 -0
- ads/jobs/serializer.py +296 -0
- ads/jobs/templates/__init__.py +5 -0
- ads/jobs/templates/container.py +6 -0
- ads/jobs/templates/driver_notebook.py +177 -0
- ads/jobs/templates/driver_oci.py +500 -0
- ads/jobs/templates/driver_python.py +48 -0
- ads/jobs/templates/driver_pytorch.py +852 -0
- ads/jobs/templates/driver_utils.py +615 -0
- ads/jobs/templates/hostname_from_env.c +55 -0
- ads/jobs/templates/oci_metrics.py +181 -0
- ads/jobs/utils.py +104 -0
- ads/llm/__init__.py +28 -0
- ads/llm/autogen/__init__.py +2 -0
- ads/llm/autogen/constants.py +15 -0
- ads/llm/autogen/reports/__init__.py +2 -0
- ads/llm/autogen/reports/base.py +67 -0
- ads/llm/autogen/reports/data.py +103 -0
- ads/llm/autogen/reports/session.py +526 -0
- ads/llm/autogen/reports/templates/chat_box.html +13 -0
- ads/llm/autogen/reports/templates/chat_box_lt.html +5 -0
- ads/llm/autogen/reports/templates/chat_box_rt.html +6 -0
- ads/llm/autogen/reports/utils.py +56 -0
- ads/llm/autogen/v02/__init__.py +4 -0
- ads/llm/autogen/v02/client.py +295 -0
- ads/llm/autogen/v02/log_handlers/__init__.py +2 -0
- ads/llm/autogen/v02/log_handlers/oci_file_handler.py +83 -0
- ads/llm/autogen/v02/loggers/__init__.py +6 -0
- ads/llm/autogen/v02/loggers/metric_logger.py +320 -0
- ads/llm/autogen/v02/loggers/session_logger.py +580 -0
- ads/llm/autogen/v02/loggers/utils.py +86 -0
- ads/llm/autogen/v02/runtime_logging.py +163 -0
- ads/llm/chain.py +268 -0
- ads/llm/chat_template.py +31 -0
- ads/llm/deploy.py +63 -0
- ads/llm/guardrails/__init__.py +5 -0
- ads/llm/guardrails/base.py +442 -0
- ads/llm/guardrails/huggingface.py +44 -0
- ads/llm/langchain/__init__.py +5 -0
- ads/llm/langchain/plugins/__init__.py +5 -0
- ads/llm/langchain/plugins/chat_models/__init__.py +5 -0
- ads/llm/langchain/plugins/chat_models/oci_data_science.py +1027 -0
- ads/llm/langchain/plugins/embeddings/__init__.py +4 -0
- ads/llm/langchain/plugins/embeddings/oci_data_science_model_deployment_endpoint.py +184 -0
- ads/llm/langchain/plugins/llms/__init__.py +5 -0
- ads/llm/langchain/plugins/llms/oci_data_science_model_deployment_endpoint.py +979 -0
- ads/llm/requirements.txt +3 -0
- ads/llm/serialize.py +219 -0
- ads/llm/serializers/__init__.py +0 -0
- ads/llm/serializers/retrieval_qa.py +153 -0
- ads/llm/serializers/runnable_parallel.py +27 -0
- ads/llm/templates/score_chain.jinja2 +155 -0
- ads/llm/templates/tool_chat_template_hermes.jinja +130 -0
- ads/llm/templates/tool_chat_template_mistral_parallel.jinja +94 -0
- ads/model/__init__.py +52 -0
- ads/model/artifact.py +573 -0
- ads/model/artifact_downloader.py +254 -0
- ads/model/artifact_uploader.py +267 -0
- ads/model/base_properties.py +238 -0
- ads/model/common/.model-ignore +66 -0
- ads/model/common/__init__.py +5 -0
- ads/model/common/utils.py +142 -0
- ads/model/datascience_model.py +2635 -0
- ads/model/deployment/__init__.py +20 -0
- ads/model/deployment/common/__init__.py +5 -0
- ads/model/deployment/common/utils.py +308 -0
- ads/model/deployment/model_deployer.py +466 -0
- ads/model/deployment/model_deployment.py +1846 -0
- ads/model/deployment/model_deployment_infrastructure.py +671 -0
- ads/model/deployment/model_deployment_properties.py +493 -0
- ads/model/deployment/model_deployment_runtime.py +838 -0
- ads/model/extractor/__init__.py +5 -0
- ads/model/extractor/automl_extractor.py +74 -0
- ads/model/extractor/embedding_onnx_extractor.py +80 -0
- ads/model/extractor/huggingface_extractor.py +88 -0
- ads/model/extractor/keras_extractor.py +84 -0
- ads/model/extractor/lightgbm_extractor.py +93 -0
- ads/model/extractor/model_info_extractor.py +114 -0
- ads/model/extractor/model_info_extractor_factory.py +105 -0
- ads/model/extractor/pytorch_extractor.py +87 -0
- ads/model/extractor/sklearn_extractor.py +112 -0
- ads/model/extractor/spark_extractor.py +89 -0
- ads/model/extractor/tensorflow_extractor.py +85 -0
- ads/model/extractor/xgboost_extractor.py +94 -0
- ads/model/framework/__init__.py +5 -0
- ads/model/framework/automl_model.py +178 -0
- ads/model/framework/embedding_onnx_model.py +438 -0
- ads/model/framework/huggingface_model.py +399 -0
- ads/model/framework/lightgbm_model.py +266 -0
- ads/model/framework/pytorch_model.py +266 -0
- ads/model/framework/sklearn_model.py +250 -0
- ads/model/framework/spark_model.py +326 -0
- ads/model/framework/tensorflow_model.py +254 -0
- ads/model/framework/xgboost_model.py +258 -0
- ads/model/generic_model.py +3518 -0
- ads/model/model_artifact_boilerplate/README.md +381 -0
- ads/model/model_artifact_boilerplate/__init__.py +5 -0
- ads/model/model_artifact_boilerplate/artifact_introspection_test/__init__.py +5 -0
- ads/model/model_artifact_boilerplate/artifact_introspection_test/model_artifact_validate.py +427 -0
- ads/model/model_artifact_boilerplate/artifact_introspection_test/requirements.txt +2 -0
- ads/model/model_artifact_boilerplate/runtime.yaml +7 -0
- ads/model/model_artifact_boilerplate/score.py +61 -0
- ads/model/model_file_description_schema.json +68 -0
- ads/model/model_introspect.py +331 -0
- ads/model/model_metadata.py +1810 -0
- ads/model/model_metadata_mixin.py +460 -0
- ads/model/model_properties.py +63 -0
- ads/model/model_version_set.py +739 -0
- ads/model/runtime/__init__.py +5 -0
- ads/model/runtime/env_info.py +306 -0
- ads/model/runtime/model_deployment_details.py +37 -0
- ads/model/runtime/model_provenance_details.py +58 -0
- ads/model/runtime/runtime_info.py +81 -0
- ads/model/runtime/schemas/inference_env_info_schema.yaml +16 -0
- ads/model/runtime/schemas/model_provenance_schema.yaml +36 -0
- ads/model/runtime/schemas/training_env_info_schema.yaml +16 -0
- ads/model/runtime/utils.py +201 -0
- ads/model/serde/__init__.py +5 -0
- ads/model/serde/common.py +40 -0
- ads/model/serde/model_input.py +547 -0
- ads/model/serde/model_serializer.py +1184 -0
- ads/model/service/__init__.py +5 -0
- ads/model/service/oci_datascience_model.py +1076 -0
- ads/model/service/oci_datascience_model_deployment.py +500 -0
- ads/model/service/oci_datascience_model_version_set.py +176 -0
- ads/model/transformer/__init__.py +5 -0
- ads/model/transformer/onnx_transformer.py +324 -0
- ads/mysqldb/__init__.py +5 -0
- ads/mysqldb/mysql_db.py +227 -0
- ads/opctl/__init__.py +18 -0
- ads/opctl/anomaly_detection.py +11 -0
- ads/opctl/backend/__init__.py +5 -0
- ads/opctl/backend/ads_dataflow.py +353 -0
- ads/opctl/backend/ads_ml_job.py +710 -0
- ads/opctl/backend/ads_ml_pipeline.py +164 -0
- ads/opctl/backend/ads_model_deployment.py +209 -0
- ads/opctl/backend/base.py +146 -0
- ads/opctl/backend/local.py +1053 -0
- ads/opctl/backend/marketplace/__init__.py +9 -0
- ads/opctl/backend/marketplace/helm_helper.py +173 -0
- ads/opctl/backend/marketplace/local_marketplace.py +271 -0
- ads/opctl/backend/marketplace/marketplace_backend_runner.py +71 -0
- ads/opctl/backend/marketplace/marketplace_operator_interface.py +44 -0
- ads/opctl/backend/marketplace/marketplace_operator_runner.py +24 -0
- ads/opctl/backend/marketplace/marketplace_utils.py +212 -0
- ads/opctl/backend/marketplace/models/__init__.py +5 -0
- ads/opctl/backend/marketplace/models/bearer_token.py +94 -0
- ads/opctl/backend/marketplace/models/marketplace_type.py +70 -0
- ads/opctl/backend/marketplace/models/ocir_details.py +56 -0
- ads/opctl/backend/marketplace/prerequisite_checker.py +238 -0
- ads/opctl/cli.py +707 -0
- ads/opctl/cmds.py +869 -0
- ads/opctl/conda/__init__.py +5 -0
- ads/opctl/conda/cli.py +193 -0
- ads/opctl/conda/cmds.py +749 -0
- ads/opctl/conda/config.yaml +34 -0
- ads/opctl/conda/manifest_template.yaml +13 -0
- ads/opctl/conda/multipart_uploader.py +188 -0
- ads/opctl/conda/pack.py +89 -0
- ads/opctl/config/__init__.py +5 -0
- ads/opctl/config/base.py +57 -0
- ads/opctl/config/diagnostics/__init__.py +5 -0
- ads/opctl/config/diagnostics/distributed/default_requirements_config.yaml +62 -0
- ads/opctl/config/merger.py +255 -0
- ads/opctl/config/resolver.py +297 -0
- ads/opctl/config/utils.py +79 -0
- ads/opctl/config/validator.py +17 -0
- ads/opctl/config/versioner.py +68 -0
- ads/opctl/config/yaml_parsers/__init__.py +7 -0
- ads/opctl/config/yaml_parsers/base.py +58 -0
- ads/opctl/config/yaml_parsers/distributed/__init__.py +7 -0
- ads/opctl/config/yaml_parsers/distributed/yaml_parser.py +201 -0
- ads/opctl/constants.py +66 -0
- ads/opctl/decorator/__init__.py +5 -0
- ads/opctl/decorator/common.py +129 -0
- ads/opctl/diagnostics/__init__.py +5 -0
- ads/opctl/diagnostics/__main__.py +25 -0
- ads/opctl/diagnostics/check_distributed_job_requirements.py +212 -0
- ads/opctl/diagnostics/check_requirements.py +144 -0
- ads/opctl/diagnostics/requirement_exception.py +9 -0
- ads/opctl/distributed/README.md +109 -0
- ads/opctl/distributed/__init__.py +5 -0
- ads/opctl/distributed/certificates.py +32 -0
- ads/opctl/distributed/cli.py +207 -0
- ads/opctl/distributed/cmds.py +731 -0
- ads/opctl/distributed/common/__init__.py +5 -0
- ads/opctl/distributed/common/abstract_cluster_provider.py +449 -0
- ads/opctl/distributed/common/abstract_framework_spec_builder.py +88 -0
- ads/opctl/distributed/common/cluster_config_helper.py +103 -0
- ads/opctl/distributed/common/cluster_provider_factory.py +21 -0
- ads/opctl/distributed/common/cluster_runner.py +54 -0
- ads/opctl/distributed/common/framework_factory.py +29 -0
- ads/opctl/docker/Dockerfile.job +103 -0
- ads/opctl/docker/Dockerfile.job.arm +107 -0
- ads/opctl/docker/Dockerfile.job.gpu +175 -0
- ads/opctl/docker/base-env.yaml +13 -0
- ads/opctl/docker/cuda.repo +6 -0
- ads/opctl/docker/operator/.dockerignore +0 -0
- ads/opctl/docker/operator/Dockerfile +41 -0
- ads/opctl/docker/operator/Dockerfile.gpu +85 -0
- ads/opctl/docker/operator/cuda.repo +6 -0
- ads/opctl/docker/operator/environment.yaml +8 -0
- ads/opctl/forecast.py +11 -0
- ads/opctl/index.yaml +3 -0
- ads/opctl/model/__init__.py +5 -0
- ads/opctl/model/cli.py +65 -0
- ads/opctl/model/cmds.py +73 -0
- ads/opctl/operator/README.md +4 -0
- ads/opctl/operator/__init__.py +31 -0
- ads/opctl/operator/cli.py +344 -0
- ads/opctl/operator/cmd.py +596 -0
- ads/opctl/operator/common/__init__.py +5 -0
- ads/opctl/operator/common/backend_factory.py +460 -0
- ads/opctl/operator/common/const.py +27 -0
- ads/opctl/operator/common/data/synthetic.csv +16001 -0
- ads/opctl/operator/common/dictionary_merger.py +148 -0
- ads/opctl/operator/common/errors.py +42 -0
- ads/opctl/operator/common/operator_config.py +99 -0
- ads/opctl/operator/common/operator_loader.py +811 -0
- ads/opctl/operator/common/operator_schema.yaml +130 -0
- ads/opctl/operator/common/operator_yaml_generator.py +152 -0
- ads/opctl/operator/common/utils.py +208 -0
- ads/opctl/operator/lowcode/__init__.py +5 -0
- ads/opctl/operator/lowcode/anomaly/MLoperator +16 -0
- ads/opctl/operator/lowcode/anomaly/README.md +207 -0
- ads/opctl/operator/lowcode/anomaly/__init__.py +5 -0
- ads/opctl/operator/lowcode/anomaly/__main__.py +103 -0
- ads/opctl/operator/lowcode/anomaly/cmd.py +35 -0
- ads/opctl/operator/lowcode/anomaly/const.py +167 -0
- ads/opctl/operator/lowcode/anomaly/environment.yaml +10 -0
- ads/opctl/operator/lowcode/anomaly/model/__init__.py +5 -0
- ads/opctl/operator/lowcode/anomaly/model/anomaly_dataset.py +146 -0
- ads/opctl/operator/lowcode/anomaly/model/anomaly_merlion.py +162 -0
- ads/opctl/operator/lowcode/anomaly/model/automlx.py +99 -0
- ads/opctl/operator/lowcode/anomaly/model/autots.py +115 -0
- ads/opctl/operator/lowcode/anomaly/model/base_model.py +404 -0
- ads/opctl/operator/lowcode/anomaly/model/factory.py +110 -0
- ads/opctl/operator/lowcode/anomaly/model/isolationforest.py +78 -0
- ads/opctl/operator/lowcode/anomaly/model/oneclasssvm.py +78 -0
- ads/opctl/operator/lowcode/anomaly/model/randomcutforest.py +120 -0
- ads/opctl/operator/lowcode/anomaly/model/tods.py +119 -0
- ads/opctl/operator/lowcode/anomaly/operator_config.py +127 -0
- ads/opctl/operator/lowcode/anomaly/schema.yaml +401 -0
- ads/opctl/operator/lowcode/anomaly/utils.py +88 -0
- ads/opctl/operator/lowcode/common/__init__.py +5 -0
- ads/opctl/operator/lowcode/common/const.py +10 -0
- ads/opctl/operator/lowcode/common/data.py +116 -0
- ads/opctl/operator/lowcode/common/errors.py +47 -0
- ads/opctl/operator/lowcode/common/transformations.py +296 -0
- ads/opctl/operator/lowcode/common/utils.py +384 -0
- ads/opctl/operator/lowcode/feature_store_marketplace/MLoperator +13 -0
- ads/opctl/operator/lowcode/feature_store_marketplace/README.md +30 -0
- ads/opctl/operator/lowcode/feature_store_marketplace/__init__.py +5 -0
- ads/opctl/operator/lowcode/feature_store_marketplace/__main__.py +116 -0
- ads/opctl/operator/lowcode/feature_store_marketplace/cmd.py +85 -0
- ads/opctl/operator/lowcode/feature_store_marketplace/const.py +15 -0
- ads/opctl/operator/lowcode/feature_store_marketplace/environment.yaml +0 -0
- ads/opctl/operator/lowcode/feature_store_marketplace/models/__init__.py +4 -0
- ads/opctl/operator/lowcode/feature_store_marketplace/models/apigw_config.py +32 -0
- ads/opctl/operator/lowcode/feature_store_marketplace/models/db_config.py +43 -0
- ads/opctl/operator/lowcode/feature_store_marketplace/models/mysql_config.py +120 -0
- ads/opctl/operator/lowcode/feature_store_marketplace/models/serializable_yaml_model.py +34 -0
- ads/opctl/operator/lowcode/feature_store_marketplace/operator_utils.py +386 -0
- ads/opctl/operator/lowcode/feature_store_marketplace/schema.yaml +160 -0
- ads/opctl/operator/lowcode/forecast/MLoperator +25 -0
- ads/opctl/operator/lowcode/forecast/README.md +209 -0
- ads/opctl/operator/lowcode/forecast/__init__.py +5 -0
- ads/opctl/operator/lowcode/forecast/__main__.py +89 -0
- ads/opctl/operator/lowcode/forecast/cmd.py +40 -0
- ads/opctl/operator/lowcode/forecast/const.py +92 -0
- ads/opctl/operator/lowcode/forecast/environment.yaml +20 -0
- ads/opctl/operator/lowcode/forecast/errors.py +26 -0
- ads/opctl/operator/lowcode/forecast/model/__init__.py +5 -0
- ads/opctl/operator/lowcode/forecast/model/arima.py +279 -0
- ads/opctl/operator/lowcode/forecast/model/automlx.py +553 -0
- ads/opctl/operator/lowcode/forecast/model/autots.py +312 -0
- ads/opctl/operator/lowcode/forecast/model/base_model.py +875 -0
- ads/opctl/operator/lowcode/forecast/model/factory.py +106 -0
- ads/opctl/operator/lowcode/forecast/model/forecast_datasets.py +492 -0
- ads/opctl/operator/lowcode/forecast/model/ml_forecast.py +243 -0
- ads/opctl/operator/lowcode/forecast/model/neuralprophet.py +482 -0
- ads/opctl/operator/lowcode/forecast/model/prophet.py +450 -0
- ads/opctl/operator/lowcode/forecast/model_evaluator.py +244 -0
- ads/opctl/operator/lowcode/forecast/operator_config.py +234 -0
- ads/opctl/operator/lowcode/forecast/schema.yaml +506 -0
- ads/opctl/operator/lowcode/forecast/utils.py +397 -0
- ads/opctl/operator/lowcode/forecast/whatifserve/__init__.py +7 -0
- ads/opctl/operator/lowcode/forecast/whatifserve/deployment_manager.py +285 -0
- ads/opctl/operator/lowcode/forecast/whatifserve/score.py +246 -0
- ads/opctl/operator/lowcode/pii/MLoperator +17 -0
- ads/opctl/operator/lowcode/pii/README.md +208 -0
- ads/opctl/operator/lowcode/pii/__init__.py +5 -0
- ads/opctl/operator/lowcode/pii/__main__.py +78 -0
- ads/opctl/operator/lowcode/pii/cmd.py +39 -0
- ads/opctl/operator/lowcode/pii/constant.py +84 -0
- ads/opctl/operator/lowcode/pii/environment.yaml +17 -0
- ads/opctl/operator/lowcode/pii/errors.py +27 -0
- ads/opctl/operator/lowcode/pii/model/__init__.py +5 -0
- ads/opctl/operator/lowcode/pii/model/factory.py +82 -0
- ads/opctl/operator/lowcode/pii/model/guardrails.py +167 -0
- ads/opctl/operator/lowcode/pii/model/pii.py +145 -0
- ads/opctl/operator/lowcode/pii/model/processor/__init__.py +34 -0
- ads/opctl/operator/lowcode/pii/model/processor/email_replacer.py +34 -0
- ads/opctl/operator/lowcode/pii/model/processor/mbi_replacer.py +35 -0
- ads/opctl/operator/lowcode/pii/model/processor/name_replacer.py +225 -0
- ads/opctl/operator/lowcode/pii/model/processor/number_replacer.py +73 -0
- ads/opctl/operator/lowcode/pii/model/processor/remover.py +26 -0
- ads/opctl/operator/lowcode/pii/model/report.py +487 -0
- ads/opctl/operator/lowcode/pii/operator_config.py +95 -0
- ads/opctl/operator/lowcode/pii/schema.yaml +108 -0
- ads/opctl/operator/lowcode/pii/utils.py +43 -0
- ads/opctl/operator/lowcode/recommender/MLoperator +16 -0
- ads/opctl/operator/lowcode/recommender/README.md +206 -0
- ads/opctl/operator/lowcode/recommender/__init__.py +5 -0
- ads/opctl/operator/lowcode/recommender/__main__.py +82 -0
- ads/opctl/operator/lowcode/recommender/cmd.py +33 -0
- ads/opctl/operator/lowcode/recommender/constant.py +30 -0
- ads/opctl/operator/lowcode/recommender/environment.yaml +11 -0
- ads/opctl/operator/lowcode/recommender/model/base_model.py +212 -0
- ads/opctl/operator/lowcode/recommender/model/factory.py +56 -0
- ads/opctl/operator/lowcode/recommender/model/recommender_dataset.py +25 -0
- ads/opctl/operator/lowcode/recommender/model/svd.py +106 -0
- ads/opctl/operator/lowcode/recommender/operator_config.py +81 -0
- ads/opctl/operator/lowcode/recommender/schema.yaml +265 -0
- ads/opctl/operator/lowcode/recommender/utils.py +13 -0
- ads/opctl/operator/runtime/__init__.py +5 -0
- ads/opctl/operator/runtime/const.py +17 -0
- ads/opctl/operator/runtime/container_runtime_schema.yaml +50 -0
- ads/opctl/operator/runtime/marketplace_runtime.py +50 -0
- ads/opctl/operator/runtime/python_marketplace_runtime_schema.yaml +21 -0
- ads/opctl/operator/runtime/python_runtime_schema.yaml +21 -0
- ads/opctl/operator/runtime/runtime.py +115 -0
- ads/opctl/schema.yaml.yml +36 -0
- ads/opctl/script.py +40 -0
- ads/opctl/spark/__init__.py +5 -0
- ads/opctl/spark/cli.py +43 -0
- ads/opctl/spark/cmds.py +147 -0
- ads/opctl/templates/diagnostic_report_template.jinja2 +102 -0
- ads/opctl/utils.py +344 -0
- ads/oracledb/__init__.py +5 -0
- ads/oracledb/oracle_db.py +346 -0
- ads/pipeline/__init__.py +39 -0
- ads/pipeline/ads_pipeline.py +2279 -0
- ads/pipeline/ads_pipeline_run.py +772 -0
- ads/pipeline/ads_pipeline_step.py +605 -0
- ads/pipeline/builders/__init__.py +5 -0
- ads/pipeline/builders/infrastructure/__init__.py +5 -0
- ads/pipeline/builders/infrastructure/custom_script.py +32 -0
- ads/pipeline/cli.py +119 -0
- ads/pipeline/extension.py +291 -0
- ads/pipeline/schema/__init__.py +5 -0
- ads/pipeline/schema/cs_step_schema.json +35 -0
- ads/pipeline/schema/ml_step_schema.json +31 -0
- ads/pipeline/schema/pipeline_schema.json +71 -0
- ads/pipeline/visualizer/__init__.py +5 -0
- ads/pipeline/visualizer/base.py +570 -0
- ads/pipeline/visualizer/graph_renderer.py +272 -0
- ads/pipeline/visualizer/text_renderer.py +84 -0
- ads/secrets/__init__.py +11 -0
- ads/secrets/adb.py +386 -0
- ads/secrets/auth_token.py +86 -0
- ads/secrets/big_data_service.py +365 -0
- ads/secrets/mysqldb.py +149 -0
- ads/secrets/oracledb.py +160 -0
- ads/secrets/secrets.py +407 -0
- ads/telemetry/__init__.py +7 -0
- ads/telemetry/base.py +69 -0
- ads/telemetry/client.py +122 -0
- ads/telemetry/telemetry.py +257 -0
- ads/templates/dataflow_pyspark.jinja2 +13 -0
- ads/templates/dataflow_sparksql.jinja2 +22 -0
- ads/templates/func.jinja2 +20 -0
- ads/templates/schemas/openapi.json +1740 -0
- ads/templates/score-pkl.jinja2 +173 -0
- ads/templates/score.jinja2 +322 -0
- ads/templates/score_embedding_onnx.jinja2 +202 -0
- ads/templates/score_generic.jinja2 +165 -0
- ads/templates/score_huggingface_pipeline.jinja2 +217 -0
- ads/templates/score_lightgbm.jinja2 +185 -0
- ads/templates/score_onnx.jinja2 +407 -0
- ads/templates/score_onnx_new.jinja2 +473 -0
- ads/templates/score_oracle_automl.jinja2 +185 -0
- ads/templates/score_pyspark.jinja2 +154 -0
- ads/templates/score_pytorch.jinja2 +219 -0
- ads/templates/score_scikit-learn.jinja2 +184 -0
- ads/templates/score_tensorflow.jinja2 +184 -0
- ads/templates/score_xgboost.jinja2 +178 -0
- ads/text_dataset/__init__.py +5 -0
- ads/text_dataset/backends.py +211 -0
- ads/text_dataset/dataset.py +445 -0
- ads/text_dataset/extractor.py +207 -0
- ads/text_dataset/options.py +53 -0
- ads/text_dataset/udfs.py +22 -0
- ads/text_dataset/utils.py +49 -0
- ads/type_discovery/__init__.py +9 -0
- ads/type_discovery/abstract_detector.py +21 -0
- ads/type_discovery/constant_detector.py +41 -0
- ads/type_discovery/continuous_detector.py +54 -0
- ads/type_discovery/credit_card_detector.py +99 -0
- ads/type_discovery/datetime_detector.py +92 -0
- ads/type_discovery/discrete_detector.py +118 -0
- ads/type_discovery/document_detector.py +146 -0
- ads/type_discovery/ip_detector.py +68 -0
- ads/type_discovery/latlon_detector.py +90 -0
- ads/type_discovery/phone_number_detector.py +63 -0
- ads/type_discovery/type_discovery_driver.py +87 -0
- ads/type_discovery/typed_feature.py +594 -0
- ads/type_discovery/unknown_detector.py +41 -0
- ads/type_discovery/zipcode_detector.py +48 -0
- ads/vault/__init__.py +7 -0
- ads/vault/vault.py +237 -0
- {oracle_ads-2.13.9rc0.dist-info → oracle_ads-2.13.10rc0.dist-info}/METADATA +150 -149
- oracle_ads-2.13.10rc0.dist-info/RECORD +858 -0
- {oracle_ads-2.13.9rc0.dist-info → oracle_ads-2.13.10rc0.dist-info}/WHEEL +1 -2
- {oracle_ads-2.13.9rc0.dist-info → oracle_ads-2.13.10rc0.dist-info}/entry_points.txt +2 -1
- oracle_ads-2.13.9rc0.dist-info/RECORD +0 -9
- oracle_ads-2.13.9rc0.dist-info/top_level.txt +0 -1
- {oracle_ads-2.13.9rc0.dist-info → oracle_ads-2.13.10rc0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -0,0 +1,1814 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# Copyright (c) 2024, 2025 Oracle and/or its affiliates.
|
3
|
+
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
4
|
+
import base64
|
5
|
+
import json
|
6
|
+
import os
|
7
|
+
import re
|
8
|
+
import tempfile
|
9
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
10
|
+
from datetime import datetime, timedelta
|
11
|
+
from pathlib import Path
|
12
|
+
from threading import Lock
|
13
|
+
from typing import Any, Dict, List, Optional, Union
|
14
|
+
|
15
|
+
import oci
|
16
|
+
from cachetools import TTLCache
|
17
|
+
from oci.data_science.models import (
|
18
|
+
JobRun,
|
19
|
+
Metadata,
|
20
|
+
UpdateModelDetails,
|
21
|
+
UpdateModelProvenanceDetails,
|
22
|
+
)
|
23
|
+
|
24
|
+
from ads.aqua import logger
|
25
|
+
from ads.aqua.app import AquaApp
|
26
|
+
from ads.aqua.common import utils
|
27
|
+
from ads.aqua.common.entities import AquaMultiModelRef
|
28
|
+
from ads.aqua.common.enums import (
|
29
|
+
DataScienceResource,
|
30
|
+
Resource,
|
31
|
+
RqsAdditionalDetails,
|
32
|
+
Tags,
|
33
|
+
)
|
34
|
+
from ads.aqua.common.errors import (
|
35
|
+
AquaFileExistsError,
|
36
|
+
AquaFileNotFoundError,
|
37
|
+
AquaMissingKeyError,
|
38
|
+
AquaRuntimeError,
|
39
|
+
AquaValueError,
|
40
|
+
)
|
41
|
+
from ads.aqua.common.utils import (
|
42
|
+
extract_id_and_name_from_tag,
|
43
|
+
fire_and_forget,
|
44
|
+
is_valid_ocid,
|
45
|
+
upload_local_to_os,
|
46
|
+
)
|
47
|
+
from ads.aqua.config.evaluation.evaluation_service_config import (
|
48
|
+
DEFAULT_EVALUATION_CONTAINER,
|
49
|
+
EvaluationServiceConfig,
|
50
|
+
MetricConfig,
|
51
|
+
)
|
52
|
+
from ads.aqua.constants import (
|
53
|
+
CONSOLE_LINK_RESOURCE_TYPE_MAPPING,
|
54
|
+
EVALUATION_REPORT,
|
55
|
+
EVALUATION_REPORT_JSON,
|
56
|
+
EVALUATION_REPORT_MD,
|
57
|
+
JOB_INFRASTRUCTURE_TYPE_DEFAULT_NETWORKING,
|
58
|
+
LIFECYCLE_DETAILS_MISSING_JOBRUN,
|
59
|
+
NB_SESSION_IDENTIFIER,
|
60
|
+
)
|
61
|
+
from ads.aqua.evaluation.constants import (
|
62
|
+
EVAL_TERMINATION_STATE,
|
63
|
+
EvaluationConfig,
|
64
|
+
EvaluationCustomMetadata,
|
65
|
+
EvaluationMetricResult,
|
66
|
+
EvaluationReportJson,
|
67
|
+
)
|
68
|
+
from ads.aqua.evaluation.entities import (
|
69
|
+
AquaEvalMetric,
|
70
|
+
AquaEvalMetrics,
|
71
|
+
AquaEvalMetricSummary,
|
72
|
+
AquaEvalParams,
|
73
|
+
AquaEvalReport,
|
74
|
+
AquaEvaluationCommands,
|
75
|
+
AquaEvaluationDetail,
|
76
|
+
AquaEvaluationSummary,
|
77
|
+
AquaResourceIdentifier,
|
78
|
+
CreateAquaEvaluationDetails,
|
79
|
+
)
|
80
|
+
from ads.aqua.evaluation.errors import EVALUATION_JOB_EXIT_CODE_MESSAGE
|
81
|
+
from ads.aqua.model.constants import ModelCustomMetadataFields
|
82
|
+
from ads.common.auth import default_signer
|
83
|
+
from ads.common.object_storage_details import ObjectStorageDetails
|
84
|
+
from ads.common.utils import (
|
85
|
+
UNKNOWN,
|
86
|
+
get_console_link,
|
87
|
+
get_files,
|
88
|
+
get_log_links,
|
89
|
+
read_file,
|
90
|
+
)
|
91
|
+
from ads.config import (
|
92
|
+
AQUA_JOB_SUBNET_ID,
|
93
|
+
COMPARTMENT_OCID,
|
94
|
+
CONDA_BUCKET_NS,
|
95
|
+
PROJECT_OCID,
|
96
|
+
)
|
97
|
+
from ads.jobs.ads_job import DataScienceJobRun, Job
|
98
|
+
from ads.jobs.builders.infrastructure.dsc_job import DataScienceJob
|
99
|
+
from ads.jobs.builders.runtimes.base import Runtime
|
100
|
+
from ads.jobs.builders.runtimes.container_runtime import ContainerRuntime
|
101
|
+
from ads.model.datascience_model import DataScienceModel
|
102
|
+
from ads.model.deployment import ModelDeploymentContainerRuntime
|
103
|
+
from ads.model.deployment.model_deployment import ModelDeployment
|
104
|
+
from ads.model.generic_model import ModelDeploymentRuntimeType
|
105
|
+
from ads.model.model_metadata import (
|
106
|
+
MetadataTaxonomyKeys,
|
107
|
+
ModelCustomMetadata,
|
108
|
+
ModelCustomMetadataItem,
|
109
|
+
ModelProvenanceMetadata,
|
110
|
+
ModelTaxonomyMetadata,
|
111
|
+
)
|
112
|
+
from ads.model.model_version_set import ModelVersionSet
|
113
|
+
from ads.telemetry import telemetry
|
114
|
+
|
115
|
+
|
116
|
+
class AquaEvaluationApp(AquaApp):
|
117
|
+
"""Provides a suite of APIs to interact with Aqua evaluations within the
|
118
|
+
Oracle Cloud Infrastructure Data Science service, serving as an interface
|
119
|
+
for managing model evalutions.
|
120
|
+
|
121
|
+
|
122
|
+
Methods
|
123
|
+
-------
|
124
|
+
create(evaluation_source_id, evaluation_name, ...) -> AquaEvaluationSummary:
|
125
|
+
Creates Aqua evaluation for resource.
|
126
|
+
get(model_id: str) -> AquaEvaluationSummary:
|
127
|
+
Retrieves details of an Aqua evaluation by its unique identifier.
|
128
|
+
list(compartment_id: str = None, project_id: str = None, **kwargs) -> List[AquaEvaluationSummary]:
|
129
|
+
Lists all Aqua evaluation within a specified compartment and/or project.
|
130
|
+
|
131
|
+
Note:
|
132
|
+
This class is designed to work within the Oracle Cloud Infrastructure
|
133
|
+
and requires proper configuration and authentication set up to interact
|
134
|
+
with OCI services.
|
135
|
+
"""
|
136
|
+
|
137
|
+
_report_cache = TTLCache(maxsize=10, ttl=timedelta(hours=5), timer=datetime.now)
|
138
|
+
_metrics_cache = TTLCache(maxsize=10, ttl=timedelta(hours=5), timer=datetime.now)
|
139
|
+
_eval_cache = TTLCache(maxsize=200, ttl=timedelta(hours=10), timer=datetime.now)
|
140
|
+
_deletion_cache = TTLCache(
|
141
|
+
maxsize=10, ttl=timedelta(minutes=10), timer=datetime.now
|
142
|
+
)
|
143
|
+
_cache_lock = Lock()
|
144
|
+
|
145
|
+
@telemetry(entry_point="plugin=evaluation&action=create", name="aqua")
|
146
|
+
def create(
|
147
|
+
self,
|
148
|
+
create_aqua_evaluation_details: CreateAquaEvaluationDetails = None,
|
149
|
+
**kwargs,
|
150
|
+
) -> "AquaEvaluationSummary":
|
151
|
+
"""Creates Aqua evaluation for resource.\n
|
152
|
+
For detailed information about CLI flags see: https://github.com/oracle-samples/oci-data-science-ai-samples/blob/main/ai-quick-actions/cli-tips.md#model-evaluation
|
153
|
+
|
154
|
+
Parameters
|
155
|
+
----------
|
156
|
+
create_aqua_evaluation_details: CreateAquaEvaluationDetails
|
157
|
+
The CreateAquaEvaluationDetails data class which contains all
|
158
|
+
required and optional fields to create the aqua evaluation.
|
159
|
+
kwargs:
|
160
|
+
evaluation_source_id: str
|
161
|
+
The evaluation source id. Must be either model or model deployment ocid.
|
162
|
+
evaluation_name: str
|
163
|
+
The name for evaluation.
|
164
|
+
dataset_path: str
|
165
|
+
The dataset path for the evaluation. Could be either a local path from notebook session
|
166
|
+
or an object storage path.
|
167
|
+
report_path: str
|
168
|
+
The report path for the evaluation. Must be an object storage path.
|
169
|
+
model_parameters: dict
|
170
|
+
The parameters for the evaluation.
|
171
|
+
shape_name: str
|
172
|
+
The shape name for the evaluation job infrastructure.
|
173
|
+
memory_in_gbs: float
|
174
|
+
The memory in gbs for the shape selected.
|
175
|
+
ocpus: float
|
176
|
+
The ocpu count for the shape selected.
|
177
|
+
block_storage_size: int
|
178
|
+
The storage for the evaluation job infrastructure.
|
179
|
+
compartment_id: (str, optional). Defaults to `None`.
|
180
|
+
The compartment id for the evaluation.
|
181
|
+
project_id: (str, optional). Defaults to `None`.
|
182
|
+
The project id for the evaluation.
|
183
|
+
evaluation_description: (str, optional). Defaults to `None`.
|
184
|
+
The description for evaluation
|
185
|
+
experiment_id: (str, optional). Defaults to `None`.
|
186
|
+
The evaluation model version set id. If provided,
|
187
|
+
evaluation model will be associated with it.
|
188
|
+
experiment_name: (str, optional). Defaults to `None`.
|
189
|
+
The evaluation model version set name. If provided,
|
190
|
+
the model version set with the same name will be used if exists,
|
191
|
+
otherwise a new model version set will be created with the name.
|
192
|
+
experiment_description: (str, optional). Defaults to `None`.
|
193
|
+
The description for the evaluation model version set.
|
194
|
+
log_group_id: (str, optional). Defaults to `None`.
|
195
|
+
The log group id for the evaluation job infrastructure.
|
196
|
+
log_id: (str, optional). Defaults to `None`.
|
197
|
+
The log id for the evaluation job infrastructure.
|
198
|
+
metrics: (list, optional). Defaults to `None`.
|
199
|
+
The metrics for the evaluation.
|
200
|
+
force_overwrite: (bool, optional). Defaults to `False`.
|
201
|
+
Whether to force overwrite the existing file in object storage.
|
202
|
+
freeform_tags: (dict, optional)
|
203
|
+
Freeform tags for the evaluation model
|
204
|
+
defined_tags: (dict, optional)
|
205
|
+
Defined tags for the evaluation model
|
206
|
+
|
207
|
+
kwargs:
|
208
|
+
The kwargs for creating CreateAquaEvaluationDetails instance if
|
209
|
+
no create_aqua_evaluation_details provided.
|
210
|
+
|
211
|
+
Returns
|
212
|
+
-------
|
213
|
+
AquaEvaluationSummary:
|
214
|
+
The instance of AquaEvaluationSummary.
|
215
|
+
"""
|
216
|
+
if not create_aqua_evaluation_details:
|
217
|
+
try:
|
218
|
+
create_aqua_evaluation_details = CreateAquaEvaluationDetails(**kwargs)
|
219
|
+
except Exception as ex:
|
220
|
+
custom_errors = {
|
221
|
+
".".join(map(str, e["loc"])): e["msg"]
|
222
|
+
for e in json.loads(ex.json())
|
223
|
+
}
|
224
|
+
raise AquaValueError(
|
225
|
+
f"Invalid create evaluation parameters. Error details: {custom_errors}."
|
226
|
+
) from ex
|
227
|
+
|
228
|
+
if not is_valid_ocid(create_aqua_evaluation_details.evaluation_source_id):
|
229
|
+
raise AquaValueError(
|
230
|
+
f"Invalid evaluation source {create_aqua_evaluation_details.evaluation_source_id}. "
|
231
|
+
"Specify either a model or model deployment id."
|
232
|
+
)
|
233
|
+
|
234
|
+
# The model to evaluate
|
235
|
+
evaluation_source = None
|
236
|
+
eval_inference_configuration: Dict = {}
|
237
|
+
|
238
|
+
if (
|
239
|
+
DataScienceResource.MODEL_DEPLOYMENT
|
240
|
+
in create_aqua_evaluation_details.evaluation_source_id
|
241
|
+
):
|
242
|
+
evaluation_source = ModelDeployment.from_id(
|
243
|
+
create_aqua_evaluation_details.evaluation_source_id
|
244
|
+
)
|
245
|
+
|
246
|
+
if Tags.MULTIMODEL_TYPE_TAG in evaluation_source.freeform_tags:
|
247
|
+
multi_model_id = evaluation_source.freeform_tags.get(
|
248
|
+
Tags.AQUA_MODEL_ID_TAG, UNKNOWN
|
249
|
+
)
|
250
|
+
|
251
|
+
if not multi_model_id:
|
252
|
+
raise AquaRuntimeError(
|
253
|
+
f"Invalid multi model deployment {multi_model_id}."
|
254
|
+
f"Make sure the {Tags.AQUA_MODEL_ID_TAG} tag is added to the deployment."
|
255
|
+
)
|
256
|
+
|
257
|
+
aqua_model = DataScienceModel.from_id(multi_model_id)
|
258
|
+
AquaEvaluationApp.validate_model_name(
|
259
|
+
aqua_model, create_aqua_evaluation_details
|
260
|
+
)
|
261
|
+
|
262
|
+
try:
|
263
|
+
if (
|
264
|
+
evaluation_source.runtime.type
|
265
|
+
== ModelDeploymentRuntimeType.CONTAINER
|
266
|
+
):
|
267
|
+
runtime = ModelDeploymentContainerRuntime.from_dict(
|
268
|
+
evaluation_source.runtime.to_dict()
|
269
|
+
)
|
270
|
+
inference_config = (
|
271
|
+
self.get_container_config().to_dict().get("inference")
|
272
|
+
)
|
273
|
+
for container in inference_config:
|
274
|
+
if container.name == runtime.image[: runtime.image.rfind(":")]:
|
275
|
+
eval_inference_configuration = (
|
276
|
+
container.spec.evaluation_configuration
|
277
|
+
)
|
278
|
+
except Exception as ex:
|
279
|
+
logger.debug(
|
280
|
+
f"Could not load inference config details for the evaluation source id: "
|
281
|
+
f"{create_aqua_evaluation_details.evaluation_source_id}. Please check if the container"
|
282
|
+
f" runtime has the correct SMC image information.\nError: {str(ex)}"
|
283
|
+
)
|
284
|
+
elif (
|
285
|
+
DataScienceResource.MODEL
|
286
|
+
in create_aqua_evaluation_details.evaluation_source_id
|
287
|
+
):
|
288
|
+
evaluation_source = DataScienceModel.from_id(
|
289
|
+
create_aqua_evaluation_details.evaluation_source_id
|
290
|
+
)
|
291
|
+
else:
|
292
|
+
raise AquaValueError(
|
293
|
+
f"Invalid evaluation source {create_aqua_evaluation_details.evaluation_source_id}. "
|
294
|
+
"Specify either a model or model deployment id."
|
295
|
+
)
|
296
|
+
|
297
|
+
if not ObjectStorageDetails.is_oci_path(
|
298
|
+
create_aqua_evaluation_details.report_path
|
299
|
+
):
|
300
|
+
raise AquaValueError(
|
301
|
+
"Evaluation report path must be an object storage path."
|
302
|
+
)
|
303
|
+
|
304
|
+
evaluation_dataset_path = create_aqua_evaluation_details.dataset_path
|
305
|
+
if not ObjectStorageDetails.is_oci_path(evaluation_dataset_path):
|
306
|
+
# format: oci://<bucket>@<namespace>/<prefix>/<dataset_file_name>
|
307
|
+
dataset_file = os.path.basename(evaluation_dataset_path)
|
308
|
+
dst_uri = f"{create_aqua_evaluation_details.report_path.rstrip('/')}/{dataset_file}"
|
309
|
+
try:
|
310
|
+
upload_local_to_os(
|
311
|
+
src_uri=evaluation_dataset_path,
|
312
|
+
dst_uri=dst_uri,
|
313
|
+
auth=default_signer(),
|
314
|
+
force_overwrite=create_aqua_evaluation_details.force_overwrite,
|
315
|
+
)
|
316
|
+
except FileExistsError as err:
|
317
|
+
raise AquaFileExistsError(
|
318
|
+
f"Dataset {dataset_file} already exists in {create_aqua_evaluation_details.report_path}. "
|
319
|
+
"Please use a new dataset file name, report path or set `force_overwrite` as True."
|
320
|
+
) from err
|
321
|
+
logger.debug(
|
322
|
+
f"Uploaded local file {evaluation_dataset_path} to object storage {dst_uri}."
|
323
|
+
)
|
324
|
+
# tracks the size of dataset uploaded by user to the destination.
|
325
|
+
self.telemetry.record_event_async(
|
326
|
+
category="aqua/evaluation/upload",
|
327
|
+
action="size",
|
328
|
+
detail=os.path.getsize(os.path.expanduser(evaluation_dataset_path)),
|
329
|
+
)
|
330
|
+
evaluation_dataset_path = dst_uri
|
331
|
+
|
332
|
+
evaluation_model_parameters = AquaEvalParams(
|
333
|
+
shape=create_aqua_evaluation_details.shape_name,
|
334
|
+
dataset_path=evaluation_dataset_path,
|
335
|
+
report_path=create_aqua_evaluation_details.report_path,
|
336
|
+
**create_aqua_evaluation_details.model_parameters,
|
337
|
+
)
|
338
|
+
|
339
|
+
evaluation_model_defined_tags = (
|
340
|
+
create_aqua_evaluation_details.defined_tags or {}
|
341
|
+
)
|
342
|
+
|
343
|
+
target_compartment = (
|
344
|
+
create_aqua_evaluation_details.compartment_id or COMPARTMENT_OCID
|
345
|
+
)
|
346
|
+
target_project = create_aqua_evaluation_details.project_id or PROJECT_OCID
|
347
|
+
|
348
|
+
experiment_model_version_set_id = create_aqua_evaluation_details.experiment_id
|
349
|
+
experiment_model_version_set_name = (
|
350
|
+
create_aqua_evaluation_details.experiment_name
|
351
|
+
)
|
352
|
+
|
353
|
+
if (
|
354
|
+
not experiment_model_version_set_id
|
355
|
+
and not experiment_model_version_set_name
|
356
|
+
):
|
357
|
+
raise AquaValueError(
|
358
|
+
"Either experiment id or experiment name must be provided."
|
359
|
+
)
|
360
|
+
|
361
|
+
if not experiment_model_version_set_id:
|
362
|
+
try:
|
363
|
+
model_version_set = ModelVersionSet.from_name(
|
364
|
+
name=experiment_model_version_set_name,
|
365
|
+
compartment_id=target_compartment,
|
366
|
+
)
|
367
|
+
if not utils._is_valid_mvs(model_version_set, Tags.AQUA_EVALUATION):
|
368
|
+
raise AquaValueError(
|
369
|
+
f"Invalid experiment name. Please provide an experiment with `{Tags.AQUA_EVALUATION}` in tags."
|
370
|
+
)
|
371
|
+
except Exception:
|
372
|
+
logger.info(
|
373
|
+
f"Model version set {experiment_model_version_set_name} doesn't exist. "
|
374
|
+
"Creating new model version set."
|
375
|
+
)
|
376
|
+
|
377
|
+
evaluation_mvs_freeform_tags = {
|
378
|
+
Tags.AQUA_EVALUATION: Tags.AQUA_EVALUATION,
|
379
|
+
}
|
380
|
+
evaluation_mvs_freeform_tags = {
|
381
|
+
**evaluation_mvs_freeform_tags,
|
382
|
+
**(create_aqua_evaluation_details.freeform_tags or {}),
|
383
|
+
}
|
384
|
+
|
385
|
+
model_version_set = (
|
386
|
+
ModelVersionSet()
|
387
|
+
.with_compartment_id(target_compartment)
|
388
|
+
.with_project_id(target_project)
|
389
|
+
.with_name(experiment_model_version_set_name)
|
390
|
+
.with_description(
|
391
|
+
create_aqua_evaluation_details.experiment_description
|
392
|
+
)
|
393
|
+
.with_freeform_tags(**evaluation_mvs_freeform_tags)
|
394
|
+
.with_defined_tags(**evaluation_model_defined_tags)
|
395
|
+
# TODO: decide what parameters will be needed
|
396
|
+
.create(**kwargs)
|
397
|
+
)
|
398
|
+
logger.debug(
|
399
|
+
f"Successfully created model version set {experiment_model_version_set_name} with id {model_version_set.id}."
|
400
|
+
)
|
401
|
+
experiment_model_version_set_id = model_version_set.id
|
402
|
+
else:
|
403
|
+
model_version_set = ModelVersionSet.from_id(experiment_model_version_set_id)
|
404
|
+
if not utils._is_valid_mvs(model_version_set, Tags.AQUA_EVALUATION):
|
405
|
+
raise AquaValueError(
|
406
|
+
f"Invalid experiment id. Please provide an experiment with `{Tags.AQUA_EVALUATION}` in tags."
|
407
|
+
)
|
408
|
+
experiment_model_version_set_name = model_version_set.name
|
409
|
+
|
410
|
+
evaluation_model_custom_metadata = ModelCustomMetadata()
|
411
|
+
evaluation_model_custom_metadata.add(
|
412
|
+
key=EvaluationCustomMetadata.EVALUATION_SOURCE,
|
413
|
+
value=create_aqua_evaluation_details.evaluation_source_id,
|
414
|
+
)
|
415
|
+
evaluation_model_custom_metadata.add(
|
416
|
+
key=EvaluationCustomMetadata.EVALUATION_OUTPUT_PATH,
|
417
|
+
value=create_aqua_evaluation_details.report_path,
|
418
|
+
)
|
419
|
+
evaluation_model_custom_metadata.add(
|
420
|
+
key=EvaluationCustomMetadata.EVALUATION_SOURCE_NAME,
|
421
|
+
value=evaluation_source.display_name,
|
422
|
+
)
|
423
|
+
|
424
|
+
evaluation_model_taxonomy_metadata = ModelTaxonomyMetadata()
|
425
|
+
evaluation_model_taxonomy_metadata[
|
426
|
+
MetadataTaxonomyKeys.HYPERPARAMETERS
|
427
|
+
].value = {"model_params": evaluation_model_parameters.to_dict()}
|
428
|
+
|
429
|
+
evaluation_model = (
|
430
|
+
DataScienceModel()
|
431
|
+
.with_compartment_id(target_compartment)
|
432
|
+
.with_project_id(target_project)
|
433
|
+
.with_display_name(create_aqua_evaluation_details.evaluation_name)
|
434
|
+
.with_description(create_aqua_evaluation_details.evaluation_description)
|
435
|
+
.with_model_version_set_id(experiment_model_version_set_id)
|
436
|
+
.with_custom_metadata_list(evaluation_model_custom_metadata)
|
437
|
+
.with_defined_metadata_list(evaluation_model_taxonomy_metadata)
|
438
|
+
.with_provenance_metadata(ModelProvenanceMetadata(training_id=UNKNOWN))
|
439
|
+
.with_defined_tags(**evaluation_model_defined_tags)
|
440
|
+
# TODO uncomment this once the evaluation container will get the updated version of the ADS
|
441
|
+
# .with_input_schema(create_aqua_evaluation_details.to_dict())
|
442
|
+
# TODO: decide what parameters will be needed
|
443
|
+
.create(
|
444
|
+
remove_existing_artifact=False, # TODO: added here for the purpose of demo and will revisit later
|
445
|
+
**kwargs,
|
446
|
+
)
|
447
|
+
)
|
448
|
+
logger.debug(
|
449
|
+
f"Successfully created evaluation model {evaluation_model.id} for {create_aqua_evaluation_details.evaluation_source_id}."
|
450
|
+
)
|
451
|
+
|
452
|
+
# TODO: validate metrics if it's provided
|
453
|
+
|
454
|
+
evaluation_job_freeform_tags = {
|
455
|
+
Tags.AQUA_EVALUATION: Tags.AQUA_EVALUATION,
|
456
|
+
Tags.AQUA_EVALUATION_MODEL_ID: evaluation_model.id,
|
457
|
+
}
|
458
|
+
evaluation_job_freeform_tags = {
|
459
|
+
**evaluation_job_freeform_tags,
|
460
|
+
**(create_aqua_evaluation_details.freeform_tags or {}),
|
461
|
+
}
|
462
|
+
|
463
|
+
evaluation_job = Job(name=evaluation_model.display_name).with_infrastructure(
|
464
|
+
DataScienceJob()
|
465
|
+
.with_log_group_id(create_aqua_evaluation_details.log_group_id)
|
466
|
+
.with_log_id(create_aqua_evaluation_details.log_id)
|
467
|
+
.with_compartment_id(target_compartment)
|
468
|
+
.with_project_id(target_project)
|
469
|
+
.with_shape_name(create_aqua_evaluation_details.shape_name)
|
470
|
+
.with_block_storage_size(create_aqua_evaluation_details.block_storage_size)
|
471
|
+
.with_freeform_tag(**evaluation_job_freeform_tags)
|
472
|
+
.with_defined_tag(**evaluation_model_defined_tags)
|
473
|
+
)
|
474
|
+
if (
|
475
|
+
create_aqua_evaluation_details.memory_in_gbs
|
476
|
+
and create_aqua_evaluation_details.ocpus
|
477
|
+
):
|
478
|
+
evaluation_job.infrastructure.with_shape_config_details(
|
479
|
+
memory_in_gbs=create_aqua_evaluation_details.memory_in_gbs,
|
480
|
+
ocpus=create_aqua_evaluation_details.ocpus,
|
481
|
+
)
|
482
|
+
if AQUA_JOB_SUBNET_ID:
|
483
|
+
evaluation_job.infrastructure.with_subnet_id(AQUA_JOB_SUBNET_ID)
|
484
|
+
elif NB_SESSION_IDENTIFIER in os.environ:
|
485
|
+
# apply default subnet id for job by setting ME_STANDALONE
|
486
|
+
# so as to avoid using the notebook session's networking when running on it
|
487
|
+
# https://accelerated-data-science.readthedocs.io/en/latest/user_guide/jobs/infra_and_runtime.html#networking
|
488
|
+
evaluation_job.infrastructure.with_job_infrastructure_type(
|
489
|
+
JOB_INFRASTRUCTURE_TYPE_DEFAULT_NETWORKING
|
490
|
+
)
|
491
|
+
|
492
|
+
container_image = (
|
493
|
+
create_aqua_evaluation_details.container_image_uri
|
494
|
+
or self._get_evaluation_container(
|
495
|
+
create_aqua_evaluation_details.evaluation_source_id
|
496
|
+
)
|
497
|
+
)
|
498
|
+
|
499
|
+
evaluation_job.with_runtime(
|
500
|
+
self._build_evaluation_runtime(
|
501
|
+
evaluation_id=evaluation_model.id,
|
502
|
+
evaluation_source_id=(
|
503
|
+
create_aqua_evaluation_details.evaluation_source_id
|
504
|
+
),
|
505
|
+
container_image=container_image,
|
506
|
+
dataset_path=evaluation_dataset_path,
|
507
|
+
report_path=create_aqua_evaluation_details.report_path,
|
508
|
+
model_parameters={
|
509
|
+
**create_aqua_evaluation_details.model_parameters,
|
510
|
+
},
|
511
|
+
metrics=create_aqua_evaluation_details.metrics,
|
512
|
+
inference_configuration=eval_inference_configuration or {},
|
513
|
+
)
|
514
|
+
).create(**kwargs) ## TODO: decide what parameters will be needed
|
515
|
+
logger.debug(
|
516
|
+
f"Successfully created evaluation job {evaluation_job.id} for {create_aqua_evaluation_details.evaluation_source_id}."
|
517
|
+
)
|
518
|
+
|
519
|
+
evaluation_job_run = evaluation_job.run(
|
520
|
+
name=evaluation_model.display_name,
|
521
|
+
freeform_tags=evaluation_job_freeform_tags,
|
522
|
+
defined_tags=evaluation_model_defined_tags,
|
523
|
+
wait=False,
|
524
|
+
)
|
525
|
+
logger.debug(
|
526
|
+
f"Successfully created evaluation job run {evaluation_job_run.id} for {create_aqua_evaluation_details.evaluation_source_id}."
|
527
|
+
)
|
528
|
+
|
529
|
+
evaluation_model_custom_metadata.add(
|
530
|
+
key=EvaluationCustomMetadata.EVALUATION_JOB_ID,
|
531
|
+
value=evaluation_job.id,
|
532
|
+
)
|
533
|
+
evaluation_model_custom_metadata.add(
|
534
|
+
key=EvaluationCustomMetadata.EVALUATION_JOB_RUN_ID,
|
535
|
+
value=evaluation_job_run.id,
|
536
|
+
)
|
537
|
+
updated_custom_metadata_list = [
|
538
|
+
Metadata(**metadata)
|
539
|
+
for metadata in evaluation_model_custom_metadata.to_dict()["data"]
|
540
|
+
]
|
541
|
+
|
542
|
+
evaluation_model_freeform_tags = {
|
543
|
+
Tags.AQUA_EVALUATION: Tags.AQUA_EVALUATION,
|
544
|
+
**(create_aqua_evaluation_details.freeform_tags or {}),
|
545
|
+
}
|
546
|
+
|
547
|
+
self.ds_client.update_model(
|
548
|
+
model_id=evaluation_model.id,
|
549
|
+
update_model_details=UpdateModelDetails(
|
550
|
+
custom_metadata_list=updated_custom_metadata_list,
|
551
|
+
freeform_tags=evaluation_model_freeform_tags,
|
552
|
+
),
|
553
|
+
)
|
554
|
+
|
555
|
+
self.ds_client.update_model_provenance(
|
556
|
+
model_id=evaluation_model.id,
|
557
|
+
update_model_provenance_details=UpdateModelProvenanceDetails(
|
558
|
+
training_id=evaluation_job_run.id
|
559
|
+
),
|
560
|
+
)
|
561
|
+
|
562
|
+
# tracks shapes used in evaluation that were created for the given evaluation source
|
563
|
+
self.telemetry.record_event_async(
|
564
|
+
category="aqua/evaluation/create",
|
565
|
+
action="shape",
|
566
|
+
detail=create_aqua_evaluation_details.shape_name,
|
567
|
+
value=self._get_service_model_name(evaluation_source),
|
568
|
+
)
|
569
|
+
|
570
|
+
# tracks unique evaluation that were created for the given evaluation source
|
571
|
+
self.telemetry.record_event_async(
|
572
|
+
category="aqua/evaluation",
|
573
|
+
action="create",
|
574
|
+
detail=self._get_service_model_name(evaluation_source),
|
575
|
+
)
|
576
|
+
|
577
|
+
return AquaEvaluationSummary(
|
578
|
+
id=evaluation_model.id,
|
579
|
+
name=evaluation_model.display_name,
|
580
|
+
console_url=get_console_link(
|
581
|
+
resource=Resource.MODEL,
|
582
|
+
ocid=evaluation_model.id,
|
583
|
+
region=self.region,
|
584
|
+
),
|
585
|
+
time_created=str(evaluation_model.dsc_model.time_created),
|
586
|
+
lifecycle_state=evaluation_job_run.lifecycle_state or UNKNOWN,
|
587
|
+
lifecycle_details=evaluation_job_run.lifecycle_details or UNKNOWN,
|
588
|
+
experiment=AquaResourceIdentifier(
|
589
|
+
id=experiment_model_version_set_id,
|
590
|
+
name=experiment_model_version_set_name,
|
591
|
+
url=get_console_link(
|
592
|
+
resource=Resource.MODEL_VERSION_SET,
|
593
|
+
ocid=experiment_model_version_set_id,
|
594
|
+
region=self.region,
|
595
|
+
),
|
596
|
+
),
|
597
|
+
source=AquaResourceIdentifier(
|
598
|
+
id=create_aqua_evaluation_details.evaluation_source_id,
|
599
|
+
name=evaluation_source.display_name,
|
600
|
+
url=get_console_link(
|
601
|
+
resource=(
|
602
|
+
Resource.MODEL_DEPLOYMENT
|
603
|
+
if DataScienceResource.MODEL_DEPLOYMENT
|
604
|
+
in create_aqua_evaluation_details.evaluation_source_id
|
605
|
+
else Resource.MODEL
|
606
|
+
),
|
607
|
+
ocid=create_aqua_evaluation_details.evaluation_source_id,
|
608
|
+
region=self.region,
|
609
|
+
),
|
610
|
+
),
|
611
|
+
job=AquaResourceIdentifier(
|
612
|
+
id=evaluation_job.id,
|
613
|
+
name=evaluation_job.name,
|
614
|
+
url=get_console_link(
|
615
|
+
resource=Resource.JOB,
|
616
|
+
ocid=evaluation_job.id,
|
617
|
+
region=self.region,
|
618
|
+
),
|
619
|
+
),
|
620
|
+
tags={
|
621
|
+
"aqua_evaluation": Tags.AQUA_EVALUATION,
|
622
|
+
"evaluation_job_id": evaluation_job.id,
|
623
|
+
"evaluation_source": create_aqua_evaluation_details.evaluation_source_id,
|
624
|
+
"evaluation_experiment_id": experiment_model_version_set_id,
|
625
|
+
**evaluation_model_freeform_tags,
|
626
|
+
**evaluation_model_defined_tags,
|
627
|
+
},
|
628
|
+
parameters=AquaEvalParams(),
|
629
|
+
)
|
630
|
+
|
631
|
+
@staticmethod
|
632
|
+
def validate_model_name(
|
633
|
+
evaluation_source: DataScienceModel,
|
634
|
+
create_aqua_evaluation_details: CreateAquaEvaluationDetails,
|
635
|
+
) -> None:
|
636
|
+
"""
|
637
|
+
Validates the user input for the model name when creating an Aqua evaluation.
|
638
|
+
|
639
|
+
This function verifies that:
|
640
|
+
- The model group is not empty.
|
641
|
+
- The model multi metadata is present in the DataScienceModel metadata.
|
642
|
+
- The user provided a non-empty model name.
|
643
|
+
- The provided model name exists in the DataScienceModel metadata.
|
644
|
+
- The deployment configuration contains core metadata required for validation.
|
645
|
+
|
646
|
+
Parameters
|
647
|
+
----------
|
648
|
+
evaluation_source : DataScienceModel
|
649
|
+
The DataScienceModel object containing metadata about each model in the deployment.
|
650
|
+
create_aqua_evaluation_details : CreateAquaEvaluationDetails
|
651
|
+
Contains required and optional fields for creating the Aqua evaluation.
|
652
|
+
|
653
|
+
Raises
|
654
|
+
------
|
655
|
+
AquaValueError
|
656
|
+
If the user fails to provide a model name or if the provided model name does not match
|
657
|
+
any of the valid model names in the deployment metadata.
|
658
|
+
AquaRuntimeError
|
659
|
+
If the metadata is missing the model group count or if the model group count is invalid.
|
660
|
+
"""
|
661
|
+
user_model_parameters = create_aqua_evaluation_details.model_parameters
|
662
|
+
custom_metadata_list = evaluation_source.custom_metadata_list
|
663
|
+
user_model_name = user_model_parameters.get("model")
|
664
|
+
|
665
|
+
# Ensure that a non-empty model name was provided.
|
666
|
+
if not user_model_name:
|
667
|
+
error_message = (
|
668
|
+
"No model name was provided for evaluation. For multi-model deployment, "
|
669
|
+
"a model must be specified in the model parameters."
|
670
|
+
)
|
671
|
+
logger.debug(error_message)
|
672
|
+
raise AquaValueError(error_message)
|
673
|
+
|
674
|
+
# Retrieve and convert the model group count from metadata.
|
675
|
+
model_count = custom_metadata_list.get(
|
676
|
+
ModelCustomMetadataFields.MULTIMODEL_GROUP_COUNT
|
677
|
+
)
|
678
|
+
try:
|
679
|
+
model_group_count = int(model_count.value)
|
680
|
+
except Exception as ex:
|
681
|
+
error_message = (
|
682
|
+
"Missing or invalid `MULTIMODEL_GROUP_COUNT` "
|
683
|
+
f"in custom metadata for evaluation source ID '{create_aqua_evaluation_details.evaluation_source_id}'. "
|
684
|
+
f"Details: {ex}"
|
685
|
+
)
|
686
|
+
logger.error(error_message)
|
687
|
+
|
688
|
+
if model_group_count < 1:
|
689
|
+
logger.error(
|
690
|
+
f"Invalid model group count: {model_group_count} for evaluation source ID "
|
691
|
+
f"'{create_aqua_evaluation_details.evaluation_source_id}'. A valid multi-model deployment "
|
692
|
+
f"requires at least one model."
|
693
|
+
)
|
694
|
+
raise AquaRuntimeError(
|
695
|
+
f"Unable to retrieve details for the multi-model deployment evaluation. A valid multi-model deployment "
|
696
|
+
f"must include at least one model. However, the provided evaluation source ID "
|
697
|
+
f"'{create_aqua_evaluation_details.evaluation_source_id}' does not contain any information about deployed models."
|
698
|
+
)
|
699
|
+
|
700
|
+
multi_model_metadata_value = custom_metadata_list.get(
|
701
|
+
ModelCustomMetadataFields.MULTIMODEL_METADATA,
|
702
|
+
ModelCustomMetadataItem(key=ModelCustomMetadataFields.MULTIMODEL_METADATA),
|
703
|
+
).value
|
704
|
+
|
705
|
+
if not multi_model_metadata_value:
|
706
|
+
error_message = (
|
707
|
+
f"Required model metadata is missing for evaluation source ID: {evaluation_source.id}. "
|
708
|
+
f"A valid multi-model deployment requires {ModelCustomMetadataFields.MULTIMODEL_METADATA}. "
|
709
|
+
"Please recreate the model deployment and retry the evaluation, as an issue occurred during the initialization of the model group."
|
710
|
+
)
|
711
|
+
logger.debug(error_message)
|
712
|
+
raise AquaRuntimeError(error_message)
|
713
|
+
|
714
|
+
try:
|
715
|
+
multi_model_metadata = json.loads(
|
716
|
+
evaluation_source.dsc_model.get_custom_metadata_artifact(
|
717
|
+
metadata_key_name=ModelCustomMetadataFields.MULTIMODEL_METADATA
|
718
|
+
).decode("utf-8")
|
719
|
+
)
|
720
|
+
except Exception as ex:
|
721
|
+
error_message = (
|
722
|
+
f"Error fetching {ModelCustomMetadataFields.MULTIMODEL_METADATA} "
|
723
|
+
f"from custom metadata for evaluation source ID '{evaluation_source.id}'. "
|
724
|
+
f"Details: {ex}"
|
725
|
+
)
|
726
|
+
logger.error(error_message)
|
727
|
+
raise AquaRuntimeError(error_message) from ex
|
728
|
+
|
729
|
+
# Build the list of valid model names from custom metadata.
|
730
|
+
model_names = [
|
731
|
+
AquaMultiModelRef(**metadata).model_name
|
732
|
+
for metadata in multi_model_metadata
|
733
|
+
]
|
734
|
+
|
735
|
+
# Check if the provided model name is among the valid names.
|
736
|
+
if user_model_name not in model_names:
|
737
|
+
error_message = (
|
738
|
+
f"Provided model name '{user_model_name}' does not match any valid model names {model_names} "
|
739
|
+
f"for evaluation source ID '{create_aqua_evaluation_details.evaluation_source_id}'. "
|
740
|
+
"Please provide the correct model name."
|
741
|
+
)
|
742
|
+
logger.debug(error_message)
|
743
|
+
raise AquaValueError(error_message)
|
744
|
+
|
745
|
+
def _build_evaluation_runtime(
|
746
|
+
self,
|
747
|
+
evaluation_id: str,
|
748
|
+
evaluation_source_id: str,
|
749
|
+
container_image: str,
|
750
|
+
dataset_path: str,
|
751
|
+
report_path: str,
|
752
|
+
model_parameters: dict,
|
753
|
+
metrics: List = None,
|
754
|
+
inference_configuration: dict = None,
|
755
|
+
) -> Runtime:
|
756
|
+
"""Builds evaluation runtime for Job."""
|
757
|
+
# TODO the image name needs to be extracted from the mapping index.json file.
|
758
|
+
runtime = (
|
759
|
+
ContainerRuntime()
|
760
|
+
.with_image(container_image)
|
761
|
+
.with_environment_variable(
|
762
|
+
**{
|
763
|
+
"AIP_SMC_EVALUATION_ARGUMENTS": json.dumps(
|
764
|
+
{
|
765
|
+
**self._build_launch_cmd(
|
766
|
+
evaluation_id=evaluation_id,
|
767
|
+
evaluation_source_id=evaluation_source_id,
|
768
|
+
dataset_path=dataset_path,
|
769
|
+
report_path=report_path,
|
770
|
+
model_parameters=model_parameters,
|
771
|
+
metrics=metrics,
|
772
|
+
).to_dict(),
|
773
|
+
**(inference_configuration or {}),
|
774
|
+
},
|
775
|
+
),
|
776
|
+
"CONDA_BUCKET_NS": CONDA_BUCKET_NS,
|
777
|
+
},
|
778
|
+
)
|
779
|
+
)
|
780
|
+
|
781
|
+
return runtime
|
782
|
+
|
783
|
+
@staticmethod
|
784
|
+
def _get_service_model_name(
|
785
|
+
source: Union[ModelDeployment, DataScienceModel],
|
786
|
+
) -> str:
|
787
|
+
"""Gets the service model name from source. If it's ModelDeployment, needs to check
|
788
|
+
if its model has been fine tuned or not.
|
789
|
+
|
790
|
+
Parameters
|
791
|
+
----------
|
792
|
+
source: Union[ModelDeployment, DataScienceModel]
|
793
|
+
An instance of either ModelDeployment or DataScienceModel
|
794
|
+
|
795
|
+
Returns
|
796
|
+
-------
|
797
|
+
str:
|
798
|
+
The service model name of source.
|
799
|
+
"""
|
800
|
+
if isinstance(source, ModelDeployment):
|
801
|
+
fine_tuned_model_tag = source.freeform_tags.get(
|
802
|
+
Tags.AQUA_FINE_TUNED_MODEL_TAG, UNKNOWN
|
803
|
+
)
|
804
|
+
if not fine_tuned_model_tag:
|
805
|
+
return source.freeform_tags.get(Tags.AQUA_MODEL_NAME_TAG)
|
806
|
+
else:
|
807
|
+
return extract_id_and_name_from_tag(fine_tuned_model_tag)[1]
|
808
|
+
|
809
|
+
return source.display_name
|
810
|
+
|
811
|
+
def _get_evaluation_container(self, source_id: str) -> str:
|
812
|
+
# todo: use the source, identify if it is a model or a deployment. If latter, then fetch the base model id
|
813
|
+
# from the deployment object, and call ds_client.get_model() to get model details. Use custom metadata to
|
814
|
+
# get the container_type_key. Pass this key as container_type to get_container_image method.
|
815
|
+
|
816
|
+
# fetch image name from config
|
817
|
+
container_image = self.get_container_image(
|
818
|
+
container_type="odsc-llm-evaluate",
|
819
|
+
)
|
820
|
+
logger.info(f"Aqua Image used for evaluating {source_id} :{container_image}")
|
821
|
+
return container_image
|
822
|
+
|
823
|
+
def _build_launch_cmd(
|
824
|
+
self,
|
825
|
+
evaluation_id: str,
|
826
|
+
evaluation_source_id: str,
|
827
|
+
dataset_path: str,
|
828
|
+
report_path: str,
|
829
|
+
model_parameters: dict,
|
830
|
+
metrics: List = None,
|
831
|
+
):
|
832
|
+
return AquaEvaluationCommands(
|
833
|
+
evaluation_id=evaluation_id,
|
834
|
+
evaluation_target_id=evaluation_source_id,
|
835
|
+
input_data={
|
836
|
+
"format": Path(dataset_path).suffix,
|
837
|
+
"url": dataset_path,
|
838
|
+
},
|
839
|
+
metrics=metrics or [],
|
840
|
+
output_dir=report_path,
|
841
|
+
params=model_parameters or {},
|
842
|
+
)
|
843
|
+
|
844
|
+
@telemetry(entry_point="plugin=evaluation&action=get", name="aqua")
|
845
|
+
def get(self, eval_id) -> AquaEvaluationDetail:
|
846
|
+
"""Gets the information of an Aqua evalution.
|
847
|
+
|
848
|
+
Parameters
|
849
|
+
----------
|
850
|
+
eval_id: str
|
851
|
+
The model OCID.
|
852
|
+
|
853
|
+
Returns
|
854
|
+
-------
|
855
|
+
AquaEvaluationDetail:
|
856
|
+
The instance of AquaEvaluationDetail.
|
857
|
+
"""
|
858
|
+
logger.info(f"Fetching evaluation: {eval_id} details ...")
|
859
|
+
|
860
|
+
resource = utils.query_resource(eval_id)
|
861
|
+
if not resource:
|
862
|
+
raise AquaRuntimeError(
|
863
|
+
f"Failed to retrieve evalution {eval_id}."
|
864
|
+
"Please check if the OCID is correct."
|
865
|
+
)
|
866
|
+
model_provenance = self.ds_client.get_model_provenance(eval_id).data
|
867
|
+
|
868
|
+
jobrun_id = model_provenance.training_id
|
869
|
+
job_run_details = self._fetch_jobrun(
|
870
|
+
resource, use_rqs=False, jobrun_id=jobrun_id
|
871
|
+
)
|
872
|
+
|
873
|
+
try:
|
874
|
+
log_id = job_run_details.log_details.log_id
|
875
|
+
except Exception as e:
|
876
|
+
logger.debug(f"Failed to get associated log. {str(e)}")
|
877
|
+
log_id = ""
|
878
|
+
|
879
|
+
try:
|
880
|
+
loggroup_id = job_run_details.log_details.log_group_id
|
881
|
+
except Exception as e:
|
882
|
+
logger.debug(f"Failed to get associated loggroup. {str(e)}")
|
883
|
+
loggroup_id = ""
|
884
|
+
|
885
|
+
loggroup_url = get_log_links(region=self.region, log_group_id=loggroup_id)
|
886
|
+
log_url = (
|
887
|
+
get_log_links(
|
888
|
+
region=self.region,
|
889
|
+
log_group_id=loggroup_id,
|
890
|
+
log_id=log_id,
|
891
|
+
compartment_id=job_run_details.compartment_id,
|
892
|
+
source_id=jobrun_id,
|
893
|
+
)
|
894
|
+
if job_run_details
|
895
|
+
else ""
|
896
|
+
)
|
897
|
+
|
898
|
+
log_name = None
|
899
|
+
loggroup_name = None
|
900
|
+
|
901
|
+
if log_id:
|
902
|
+
try:
|
903
|
+
log = utils.query_resource(log_id, return_all=False)
|
904
|
+
log_name = log.display_name if log else ""
|
905
|
+
except Exception as ex:
|
906
|
+
logger.debug(f"Failed to get associated log name. Error: {ex}")
|
907
|
+
pass
|
908
|
+
|
909
|
+
if loggroup_id:
|
910
|
+
try:
|
911
|
+
loggroup = utils.query_resource(loggroup_id, return_all=False)
|
912
|
+
loggroup_name = loggroup.display_name if loggroup else ""
|
913
|
+
except Exception as ex:
|
914
|
+
logger.debug(f"Failed to get associated loggroup name. Error: {ex}")
|
915
|
+
pass
|
916
|
+
|
917
|
+
try:
|
918
|
+
introspection = json.loads(
|
919
|
+
self._get_attribute_from_model_metadata(resource, "ArtifactTestResults")
|
920
|
+
)
|
921
|
+
except Exception as ex:
|
922
|
+
logger.debug(
|
923
|
+
f"There was an issue loading the model attribute as json object for evaluation {eval_id}. "
|
924
|
+
f"Setting introspection to empty.\n Error:{ex}"
|
925
|
+
)
|
926
|
+
introspection = {}
|
927
|
+
|
928
|
+
summary = AquaEvaluationDetail(
|
929
|
+
**self._process(resource),
|
930
|
+
**self._get_status(model=resource, jobrun=job_run_details),
|
931
|
+
job=self._build_job_identifier(
|
932
|
+
job_run_details=job_run_details,
|
933
|
+
),
|
934
|
+
log_group=AquaResourceIdentifier(loggroup_id, loggroup_name, loggroup_url),
|
935
|
+
log=AquaResourceIdentifier(log_id, log_name, log_url),
|
936
|
+
introspection=introspection,
|
937
|
+
)
|
938
|
+
summary.parameters.shape = (
|
939
|
+
job_run_details.job_infrastructure_configuration_details.shape_name
|
940
|
+
)
|
941
|
+
return summary
|
942
|
+
|
943
|
+
@telemetry(entry_point="plugin=evaluation&action=list", name="aqua")
|
944
|
+
def list(self, compartment_id: str = None) -> List[AquaEvaluationSummary]:
|
945
|
+
"""List Aqua evaluations in a given compartment and under certain project.
|
946
|
+
|
947
|
+
Parameters
|
948
|
+
----------
|
949
|
+
compartment_id: (str, optional). Defaults to `None`.
|
950
|
+
The compartment OCID.
|
951
|
+
|
952
|
+
Returns
|
953
|
+
-------
|
954
|
+
List[AquaEvaluationSummary]:
|
955
|
+
The list of the `ads.aqua.evalution.AquaEvaluationSummary`.
|
956
|
+
"""
|
957
|
+
compartment_id = compartment_id or COMPARTMENT_OCID
|
958
|
+
logger.info(f"Fetching evaluations from compartment {compartment_id}.")
|
959
|
+
models = utils.query_resources(
|
960
|
+
compartment_id=compartment_id,
|
961
|
+
resource_type="datasciencemodel",
|
962
|
+
tag_list=[Tags.AQUA_EVALUATION],
|
963
|
+
)
|
964
|
+
logger.info(f"Fetched {len(models)} evaluations.")
|
965
|
+
|
966
|
+
mapping = self._prefetch_resources(compartment_id)
|
967
|
+
|
968
|
+
evaluations = []
|
969
|
+
async_tasks = []
|
970
|
+
for model in models:
|
971
|
+
if model.identifier in self._eval_cache:
|
972
|
+
logger.debug(f"Retrieving evaluation {model.identifier} from cache.")
|
973
|
+
evaluations.append(self._eval_cache.get(model.identifier))
|
974
|
+
|
975
|
+
else:
|
976
|
+
jobrun_id = self._get_attribute_from_model_metadata(
|
977
|
+
model, EvaluationCustomMetadata.EVALUATION_JOB_RUN_ID
|
978
|
+
)
|
979
|
+
job_run = mapping.get(jobrun_id)
|
980
|
+
|
981
|
+
if not job_run:
|
982
|
+
async_tasks.append((model, jobrun_id))
|
983
|
+
else:
|
984
|
+
evaluations.append(self._process_evaluation_summary(model, job_run))
|
985
|
+
|
986
|
+
with ThreadPoolExecutor(max_workers=10) as executor:
|
987
|
+
future_to_model = {
|
988
|
+
executor.submit(
|
989
|
+
self._fetch_jobrun, model, use_rqs=True, jobrun_id=jobrun_id
|
990
|
+
): model
|
991
|
+
for model, jobrun_id in async_tasks
|
992
|
+
}
|
993
|
+
for future in as_completed(future_to_model):
|
994
|
+
model = future_to_model[future]
|
995
|
+
try:
|
996
|
+
jobrun = future.result()
|
997
|
+
evaluations.append(
|
998
|
+
self._process_evaluation_summary(model=model, jobrun=jobrun)
|
999
|
+
)
|
1000
|
+
except Exception as exc:
|
1001
|
+
logger.debug(
|
1002
|
+
f"Processing evaluation: {model.identifier} generated an exception: {exc}"
|
1003
|
+
)
|
1004
|
+
evaluations.append(
|
1005
|
+
self._process_evaluation_summary(model=model, jobrun=None)
|
1006
|
+
)
|
1007
|
+
|
1008
|
+
# tracks number of times deployment listing was called
|
1009
|
+
self.telemetry.record_event_async(category="aqua/evaluation", action="list")
|
1010
|
+
|
1011
|
+
return evaluations
|
1012
|
+
|
1013
|
+
def _process_evaluation_summary(
|
1014
|
+
self,
|
1015
|
+
model: oci.resource_search.models.ResourceSummary,
|
1016
|
+
jobrun: oci.resource_search.models.ResourceSummary = None,
|
1017
|
+
) -> AquaEvaluationSummary:
|
1018
|
+
"""Builds AquaEvaluationSummary from model and jobrun."""
|
1019
|
+
|
1020
|
+
evaluation_summary = AquaEvaluationSummary(
|
1021
|
+
**self._process(model),
|
1022
|
+
**self._get_status(
|
1023
|
+
model=model,
|
1024
|
+
jobrun=jobrun,
|
1025
|
+
),
|
1026
|
+
job=self._build_job_identifier(
|
1027
|
+
job_run_details=jobrun,
|
1028
|
+
),
|
1029
|
+
)
|
1030
|
+
|
1031
|
+
# Add evaluation in terminal state into cache
|
1032
|
+
if evaluation_summary.lifecycle_state in EVAL_TERMINATION_STATE:
|
1033
|
+
self._eval_cache.__setitem__(key=model.identifier, value=evaluation_summary)
|
1034
|
+
|
1035
|
+
return evaluation_summary
|
1036
|
+
|
1037
|
+
def _if_eval_artifact_exist(
|
1038
|
+
self, model: oci.resource_search.models.ResourceSummary
|
1039
|
+
) -> bool:
|
1040
|
+
"""Checks if the evaluation artifact exists."""
|
1041
|
+
try:
|
1042
|
+
response = self.ds_client.head_model_artifact(model_id=model.identifier)
|
1043
|
+
return response.status == 200
|
1044
|
+
except oci.exceptions.ServiceError as ex:
|
1045
|
+
if ex.status == 404:
|
1046
|
+
logger.debug(f"Evaluation artifact not found for {model.identifier}.")
|
1047
|
+
return False
|
1048
|
+
|
1049
|
+
@telemetry(entry_point="plugin=evaluation&action=get_status", name="aqua")
|
1050
|
+
def get_status(self, eval_id: str) -> dict:
|
1051
|
+
"""Gets evaluation's current status.
|
1052
|
+
|
1053
|
+
Parameters
|
1054
|
+
----------
|
1055
|
+
eval_id: str
|
1056
|
+
The evaluation ocid.
|
1057
|
+
|
1058
|
+
Returns
|
1059
|
+
-------
|
1060
|
+
dict
|
1061
|
+
"""
|
1062
|
+
eval = utils.query_resource(eval_id)
|
1063
|
+
|
1064
|
+
if not eval:
|
1065
|
+
raise AquaRuntimeError(
|
1066
|
+
f"Failed to retrieve evalution {eval_id}."
|
1067
|
+
"Please check if the OCID is correct."
|
1068
|
+
)
|
1069
|
+
|
1070
|
+
model_provenance = self.ds_client.get_model_provenance(eval_id).data
|
1071
|
+
|
1072
|
+
jobrun_id = model_provenance.training_id
|
1073
|
+
job_run_details = self._fetch_jobrun(eval, use_rqs=False, jobrun_id=jobrun_id)
|
1074
|
+
|
1075
|
+
try:
|
1076
|
+
log_id = job_run_details.log_details.log_id
|
1077
|
+
except Exception as e:
|
1078
|
+
logger.debug(f"Failed to get associated log.\nError: {str(e)}")
|
1079
|
+
log_id = ""
|
1080
|
+
|
1081
|
+
try:
|
1082
|
+
loggroup_id = job_run_details.log_details.log_group_id
|
1083
|
+
except Exception as e:
|
1084
|
+
logger.debug(f"Failed to get associated log.\nError: {str(e)}")
|
1085
|
+
loggroup_id = ""
|
1086
|
+
|
1087
|
+
loggroup_url = get_log_links(region=self.region, log_group_id=loggroup_id)
|
1088
|
+
log_url = (
|
1089
|
+
get_log_links(
|
1090
|
+
region=self.region,
|
1091
|
+
log_group_id=loggroup_id,
|
1092
|
+
log_id=log_id,
|
1093
|
+
compartment_id=job_run_details.compartment_id,
|
1094
|
+
source_id=jobrun_id,
|
1095
|
+
)
|
1096
|
+
if job_run_details
|
1097
|
+
else ""
|
1098
|
+
)
|
1099
|
+
return {
|
1100
|
+
"id": eval_id,
|
1101
|
+
**self._get_status(
|
1102
|
+
model=eval,
|
1103
|
+
jobrun=job_run_details,
|
1104
|
+
),
|
1105
|
+
"log_id": log_id,
|
1106
|
+
"log_url": log_url,
|
1107
|
+
"loggroup_id": loggroup_id,
|
1108
|
+
"loggroup_url": loggroup_url,
|
1109
|
+
}
|
1110
|
+
|
1111
|
+
def get_supported_metrics(self) -> List[MetricConfig]:
|
1112
|
+
"""Gets a list of supported metrics for evaluation."""
|
1113
|
+
containers = self.list_service_containers()
|
1114
|
+
container_item = next(
|
1115
|
+
c
|
1116
|
+
for c in containers
|
1117
|
+
if c.is_latest and c.family_name == DEFAULT_EVALUATION_CONTAINER
|
1118
|
+
)
|
1119
|
+
evaluation_service_config = EvaluationServiceConfig.from_oci_container_config(
|
1120
|
+
container_item
|
1121
|
+
)
|
1122
|
+
return evaluation_service_config.ui_config.metrics
|
1123
|
+
|
1124
|
+
@telemetry(entry_point="plugin=evaluation&action=load_metrics", name="aqua")
|
1125
|
+
def load_metrics(self, eval_id: str) -> AquaEvalMetrics:
|
1126
|
+
"""Loads evalution metrics markdown from artifacts.
|
1127
|
+
|
1128
|
+
Parameters
|
1129
|
+
----------
|
1130
|
+
eval_id: str
|
1131
|
+
The evaluation ocid.
|
1132
|
+
|
1133
|
+
Returns
|
1134
|
+
-------
|
1135
|
+
AquaEvalMetrics:
|
1136
|
+
An instance of AquaEvalMetrics.
|
1137
|
+
"""
|
1138
|
+
if eval_id in self._metrics_cache:
|
1139
|
+
logger.info("Returning metrics from cache.")
|
1140
|
+
eval_metrics = self._metrics_cache.get(eval_id)
|
1141
|
+
if len(eval_metrics.report) > 0:
|
1142
|
+
return eval_metrics
|
1143
|
+
|
1144
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
1145
|
+
logger.info(f"Downloading evaluation artifact: {eval_id}.")
|
1146
|
+
|
1147
|
+
dsc_model = DataScienceModel.from_id(eval_id)
|
1148
|
+
if dsc_model.if_model_custom_metadata_artifact_exist(
|
1149
|
+
EVALUATION_REPORT_MD
|
1150
|
+
) and dsc_model.if_model_custom_metadata_artifact_exist(
|
1151
|
+
EVALUATION_REPORT_JSON
|
1152
|
+
):
|
1153
|
+
logger.info(
|
1154
|
+
f"Fetching {EVALUATION_REPORT_MD} and {EVALUATION_REPORT_JSON} from custom metadata..."
|
1155
|
+
)
|
1156
|
+
dsc_model.get_custom_metadata_artifact(EVALUATION_REPORT_MD, temp_dir)
|
1157
|
+
dsc_model.get_custom_metadata_artifact(EVALUATION_REPORT_JSON, temp_dir)
|
1158
|
+
else:
|
1159
|
+
logger.info("Fetching Evaluation Reports from OSS bucket...")
|
1160
|
+
dsc_model.download_artifact(
|
1161
|
+
temp_dir,
|
1162
|
+
auth=self._auth,
|
1163
|
+
)
|
1164
|
+
|
1165
|
+
files_in_artifact = get_files(temp_dir)
|
1166
|
+
md_report_content = self._read_from_artifact(
|
1167
|
+
temp_dir, files_in_artifact, EVALUATION_REPORT_MD
|
1168
|
+
)
|
1169
|
+
|
1170
|
+
# json report not available for failed evaluation
|
1171
|
+
try:
|
1172
|
+
json_report = json.loads(
|
1173
|
+
self._read_from_artifact(
|
1174
|
+
temp_dir, files_in_artifact, EVALUATION_REPORT_JSON
|
1175
|
+
)
|
1176
|
+
)
|
1177
|
+
except Exception as e:
|
1178
|
+
logger.debug(
|
1179
|
+
f"Failed to load `report.json` from evaluation artifact.\nError: {str(e)}"
|
1180
|
+
)
|
1181
|
+
json_report = {}
|
1182
|
+
|
1183
|
+
eval_metrics = AquaEvalMetrics(
|
1184
|
+
id=eval_id,
|
1185
|
+
report=base64.b64encode(md_report_content).decode(),
|
1186
|
+
metric_results=[
|
1187
|
+
AquaEvalMetric(
|
1188
|
+
key=metadata.get(EvaluationMetricResult.SHORT_NAME, utils.UNKNOWN),
|
1189
|
+
name=metadata.get(EvaluationMetricResult.NAME, utils.UNKNOWN),
|
1190
|
+
description=metadata.get(
|
1191
|
+
EvaluationMetricResult.DESCRIPTION, utils.UNKNOWN
|
1192
|
+
),
|
1193
|
+
)
|
1194
|
+
for _, metadata in json_report.get(
|
1195
|
+
EvaluationReportJson.METRIC_RESULT, {}
|
1196
|
+
).items()
|
1197
|
+
],
|
1198
|
+
metric_summary_result=[
|
1199
|
+
AquaEvalMetricSummary(**m)
|
1200
|
+
for m in json_report.get(
|
1201
|
+
EvaluationReportJson.METRIC_SUMMARY_RESULT, [{}]
|
1202
|
+
)
|
1203
|
+
],
|
1204
|
+
)
|
1205
|
+
|
1206
|
+
if md_report_content:
|
1207
|
+
self._metrics_cache.__setitem__(key=eval_id, value=eval_metrics)
|
1208
|
+
|
1209
|
+
return eval_metrics
|
1210
|
+
|
1211
|
+
def _read_from_artifact(self, artifact_dir, files, target):
|
1212
|
+
"""Reads target file from artifacts.
|
1213
|
+
|
1214
|
+
Parameters
|
1215
|
+
----------
|
1216
|
+
artifact_dir: str
|
1217
|
+
Path of the artifact.
|
1218
|
+
files: list
|
1219
|
+
List of files name in artifacts.
|
1220
|
+
target: str
|
1221
|
+
Target file name.
|
1222
|
+
|
1223
|
+
Return
|
1224
|
+
------
|
1225
|
+
bytes
|
1226
|
+
"""
|
1227
|
+
content = None
|
1228
|
+
for f in files:
|
1229
|
+
if os.path.basename(f) == target:
|
1230
|
+
logger.info(f"Reading {f}...")
|
1231
|
+
with open(os.path.join(artifact_dir, f), "rb") as f:
|
1232
|
+
content = f.read()
|
1233
|
+
break
|
1234
|
+
|
1235
|
+
if not content:
|
1236
|
+
raise AquaFileNotFoundError(
|
1237
|
+
"Related Resource Not Authorized Or Not Found:"
|
1238
|
+
f"Missing `{target}` in evaluation artifact."
|
1239
|
+
)
|
1240
|
+
return content
|
1241
|
+
|
1242
|
+
@telemetry(entry_point="plugin=evaluation&action=download_report", name="aqua")
|
1243
|
+
def download_report(self, eval_id) -> AquaEvalReport:
|
1244
|
+
"""Downloads HTML report from model artifact.
|
1245
|
+
|
1246
|
+
Parameters
|
1247
|
+
----------
|
1248
|
+
eval_id: str
|
1249
|
+
The evaluation ocid.
|
1250
|
+
|
1251
|
+
Returns
|
1252
|
+
-------
|
1253
|
+
AquaEvalReport:
|
1254
|
+
An instance of AquaEvalReport.
|
1255
|
+
|
1256
|
+
Raises
|
1257
|
+
------
|
1258
|
+
AquaFileNotFoundError:
|
1259
|
+
When missing `report.html` in evaluation artifact.
|
1260
|
+
"""
|
1261
|
+
if eval_id in self._report_cache:
|
1262
|
+
logger.info("Returning report from cache.")
|
1263
|
+
report = self._report_cache.get(eval_id)
|
1264
|
+
if report.content:
|
1265
|
+
return report
|
1266
|
+
|
1267
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
1268
|
+
logger.info(f"Downloading evaluation artifact for {eval_id}.")
|
1269
|
+
dsc_model = DataScienceModel.from_id(eval_id)
|
1270
|
+
if_custom_metadata_exists = (
|
1271
|
+
dsc_model.if_model_custom_metadata_artifact_exist(EVALUATION_REPORT)
|
1272
|
+
)
|
1273
|
+
if if_custom_metadata_exists:
|
1274
|
+
logger.info(f"Fetching {EVALUATION_REPORT} from custom metadata.")
|
1275
|
+
dsc_model.get_custom_metadata_artifact(EVALUATION_REPORT, temp_dir)
|
1276
|
+
else:
|
1277
|
+
logger.info(f"Fetching {EVALUATION_REPORT} from Model artifact.")
|
1278
|
+
dsc_model.download_artifact(
|
1279
|
+
temp_dir,
|
1280
|
+
auth=self._auth,
|
1281
|
+
)
|
1282
|
+
files_in_artifact = get_files(temp_dir)
|
1283
|
+
if not len(files_in_artifact):
|
1284
|
+
try:
|
1285
|
+
evaluation_output_path = dsc_model.custom_metadata_list.get(
|
1286
|
+
EvaluationCustomMetadata.EVALUATION_OUTPUT_PATH
|
1287
|
+
).value
|
1288
|
+
report_path = (
|
1289
|
+
evaluation_output_path.rstrip("/")
|
1290
|
+
+ "/"
|
1291
|
+
+ eval_id
|
1292
|
+
+ "/"
|
1293
|
+
+ EVALUATION_REPORT
|
1294
|
+
)
|
1295
|
+
logger.info(
|
1296
|
+
f"Fetching {EVALUATION_REPORT} from {report_path} for evaluation {eval_id}"
|
1297
|
+
)
|
1298
|
+
content = read_file(
|
1299
|
+
file_path=report_path, auth=default_signer()
|
1300
|
+
).encode()
|
1301
|
+
except ValueError as err:
|
1302
|
+
raise AquaValueError(
|
1303
|
+
f"{EvaluationCustomMetadata.EVALUATION_OUTPUT_PATH} is missing from custom metadata for the model {eval_id}"
|
1304
|
+
) from err
|
1305
|
+
else:
|
1306
|
+
content = self._read_from_artifact(
|
1307
|
+
temp_dir, files_in_artifact, EVALUATION_REPORT
|
1308
|
+
)
|
1309
|
+
report = AquaEvalReport(
|
1310
|
+
evaluation_id=eval_id, content=base64.b64encode(content).decode()
|
1311
|
+
)
|
1312
|
+
|
1313
|
+
self._report_cache.__setitem__(key=eval_id, value=report)
|
1314
|
+
|
1315
|
+
return report
|
1316
|
+
|
1317
|
+
@telemetry(entry_point="plugin=evaluation&action=cancel", name="aqua")
|
1318
|
+
def cancel(self, eval_id) -> dict:
|
1319
|
+
"""Cancels the job run for the given evaluation id.
|
1320
|
+
Parameters
|
1321
|
+
----------
|
1322
|
+
eval_id: str
|
1323
|
+
The evaluation ocid.
|
1324
|
+
|
1325
|
+
Returns
|
1326
|
+
-------
|
1327
|
+
dict containing id, status and time_accepted
|
1328
|
+
|
1329
|
+
Raises
|
1330
|
+
------
|
1331
|
+
AquaRuntimeError:
|
1332
|
+
if a model doesn't exist for the given eval_id
|
1333
|
+
AquaMissingKeyError:
|
1334
|
+
if training_id is missing the job run id
|
1335
|
+
"""
|
1336
|
+
model = DataScienceModel.from_id(eval_id)
|
1337
|
+
if not model:
|
1338
|
+
raise AquaRuntimeError(
|
1339
|
+
f"Failed to get evaluation details for model {eval_id}"
|
1340
|
+
)
|
1341
|
+
|
1342
|
+
job_run_id = (
|
1343
|
+
model.provenance_metadata.training_id if model.provenance_metadata else None
|
1344
|
+
)
|
1345
|
+
if not job_run_id:
|
1346
|
+
raise AquaMissingKeyError(
|
1347
|
+
"Model provenance is missing job run training_id key"
|
1348
|
+
)
|
1349
|
+
|
1350
|
+
status = {"id": eval_id, "lifecycle_state": UNKNOWN, "time_accepted": UNKNOWN}
|
1351
|
+
run = DataScienceJobRun.from_ocid(job_run_id)
|
1352
|
+
if run.lifecycle_state in [
|
1353
|
+
DataScienceJobRun.LIFECYCLE_STATE_ACCEPTED,
|
1354
|
+
DataScienceJobRun.LIFECYCLE_STATE_IN_PROGRESS,
|
1355
|
+
DataScienceJobRun.LIFECYCLE_STATE_NEEDS_ATTENTION,
|
1356
|
+
]:
|
1357
|
+
self._cancel_job_run(run, model)
|
1358
|
+
status = {
|
1359
|
+
"id": eval_id,
|
1360
|
+
"lifecycle_state": "CANCELING",
|
1361
|
+
"time_accepted": datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f%z"),
|
1362
|
+
}
|
1363
|
+
return status
|
1364
|
+
|
1365
|
+
@staticmethod
|
1366
|
+
@fire_and_forget
|
1367
|
+
def _cancel_job_run(run, model):
|
1368
|
+
try:
|
1369
|
+
run.cancel()
|
1370
|
+
logger.info(f"Canceling Job Run: {run.id} for evaluation {model.id}")
|
1371
|
+
except oci.exceptions.ServiceError as ex:
|
1372
|
+
logger.error(
|
1373
|
+
f"Exception occurred while canceling job run: {run.id} for evaluation {model.id}. "
|
1374
|
+
f"Exception message: {ex}"
|
1375
|
+
)
|
1376
|
+
|
1377
|
+
@telemetry(entry_point="plugin=evaluation&action=delete", name="aqua")
|
1378
|
+
def delete(self, eval_id):
|
1379
|
+
"""Deletes the job and the associated model for the given evaluation id.
|
1380
|
+
|
1381
|
+
Parameters
|
1382
|
+
----------
|
1383
|
+
eval_id: str
|
1384
|
+
The evaluation ocid.
|
1385
|
+
|
1386
|
+
Returns
|
1387
|
+
-------
|
1388
|
+
dict containing id, status and time_accepted
|
1389
|
+
|
1390
|
+
Raises
|
1391
|
+
------
|
1392
|
+
AquaRuntimeError:
|
1393
|
+
if a model doesn't exist for the given eval_id.
|
1394
|
+
AquaMissingKeyError:
|
1395
|
+
if job/jobrun id is missing.
|
1396
|
+
"""
|
1397
|
+
|
1398
|
+
model = DataScienceModel.from_id(eval_id)
|
1399
|
+
if not model:
|
1400
|
+
raise AquaRuntimeError(
|
1401
|
+
f"Failed to get evaluation details for model {eval_id}"
|
1402
|
+
)
|
1403
|
+
|
1404
|
+
try:
|
1405
|
+
job_id = model.custom_metadata_list.get(
|
1406
|
+
EvaluationCustomMetadata.EVALUATION_JOB_ID
|
1407
|
+
).value
|
1408
|
+
except Exception as ex:
|
1409
|
+
raise AquaMissingKeyError(
|
1410
|
+
f"Custom metadata is missing {EvaluationCustomMetadata.EVALUATION_JOB_ID} key"
|
1411
|
+
) from ex
|
1412
|
+
|
1413
|
+
job = DataScienceJob.from_id(job_id)
|
1414
|
+
|
1415
|
+
self._delete_job_and_model(job, model)
|
1416
|
+
|
1417
|
+
try:
|
1418
|
+
jobrun_id = model.custom_metadata_list.get(
|
1419
|
+
EvaluationCustomMetadata.EVALUATION_JOB_RUN_ID
|
1420
|
+
).value
|
1421
|
+
jobrun = utils.query_resource(jobrun_id, return_all=False)
|
1422
|
+
except Exception:
|
1423
|
+
logger.debug("Associated Job Run OCID is missing.")
|
1424
|
+
jobrun = None
|
1425
|
+
|
1426
|
+
self._eval_cache.pop(key=eval_id, default=None)
|
1427
|
+
self._deletion_cache.__setitem__(key=eval_id, value="")
|
1428
|
+
|
1429
|
+
status = {
|
1430
|
+
"id": eval_id,
|
1431
|
+
"lifecycle_state": jobrun.lifecycle_state if jobrun else "DELETING",
|
1432
|
+
"time_accepted": datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f%z"),
|
1433
|
+
}
|
1434
|
+
return status
|
1435
|
+
|
1436
|
+
@staticmethod
|
1437
|
+
@fire_and_forget
|
1438
|
+
def _delete_job_and_model(job: DataScienceJob, model: DataScienceModel):
|
1439
|
+
try:
|
1440
|
+
job.dsc_job.delete(force_delete=True)
|
1441
|
+
logger.info(f"Deleting Job: {job.job_id} for evaluation {model.id}")
|
1442
|
+
model.delete()
|
1443
|
+
logger.info(f"Deleting evaluation: {model.id}")
|
1444
|
+
except oci.exceptions.ServiceError as ex:
|
1445
|
+
logger.error(
|
1446
|
+
f"Exception occurred while deleting job: {job.job_id} for evaluation {model.id}. "
|
1447
|
+
f"Exception message: {ex}"
|
1448
|
+
)
|
1449
|
+
|
1450
|
+
def load_evaluation_config(
|
1451
|
+
self, container: Optional[str] = DEFAULT_EVALUATION_CONTAINER
|
1452
|
+
) -> Dict:
|
1453
|
+
"""Loads evaluation config."""
|
1454
|
+
|
1455
|
+
logger.info("Loading evaluation container config.")
|
1456
|
+
# retrieve the evaluation config by container family name
|
1457
|
+
containers = self.list_service_containers()
|
1458
|
+
container_item = next(
|
1459
|
+
c for c in containers if c.is_latest and c.family_name == container
|
1460
|
+
)
|
1461
|
+
evaluation_config = EvaluationServiceConfig.from_oci_container_config(
|
1462
|
+
container_item
|
1463
|
+
)
|
1464
|
+
|
1465
|
+
# convert the new config representation to the old one
|
1466
|
+
return {
|
1467
|
+
"model_params": evaluation_config.ui_config.model_params.default,
|
1468
|
+
"shape": {
|
1469
|
+
shape.name: shape.to_dict()
|
1470
|
+
for shape in evaluation_config.ui_config.shapes
|
1471
|
+
},
|
1472
|
+
"default": (
|
1473
|
+
evaluation_config.ui_config.shapes[0].to_dict()
|
1474
|
+
if len(evaluation_config.ui_config.shapes) > 0
|
1475
|
+
else {}
|
1476
|
+
),
|
1477
|
+
}
|
1478
|
+
|
1479
|
+
def _get_attribute_from_model_metadata(
|
1480
|
+
self,
|
1481
|
+
model: oci.resource_search.models.ResourceSummary,
|
1482
|
+
target_attribute: str,
|
1483
|
+
) -> str:
|
1484
|
+
try:
|
1485
|
+
return self._extract_metadata(
|
1486
|
+
model.additional_details.get(RqsAdditionalDetails.METADATA),
|
1487
|
+
target_attribute,
|
1488
|
+
)
|
1489
|
+
except Exception:
|
1490
|
+
logger.debug(
|
1491
|
+
f"Missing `{target_attribute}` in custom metadata of the evaluation."
|
1492
|
+
f"Evaluation id: {model.identifier} "
|
1493
|
+
)
|
1494
|
+
return ""
|
1495
|
+
|
1496
|
+
def _extract_metadata(self, metadata_list: List[Dict], key: str) -> Any:
|
1497
|
+
for metadata in metadata_list:
|
1498
|
+
if metadata.get("key") == key:
|
1499
|
+
return metadata.get("value")
|
1500
|
+
raise AquaMissingKeyError(
|
1501
|
+
f"Missing `{key}` in custom metadata of the evaluation."
|
1502
|
+
)
|
1503
|
+
|
1504
|
+
def _get_source(
|
1505
|
+
self,
|
1506
|
+
evaluation: oci.resource_search.models.ResourceSummary,
|
1507
|
+
resources_mapping: dict = None,
|
1508
|
+
) -> tuple:
|
1509
|
+
"""Returns ocid and name of the model has been evaluated."""
|
1510
|
+
source_id = self._get_attribute_from_model_metadata(
|
1511
|
+
evaluation,
|
1512
|
+
EvaluationCustomMetadata.EVALUATION_SOURCE,
|
1513
|
+
)
|
1514
|
+
|
1515
|
+
try:
|
1516
|
+
source_name = None
|
1517
|
+
if resources_mapping:
|
1518
|
+
source = resources_mapping.get(source_id)
|
1519
|
+
source_name = (
|
1520
|
+
source.display_name
|
1521
|
+
if source
|
1522
|
+
else self._get_attribute_from_model_metadata(
|
1523
|
+
evaluation, EvaluationCustomMetadata.EVALUATION_SOURCE_NAME
|
1524
|
+
)
|
1525
|
+
)
|
1526
|
+
|
1527
|
+
# try to resolve source_name from source id
|
1528
|
+
if source_id and not source_name:
|
1529
|
+
resource_type = utils.get_resource_type(source_id)
|
1530
|
+
|
1531
|
+
if resource_type.startswith("datasciencemodeldeployment"):
|
1532
|
+
source_name = self.ds_client.get_model_deployment(
|
1533
|
+
source_id
|
1534
|
+
).data.display_name
|
1535
|
+
elif resource_type.startswith("datasciencemodel"):
|
1536
|
+
source_name = self.ds_client.get_model(source_id).data.display_name
|
1537
|
+
else:
|
1538
|
+
raise AquaRuntimeError(
|
1539
|
+
f"Not supported source type: {resource_type}"
|
1540
|
+
)
|
1541
|
+
except Exception as ex:
|
1542
|
+
logger.debug(
|
1543
|
+
f"Failed to retrieve source information for evaluation {evaluation.identifier}.\nError: {str(ex)}"
|
1544
|
+
)
|
1545
|
+
source_name = ""
|
1546
|
+
|
1547
|
+
return source_id, source_name
|
1548
|
+
|
1549
|
+
def _get_experiment_info(
|
1550
|
+
self, model: oci.resource_search.models.ResourceSummary
|
1551
|
+
) -> tuple:
|
1552
|
+
"""Returns ocid and name of the experiment."""
|
1553
|
+
return (
|
1554
|
+
model.additional_details.get(RqsAdditionalDetails.MODEL_VERSION_SET_ID),
|
1555
|
+
model.additional_details.get(RqsAdditionalDetails.MODEL_VERSION_SET_NAME),
|
1556
|
+
)
|
1557
|
+
|
1558
|
+
def _process(
|
1559
|
+
self,
|
1560
|
+
model: oci.resource_search.models.ResourceSummary,
|
1561
|
+
resources_mapping: dict = None,
|
1562
|
+
) -> dict:
|
1563
|
+
"""Constructs AquaEvaluationSummary from `oci.resource_search.models.ResourceSummary`."""
|
1564
|
+
|
1565
|
+
tags = {}
|
1566
|
+
tags.update(model.defined_tags or {})
|
1567
|
+
tags.update(model.freeform_tags or {})
|
1568
|
+
|
1569
|
+
model_id = model.identifier
|
1570
|
+
console_url = get_console_link(
|
1571
|
+
resource="models",
|
1572
|
+
ocid=model_id,
|
1573
|
+
region=self.region,
|
1574
|
+
)
|
1575
|
+
source_model_id, source_model_name = self._get_source(
|
1576
|
+
model, resources_mapping if resources_mapping else {}
|
1577
|
+
)
|
1578
|
+
experiment_id, experiment_name = self._get_experiment_info(model)
|
1579
|
+
parameters = self._fetch_runtime_params(model)
|
1580
|
+
|
1581
|
+
return {
|
1582
|
+
"id": model_id,
|
1583
|
+
"name": model.display_name,
|
1584
|
+
"console_url": console_url,
|
1585
|
+
"time_created": str(model.time_created),
|
1586
|
+
"tags": tags,
|
1587
|
+
"experiment": self._build_resource_identifier(
|
1588
|
+
id=experiment_id,
|
1589
|
+
name=experiment_name,
|
1590
|
+
),
|
1591
|
+
"source": self._build_resource_identifier(
|
1592
|
+
id=source_model_id, name=source_model_name
|
1593
|
+
),
|
1594
|
+
"parameters": parameters,
|
1595
|
+
}
|
1596
|
+
|
1597
|
+
def _build_resource_identifier(
|
1598
|
+
self, id: str = None, name: str = None
|
1599
|
+
) -> AquaResourceIdentifier:
|
1600
|
+
"""Constructs AquaResourceIdentifier based on the given ocid and display name."""
|
1601
|
+
try:
|
1602
|
+
resource_type = CONSOLE_LINK_RESOURCE_TYPE_MAPPING.get(
|
1603
|
+
utils.get_resource_type(id)
|
1604
|
+
)
|
1605
|
+
|
1606
|
+
return AquaResourceIdentifier(
|
1607
|
+
id=id,
|
1608
|
+
name=name,
|
1609
|
+
url=get_console_link(
|
1610
|
+
resource=resource_type,
|
1611
|
+
ocid=id,
|
1612
|
+
region=self.region,
|
1613
|
+
),
|
1614
|
+
)
|
1615
|
+
except Exception as e:
|
1616
|
+
logger.debug(
|
1617
|
+
f"Failed to construct AquaResourceIdentifier from given id=`{id}`, and name=`{name}`. "
|
1618
|
+
f"DEBUG INFO: {str(e)}"
|
1619
|
+
)
|
1620
|
+
return AquaResourceIdentifier()
|
1621
|
+
|
1622
|
+
def _fetch_jobrun(
|
1623
|
+
self,
|
1624
|
+
resource: oci.resource_search.models.ResourceSummary,
|
1625
|
+
use_rqs: bool = True,
|
1626
|
+
jobrun_id: str = None,
|
1627
|
+
) -> Union[
|
1628
|
+
oci.resource_search.models.ResourceSummary, oci.data_science.models.JobRun
|
1629
|
+
]:
|
1630
|
+
"""Extracts job run id from metadata, and gets related job run information."""
|
1631
|
+
|
1632
|
+
jobrun_id = jobrun_id or self._get_attribute_from_model_metadata(
|
1633
|
+
resource, EvaluationCustomMetadata.EVALUATION_JOB_RUN_ID
|
1634
|
+
)
|
1635
|
+
|
1636
|
+
logger.info(f"Fetching associated job run: {jobrun_id}")
|
1637
|
+
|
1638
|
+
try:
|
1639
|
+
jobrun = (
|
1640
|
+
utils.query_resource(jobrun_id, return_all=False)
|
1641
|
+
if use_rqs
|
1642
|
+
else self.ds_client.get_job_run(jobrun_id).data
|
1643
|
+
)
|
1644
|
+
except Exception as e:
|
1645
|
+
logger.debug(
|
1646
|
+
f"Failed to retreive job run: {jobrun_id}. DEBUG INFO: {str(e)}"
|
1647
|
+
)
|
1648
|
+
jobrun = None
|
1649
|
+
|
1650
|
+
return jobrun
|
1651
|
+
|
1652
|
+
def _fetch_runtime_params(
|
1653
|
+
self, resource: oci.resource_search.models.ResourceSummary
|
1654
|
+
) -> AquaEvalParams:
|
1655
|
+
"""Extracts model parameters from metadata. Shape is the shape used in job run."""
|
1656
|
+
try:
|
1657
|
+
params = json.loads(
|
1658
|
+
self._get_attribute_from_model_metadata(
|
1659
|
+
resource, MetadataTaxonomyKeys.HYPERPARAMETERS
|
1660
|
+
)
|
1661
|
+
)
|
1662
|
+
if not params.get(EvaluationConfig.PARAMS):
|
1663
|
+
raise AquaMissingKeyError(
|
1664
|
+
"model parameters have not been saved in correct format in model taxonomy. ",
|
1665
|
+
service_payload={"params": params},
|
1666
|
+
)
|
1667
|
+
|
1668
|
+
return AquaEvalParams(**params[EvaluationConfig.PARAMS])
|
1669
|
+
except Exception as e:
|
1670
|
+
logger.debug(
|
1671
|
+
f"Failed to retrieve model parameters for the model: {str(resource)}."
|
1672
|
+
f"DEBUG INFO: {str(e)}."
|
1673
|
+
)
|
1674
|
+
return AquaEvalParams()
|
1675
|
+
|
1676
|
+
def _build_job_identifier(
|
1677
|
+
self,
|
1678
|
+
job_run_details: Union[
|
1679
|
+
oci.data_science.models.JobRun, oci.resource_search.models.ResourceSummary
|
1680
|
+
] = None,
|
1681
|
+
) -> AquaResourceIdentifier:
|
1682
|
+
try:
|
1683
|
+
job_id = (
|
1684
|
+
job_run_details.id
|
1685
|
+
if isinstance(job_run_details, oci.data_science.models.JobRun)
|
1686
|
+
else job_run_details.identifier
|
1687
|
+
)
|
1688
|
+
return self._build_resource_identifier(
|
1689
|
+
id=job_id, name=job_run_details.display_name
|
1690
|
+
)
|
1691
|
+
|
1692
|
+
except Exception as e:
|
1693
|
+
logger.debug(
|
1694
|
+
f"Failed to get job details from job_run_details: {job_run_details} "
|
1695
|
+
f"DEBUG INFO:{str(e)}"
|
1696
|
+
)
|
1697
|
+
return AquaResourceIdentifier()
|
1698
|
+
|
1699
|
+
def _get_status(
|
1700
|
+
self,
|
1701
|
+
model: oci.resource_search.models.ResourceSummary,
|
1702
|
+
jobrun: Union[
|
1703
|
+
oci.resource_search.models.ResourceSummary, oci.data_science.models.JobRun
|
1704
|
+
] = None,
|
1705
|
+
) -> dict:
|
1706
|
+
"""Builds evaluation status based on the model status and job run status.
|
1707
|
+
When missing jobrun information, the status will be decided based on:
|
1708
|
+
|
1709
|
+
* If the evaluation just has been deleted, the jobrun status should be deleted.
|
1710
|
+
* When detect `aqua_evaluation_error` in custom metadata, the jobrun is failed.
|
1711
|
+
* If jobrun failed before saving this meta, we need to check the existance
|
1712
|
+
of the evaluation artifact.
|
1713
|
+
|
1714
|
+
"""
|
1715
|
+
model_status = model.lifecycle_state
|
1716
|
+
job_run_status = None
|
1717
|
+
|
1718
|
+
if jobrun:
|
1719
|
+
job_run_status = jobrun.lifecycle_state
|
1720
|
+
|
1721
|
+
if jobrun is None:
|
1722
|
+
if model.identifier in self._deletion_cache:
|
1723
|
+
job_run_status = JobRun.LIFECYCLE_STATE_DELETED
|
1724
|
+
|
1725
|
+
elif self._get_attribute_from_model_metadata(
|
1726
|
+
model, EvaluationCustomMetadata.EVALUATION_ERROR
|
1727
|
+
):
|
1728
|
+
job_run_status = JobRun.LIFECYCLE_STATE_FAILED
|
1729
|
+
|
1730
|
+
elif self._if_eval_artifact_exist(model):
|
1731
|
+
job_run_status = JobRun.LIFECYCLE_STATE_SUCCEEDED
|
1732
|
+
else:
|
1733
|
+
job_run_status = JobRun.LIFECYCLE_STATE_FAILED
|
1734
|
+
|
1735
|
+
lifecycle_state = utils.LifecycleStatus.get_status(
|
1736
|
+
evaluation_status=model_status, job_run_status=job_run_status
|
1737
|
+
)
|
1738
|
+
|
1739
|
+
try:
|
1740
|
+
lifecycle_details = (
|
1741
|
+
LIFECYCLE_DETAILS_MISSING_JOBRUN
|
1742
|
+
if not jobrun
|
1743
|
+
else self._extract_job_lifecycle_details(jobrun.lifecycle_details)
|
1744
|
+
)
|
1745
|
+
except Exception:
|
1746
|
+
# ResourceSummary does not have lifecycle_details attr
|
1747
|
+
lifecycle_details = ""
|
1748
|
+
|
1749
|
+
return {
|
1750
|
+
"lifecycle_state": (
|
1751
|
+
lifecycle_state if isinstance(lifecycle_state, str) else lifecycle_state
|
1752
|
+
),
|
1753
|
+
"lifecycle_details": lifecycle_details,
|
1754
|
+
}
|
1755
|
+
|
1756
|
+
def _prefetch_resources(self, compartment_id) -> dict:
|
1757
|
+
"""Fetches all AQUA resources."""
|
1758
|
+
resources = utils.query_resources(
|
1759
|
+
compartment_id=compartment_id,
|
1760
|
+
resource_type="all",
|
1761
|
+
tag_list=[Tags.AQUA_EVALUATION, "OCI_AQUA"],
|
1762
|
+
connect_by_ampersands=False,
|
1763
|
+
return_all=False,
|
1764
|
+
)
|
1765
|
+
logger.debug(f"Fetched {len(resources)} AQUA resources.")
|
1766
|
+
return {item.identifier: item for item in resources}
|
1767
|
+
|
1768
|
+
def _extract_job_lifecycle_details(self, lifecycle_details: str) -> str:
|
1769
|
+
"""
|
1770
|
+
Extracts the exit code from a job lifecycle detail string and associates it
|
1771
|
+
with a corresponding message from the EVALUATION_JOB_EXIT_CODE_MESSAGE dictionary.
|
1772
|
+
|
1773
|
+
This method searches the provided lifecycle detail string for an exit code pattern.
|
1774
|
+
Upon finding an exit code, it retrieves the related human-readable message
|
1775
|
+
from a predefined dictionary of exit codes and their meanings. If the exit code
|
1776
|
+
is not found within the string, or if it does not exist in the dictionary,
|
1777
|
+
the original `lifecycle_details` message will be returned.
|
1778
|
+
|
1779
|
+
Parameters
|
1780
|
+
----------
|
1781
|
+
lifecycle_details : str
|
1782
|
+
A string containing the details of the job's lifecycle, typically including an exit code.
|
1783
|
+
|
1784
|
+
Returns
|
1785
|
+
-------
|
1786
|
+
str
|
1787
|
+
A message that combines the extracted exit code with its corresponding descriptive text.
|
1788
|
+
If no exit code is found, or if the exit code is not in the dictionary,
|
1789
|
+
the original `lifecycle_details` message will be returned.
|
1790
|
+
|
1791
|
+
Examples
|
1792
|
+
--------
|
1793
|
+
>>> _extract_job_lifecycle_details("Job run artifact execution failed with exit code 16")
|
1794
|
+
'Validation errors in the evaluation config. Exit code: 16.'
|
1795
|
+
|
1796
|
+
>>> _extract_job_lifecycle_details("Job completed successfully.")
|
1797
|
+
'Job completed successfully.'
|
1798
|
+
"""
|
1799
|
+
if not lifecycle_details:
|
1800
|
+
return lifecycle_details
|
1801
|
+
|
1802
|
+
message = lifecycle_details
|
1803
|
+
try:
|
1804
|
+
# Extract exit code
|
1805
|
+
match = re.search(r"exit code (\d+)", lifecycle_details)
|
1806
|
+
if match:
|
1807
|
+
exit_code = int(match.group(1))
|
1808
|
+
exit_code_message = EVALUATION_JOB_EXIT_CODE_MESSAGE.get(exit_code)
|
1809
|
+
if exit_code_message:
|
1810
|
+
message = f"{exit_code_message} Exit code: {exit_code}."
|
1811
|
+
except Exception:
|
1812
|
+
pass
|
1813
|
+
|
1814
|
+
return message
|