mlrun 1.7.0rc4__py3-none-any.whl → 1.7.2__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.
Potentially problematic release.
This version of mlrun might be problematic. Click here for more details.
- mlrun/__init__.py +11 -1
- mlrun/__main__.py +39 -121
- mlrun/{datastore/helpers.py → alerts/__init__.py} +2 -5
- mlrun/alerts/alert.py +248 -0
- mlrun/api/schemas/__init__.py +4 -3
- mlrun/artifacts/__init__.py +8 -3
- mlrun/artifacts/base.py +39 -254
- mlrun/artifacts/dataset.py +9 -190
- mlrun/artifacts/manager.py +73 -46
- mlrun/artifacts/model.py +30 -158
- mlrun/artifacts/plots.py +23 -380
- mlrun/common/constants.py +73 -1
- mlrun/common/db/sql_session.py +3 -2
- mlrun/common/formatters/__init__.py +21 -0
- mlrun/common/formatters/artifact.py +46 -0
- mlrun/common/formatters/base.py +113 -0
- mlrun/common/formatters/feature_set.py +44 -0
- mlrun/common/formatters/function.py +46 -0
- mlrun/common/formatters/pipeline.py +53 -0
- mlrun/common/formatters/project.py +51 -0
- mlrun/common/formatters/run.py +29 -0
- mlrun/common/helpers.py +11 -1
- mlrun/{runtimes → common/runtimes}/constants.py +32 -4
- mlrun/common/schemas/__init__.py +31 -4
- mlrun/common/schemas/alert.py +202 -0
- mlrun/common/schemas/api_gateway.py +196 -0
- mlrun/common/schemas/artifact.py +28 -1
- mlrun/common/schemas/auth.py +13 -2
- mlrun/common/schemas/client_spec.py +2 -1
- mlrun/common/schemas/common.py +7 -4
- mlrun/common/schemas/constants.py +3 -0
- mlrun/common/schemas/feature_store.py +58 -28
- mlrun/common/schemas/frontend_spec.py +8 -0
- mlrun/common/schemas/function.py +11 -0
- mlrun/common/schemas/hub.py +7 -9
- mlrun/common/schemas/model_monitoring/__init__.py +21 -4
- mlrun/common/schemas/model_monitoring/constants.py +136 -42
- mlrun/common/schemas/model_monitoring/grafana.py +9 -5
- mlrun/common/schemas/model_monitoring/model_endpoints.py +89 -41
- mlrun/common/schemas/notification.py +69 -12
- mlrun/{runtimes/mpijob/v1alpha1.py → common/schemas/pagination.py} +10 -13
- mlrun/common/schemas/pipeline.py +7 -0
- mlrun/common/schemas/project.py +67 -16
- mlrun/common/schemas/runs.py +17 -0
- mlrun/common/schemas/schedule.py +1 -1
- mlrun/common/schemas/workflow.py +10 -2
- mlrun/common/types.py +14 -1
- mlrun/config.py +233 -58
- mlrun/data_types/data_types.py +11 -1
- mlrun/data_types/spark.py +5 -4
- mlrun/data_types/to_pandas.py +75 -34
- mlrun/datastore/__init__.py +8 -10
- mlrun/datastore/alibaba_oss.py +131 -0
- mlrun/datastore/azure_blob.py +131 -43
- mlrun/datastore/base.py +107 -47
- mlrun/datastore/datastore.py +17 -7
- mlrun/datastore/datastore_profile.py +91 -7
- mlrun/datastore/dbfs_store.py +3 -7
- mlrun/datastore/filestore.py +1 -3
- mlrun/datastore/google_cloud_storage.py +92 -32
- mlrun/datastore/hdfs.py +5 -0
- mlrun/datastore/inmem.py +6 -3
- mlrun/datastore/redis.py +3 -2
- mlrun/datastore/s3.py +30 -12
- mlrun/datastore/snowflake_utils.py +45 -0
- mlrun/datastore/sources.py +274 -59
- mlrun/datastore/spark_utils.py +30 -0
- mlrun/datastore/store_resources.py +9 -7
- mlrun/datastore/storeytargets.py +151 -0
- mlrun/datastore/targets.py +387 -119
- mlrun/datastore/utils.py +68 -5
- mlrun/datastore/v3io.py +28 -50
- mlrun/db/auth_utils.py +152 -0
- mlrun/db/base.py +245 -20
- mlrun/db/factory.py +1 -4
- mlrun/db/httpdb.py +909 -231
- mlrun/db/nopdb.py +279 -14
- mlrun/errors.py +35 -5
- mlrun/execution.py +111 -38
- mlrun/feature_store/__init__.py +0 -2
- mlrun/feature_store/api.py +46 -53
- mlrun/feature_store/common.py +6 -11
- mlrun/feature_store/feature_set.py +48 -23
- mlrun/feature_store/feature_vector.py +13 -2
- mlrun/feature_store/ingestion.py +7 -6
- mlrun/feature_store/retrieval/base.py +9 -4
- mlrun/feature_store/retrieval/dask_merger.py +2 -0
- mlrun/feature_store/retrieval/job.py +13 -4
- mlrun/feature_store/retrieval/local_merger.py +2 -0
- mlrun/feature_store/retrieval/spark_merger.py +24 -32
- mlrun/feature_store/steps.py +38 -19
- mlrun/features.py +6 -14
- mlrun/frameworks/_common/plan.py +3 -3
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +7 -12
- mlrun/frameworks/_ml_common/plan.py +1 -1
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +2 -2
- mlrun/frameworks/lgbm/__init__.py +1 -1
- mlrun/frameworks/lgbm/callbacks/callback.py +2 -4
- mlrun/frameworks/lgbm/model_handler.py +1 -1
- mlrun/frameworks/parallel_coordinates.py +4 -4
- mlrun/frameworks/pytorch/__init__.py +2 -2
- mlrun/frameworks/sklearn/__init__.py +1 -1
- mlrun/frameworks/sklearn/mlrun_interface.py +13 -3
- mlrun/frameworks/tf_keras/__init__.py +5 -2
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +1 -1
- mlrun/frameworks/tf_keras/mlrun_interface.py +2 -2
- mlrun/frameworks/xgboost/__init__.py +1 -1
- mlrun/k8s_utils.py +57 -12
- mlrun/launcher/__init__.py +1 -1
- mlrun/launcher/base.py +6 -5
- mlrun/launcher/client.py +13 -11
- mlrun/launcher/factory.py +1 -1
- mlrun/launcher/local.py +15 -5
- mlrun/launcher/remote.py +10 -3
- mlrun/lists.py +6 -2
- mlrun/model.py +297 -48
- mlrun/model_monitoring/__init__.py +1 -1
- mlrun/model_monitoring/api.py +152 -357
- mlrun/model_monitoring/applications/__init__.py +10 -0
- mlrun/model_monitoring/applications/_application_steps.py +190 -0
- mlrun/model_monitoring/applications/base.py +108 -0
- mlrun/model_monitoring/applications/context.py +341 -0
- mlrun/model_monitoring/{evidently_application.py → applications/evidently_base.py} +27 -22
- mlrun/model_monitoring/applications/histogram_data_drift.py +227 -91
- mlrun/model_monitoring/applications/results.py +99 -0
- mlrun/model_monitoring/controller.py +130 -303
- mlrun/model_monitoring/{stores/models/sqlite.py → db/__init__.py} +5 -10
- mlrun/model_monitoring/db/stores/__init__.py +136 -0
- mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
- mlrun/model_monitoring/db/stores/base/store.py +213 -0
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +190 -0
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +103 -0
- mlrun/model_monitoring/{stores/models/mysql.py → db/stores/sqldb/models/sqlite.py} +19 -13
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +659 -0
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +726 -0
- mlrun/model_monitoring/db/tsdb/__init__.py +105 -0
- mlrun/model_monitoring/db/tsdb/base.py +448 -0
- mlrun/model_monitoring/db/tsdb/helpers.py +30 -0
- mlrun/model_monitoring/db/tsdb/tdengine/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +298 -0
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +42 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +522 -0
- mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +158 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +849 -0
- mlrun/model_monitoring/features_drift_table.py +34 -22
- mlrun/model_monitoring/helpers.py +177 -39
- mlrun/model_monitoring/model_endpoint.py +3 -2
- mlrun/model_monitoring/stream_processing.py +165 -398
- mlrun/model_monitoring/tracking_policy.py +7 -1
- mlrun/model_monitoring/writer.py +161 -125
- mlrun/package/packagers/default_packager.py +2 -2
- mlrun/package/packagers_manager.py +1 -0
- mlrun/package/utils/_formatter.py +2 -2
- mlrun/platforms/__init__.py +11 -10
- mlrun/platforms/iguazio.py +67 -228
- mlrun/projects/__init__.py +6 -1
- mlrun/projects/operations.py +47 -20
- mlrun/projects/pipelines.py +396 -249
- mlrun/projects/project.py +1176 -406
- mlrun/render.py +28 -22
- mlrun/run.py +208 -181
- mlrun/runtimes/__init__.py +76 -11
- mlrun/runtimes/base.py +54 -24
- mlrun/runtimes/daskjob.py +9 -2
- mlrun/runtimes/databricks_job/databricks_runtime.py +1 -0
- mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
- mlrun/runtimes/funcdoc.py +1 -29
- mlrun/runtimes/kubejob.py +34 -128
- mlrun/runtimes/local.py +39 -10
- mlrun/runtimes/mpijob/__init__.py +0 -20
- mlrun/runtimes/mpijob/abstract.py +8 -8
- mlrun/runtimes/mpijob/v1.py +1 -1
- mlrun/runtimes/nuclio/__init__.py +1 -0
- mlrun/runtimes/nuclio/api_gateway.py +769 -0
- mlrun/runtimes/nuclio/application/__init__.py +15 -0
- mlrun/runtimes/nuclio/application/application.py +758 -0
- mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
- mlrun/runtimes/nuclio/function.py +188 -68
- mlrun/runtimes/nuclio/serving.py +57 -60
- mlrun/runtimes/pod.py +191 -58
- mlrun/runtimes/remotesparkjob.py +11 -8
- mlrun/runtimes/sparkjob/spark3job.py +17 -18
- mlrun/runtimes/utils.py +40 -73
- mlrun/secrets.py +6 -2
- mlrun/serving/__init__.py +8 -1
- mlrun/serving/remote.py +2 -3
- mlrun/serving/routers.py +89 -64
- mlrun/serving/server.py +54 -26
- mlrun/serving/states.py +187 -56
- mlrun/serving/utils.py +19 -11
- mlrun/serving/v2_serving.py +136 -63
- mlrun/track/tracker.py +2 -1
- mlrun/track/trackers/mlflow_tracker.py +5 -0
- mlrun/utils/async_http.py +26 -6
- mlrun/utils/db.py +18 -0
- mlrun/utils/helpers.py +375 -105
- mlrun/utils/http.py +2 -2
- mlrun/utils/logger.py +75 -9
- mlrun/utils/notifications/notification/__init__.py +14 -10
- mlrun/utils/notifications/notification/base.py +48 -0
- mlrun/utils/notifications/notification/console.py +2 -0
- mlrun/utils/notifications/notification/git.py +24 -1
- mlrun/utils/notifications/notification/ipython.py +2 -0
- mlrun/utils/notifications/notification/slack.py +96 -21
- mlrun/utils/notifications/notification/webhook.py +63 -2
- mlrun/utils/notifications/notification_pusher.py +146 -16
- mlrun/utils/regex.py +9 -0
- mlrun/utils/retryer.py +3 -2
- mlrun/utils/v3io_clients.py +2 -3
- mlrun/utils/version/version.json +2 -2
- mlrun-1.7.2.dist-info/METADATA +390 -0
- mlrun-1.7.2.dist-info/RECORD +351 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.2.dist-info}/WHEEL +1 -1
- mlrun/feature_store/retrieval/conversion.py +0 -271
- mlrun/kfpops.py +0 -868
- mlrun/model_monitoring/application.py +0 -310
- mlrun/model_monitoring/batch.py +0 -974
- mlrun/model_monitoring/controller_handler.py +0 -37
- mlrun/model_monitoring/prometheus.py +0 -216
- mlrun/model_monitoring/stores/__init__.py +0 -111
- mlrun/model_monitoring/stores/kv_model_endpoint_store.py +0 -574
- mlrun/model_monitoring/stores/model_endpoint_store.py +0 -145
- mlrun/model_monitoring/stores/models/__init__.py +0 -27
- mlrun/model_monitoring/stores/models/base.py +0 -84
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -382
- mlrun/platforms/other.py +0 -305
- mlrun-1.7.0rc4.dist-info/METADATA +0 -269
- mlrun-1.7.0rc4.dist-info/RECORD +0 -321
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.2.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.2.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.2.dist-info}/top_level.txt +0 -0
mlrun/model_monitoring/api.py
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
import hashlib
|
|
16
|
-
import json
|
|
17
16
|
import typing
|
|
17
|
+
import warnings
|
|
18
18
|
from datetime import datetime
|
|
19
19
|
|
|
20
20
|
import numpy as np
|
|
@@ -22,13 +22,13 @@ import pandas as pd
|
|
|
22
22
|
|
|
23
23
|
import mlrun.artifacts
|
|
24
24
|
import mlrun.common.helpers
|
|
25
|
+
import mlrun.common.schemas.model_monitoring.constants as mm_constants
|
|
25
26
|
import mlrun.feature_store
|
|
26
|
-
|
|
27
|
+
import mlrun.model_monitoring.applications as mm_app
|
|
28
|
+
import mlrun.serving
|
|
27
29
|
from mlrun.data_types.infer import InferOptions, get_df_stats
|
|
28
30
|
from mlrun.utils import datetime_now, logger
|
|
29
31
|
|
|
30
|
-
from .batch import VirtualDrift
|
|
31
|
-
from .features_drift_table import FeaturesDriftTablePlot
|
|
32
32
|
from .helpers import update_model_endpoint_last_request
|
|
33
33
|
from .model_endpoint import ModelEndpoint
|
|
34
34
|
|
|
@@ -46,9 +46,9 @@ def get_or_create_model_endpoint(
|
|
|
46
46
|
function_name: str = "",
|
|
47
47
|
context: mlrun.MLClientCtx = None,
|
|
48
48
|
sample_set_statistics: dict[str, typing.Any] = None,
|
|
49
|
-
drift_threshold: float = None,
|
|
50
|
-
possible_drift_threshold: float = None,
|
|
51
|
-
monitoring_mode: ModelMonitoringMode = ModelMonitoringMode.disabled,
|
|
49
|
+
drift_threshold: typing.Optional[float] = None,
|
|
50
|
+
possible_drift_threshold: typing.Optional[float] = None,
|
|
51
|
+
monitoring_mode: mm_constants.ModelMonitoringMode = mm_constants.ModelMonitoringMode.disabled,
|
|
52
52
|
db_session=None,
|
|
53
53
|
) -> ModelEndpoint:
|
|
54
54
|
"""
|
|
@@ -68,14 +68,14 @@ def get_or_create_model_endpoint(
|
|
|
68
68
|
full function hash.
|
|
69
69
|
:param sample_set_statistics: Dictionary of sample set statistics that will be used as a reference data for
|
|
70
70
|
the new model endpoint (applicable only to new endpoint_id).
|
|
71
|
-
:param drift_threshold: The threshold of which to mark drifts (applicable only to new
|
|
72
|
-
|
|
71
|
+
:param drift_threshold: (deprecated) The threshold of which to mark drifts (applicable only to new
|
|
72
|
+
endpoint_id).
|
|
73
|
+
:param possible_drift_threshold: (deprecated) The threshold of which to mark possible drifts (applicable only to new
|
|
73
74
|
endpoint_id).
|
|
74
75
|
:param monitoring_mode: If enabled, apply model monitoring features on the provided endpoint id
|
|
75
76
|
(applicable only to new endpoint_id).
|
|
76
77
|
:param db_session: A runtime session that manages the current dialog with the database.
|
|
77
78
|
|
|
78
|
-
|
|
79
79
|
:return: A ModelEndpoint object
|
|
80
80
|
"""
|
|
81
81
|
|
|
@@ -97,8 +97,6 @@ def get_or_create_model_endpoint(
|
|
|
97
97
|
model_endpoint=model_endpoint,
|
|
98
98
|
model_path=model_path,
|
|
99
99
|
sample_set_statistics=sample_set_statistics,
|
|
100
|
-
drift_threshold=drift_threshold,
|
|
101
|
-
possible_drift_threshold=possible_drift_threshold,
|
|
102
100
|
)
|
|
103
101
|
|
|
104
102
|
except mlrun.errors.MLRunNotFoundError:
|
|
@@ -112,8 +110,6 @@ def get_or_create_model_endpoint(
|
|
|
112
110
|
function_name=function_name,
|
|
113
111
|
context=context,
|
|
114
112
|
sample_set_statistics=sample_set_statistics,
|
|
115
|
-
drift_threshold=drift_threshold,
|
|
116
|
-
possible_drift_threshold=possible_drift_threshold,
|
|
117
113
|
monitoring_mode=monitoring_mode,
|
|
118
114
|
)
|
|
119
115
|
return model_endpoint
|
|
@@ -128,20 +124,19 @@ def record_results(
|
|
|
128
124
|
context: typing.Optional[mlrun.MLClientCtx] = None,
|
|
129
125
|
infer_results_df: typing.Optional[pd.DataFrame] = None,
|
|
130
126
|
sample_set_statistics: typing.Optional[dict[str, typing.Any]] = None,
|
|
131
|
-
monitoring_mode: ModelMonitoringMode = ModelMonitoringMode.enabled,
|
|
127
|
+
monitoring_mode: mm_constants.ModelMonitoringMode = mm_constants.ModelMonitoringMode.enabled,
|
|
128
|
+
# Deprecated arguments:
|
|
132
129
|
drift_threshold: typing.Optional[float] = None,
|
|
133
130
|
possible_drift_threshold: typing.Optional[float] = None,
|
|
134
131
|
trigger_monitoring_job: bool = False,
|
|
135
132
|
artifacts_tag: str = "",
|
|
136
|
-
default_batch_image="mlrun/mlrun",
|
|
133
|
+
default_batch_image: str = "mlrun/mlrun",
|
|
137
134
|
) -> ModelEndpoint:
|
|
138
135
|
"""
|
|
139
136
|
Write a provided inference dataset to model endpoint parquet target. If not exist, generate a new model endpoint
|
|
140
137
|
record and use the provided sample set statistics as feature stats that will be used later for the drift analysis.
|
|
141
|
-
To
|
|
142
|
-
|
|
143
|
-
input data (along with the outputs). The drift rule is the value per-feature mean of the TVD and Hellinger scores
|
|
144
|
-
according to the provided thresholds.
|
|
138
|
+
To activate model monitoring, run `project.enable_model_monitoring()`. The model monitoring applications will be
|
|
139
|
+
triggered with the recorded data according to a periodic schedule.
|
|
145
140
|
|
|
146
141
|
:param project: Project name.
|
|
147
142
|
:param model_path: The model Store path.
|
|
@@ -151,8 +146,7 @@ def record_results(
|
|
|
151
146
|
on the provided `endpoint_id`.
|
|
152
147
|
:param function_name: If a new model endpoint is created, use this function name for generating the
|
|
153
148
|
function URI.
|
|
154
|
-
:param context: MLRun context. Note that the context is required
|
|
155
|
-
following the batch drift job.
|
|
149
|
+
:param context: MLRun context. Note that the context is required generating the model endpoint.
|
|
156
150
|
:param infer_results_df: DataFrame that will be stored under the model endpoint parquet target. Will be
|
|
157
151
|
used for doing the drift analysis. Please make sure that the dataframe includes
|
|
158
152
|
both feature names and label columns.
|
|
@@ -160,17 +154,47 @@ def record_results(
|
|
|
160
154
|
the current model endpoint.
|
|
161
155
|
:param monitoring_mode: If enabled, apply model monitoring features on the provided endpoint id. Enabled
|
|
162
156
|
by default.
|
|
163
|
-
:param drift_threshold: The threshold of which to mark drifts.
|
|
164
|
-
:param possible_drift_threshold: The threshold of which to mark possible drifts.
|
|
165
|
-
:param trigger_monitoring_job: If true, run the batch drift job. If not exists, the monitoring
|
|
166
|
-
will be registered through MLRun API with the provided image.
|
|
167
|
-
:param artifacts_tag: Tag to use for all the artifacts resulted from the function.
|
|
168
|
-
only if the monitoring batch job has been triggered.
|
|
169
|
-
|
|
170
|
-
|
|
157
|
+
:param drift_threshold: (deprecated) The threshold of which to mark drifts.
|
|
158
|
+
:param possible_drift_threshold: (deprecated) The threshold of which to mark possible drifts.
|
|
159
|
+
:param trigger_monitoring_job: (deprecated) If true, run the batch drift job. If not exists, the monitoring
|
|
160
|
+
batch function will be registered through MLRun API with the provided image.
|
|
161
|
+
:param artifacts_tag: (deprecated) Tag to use for all the artifacts resulted from the function.
|
|
162
|
+
Will be relevant only if the monitoring batch job has been triggered.
|
|
163
|
+
:param default_batch_image: (deprecated) The image that will be used when registering the model monitoring
|
|
164
|
+
batch job.
|
|
171
165
|
|
|
172
166
|
:return: A ModelEndpoint object
|
|
173
167
|
"""
|
|
168
|
+
|
|
169
|
+
if drift_threshold is not None or possible_drift_threshold is not None:
|
|
170
|
+
warnings.warn(
|
|
171
|
+
"Custom drift threshold arguments are deprecated since version "
|
|
172
|
+
"1.7.0 and have no effect. They will be removed in version 1.9.0.\n"
|
|
173
|
+
"To enable the default histogram data drift application, run:\n"
|
|
174
|
+
"`project.enable_model_monitoring()`.",
|
|
175
|
+
FutureWarning,
|
|
176
|
+
)
|
|
177
|
+
if trigger_monitoring_job is not False:
|
|
178
|
+
warnings.warn(
|
|
179
|
+
"`trigger_monitoring_job` argument is deprecated since version "
|
|
180
|
+
"1.7.0 and has no effect. It will be removed in version 1.9.0.\n"
|
|
181
|
+
"To enable the default histogram data drift application, run:\n"
|
|
182
|
+
"`project.enable_model_monitoring()`.",
|
|
183
|
+
FutureWarning,
|
|
184
|
+
)
|
|
185
|
+
if artifacts_tag != "":
|
|
186
|
+
warnings.warn(
|
|
187
|
+
"`artifacts_tag` argument is deprecated since version "
|
|
188
|
+
"1.7.0 and has no effect. It will be removed in version 1.9.0.",
|
|
189
|
+
FutureWarning,
|
|
190
|
+
)
|
|
191
|
+
if default_batch_image != "mlrun/mlrun":
|
|
192
|
+
warnings.warn(
|
|
193
|
+
"`default_batch_image` argument is deprecated since version "
|
|
194
|
+
"1.7.0 and has no effect. It will be removed in version 1.9.0.",
|
|
195
|
+
FutureWarning,
|
|
196
|
+
)
|
|
197
|
+
|
|
174
198
|
db = mlrun.get_run_db()
|
|
175
199
|
|
|
176
200
|
model_endpoint = get_or_create_model_endpoint(
|
|
@@ -181,8 +205,6 @@ def record_results(
|
|
|
181
205
|
function_name=function_name,
|
|
182
206
|
context=context,
|
|
183
207
|
sample_set_statistics=sample_set_statistics,
|
|
184
|
-
drift_threshold=drift_threshold,
|
|
185
|
-
possible_drift_threshold=possible_drift_threshold,
|
|
186
208
|
monitoring_mode=monitoring_mode,
|
|
187
209
|
db_session=db,
|
|
188
210
|
)
|
|
@@ -206,33 +228,6 @@ def record_results(
|
|
|
206
228
|
db=db,
|
|
207
229
|
)
|
|
208
230
|
|
|
209
|
-
if trigger_monitoring_job:
|
|
210
|
-
# Run the monitoring batch drift job
|
|
211
|
-
trigger_drift_batch_job(
|
|
212
|
-
project=project,
|
|
213
|
-
default_batch_image=default_batch_image,
|
|
214
|
-
model_endpoints_ids=[model_endpoint.metadata.uid],
|
|
215
|
-
db_session=db,
|
|
216
|
-
)
|
|
217
|
-
|
|
218
|
-
# Getting drift thresholds if not provided
|
|
219
|
-
drift_threshold, possible_drift_threshold = get_drift_thresholds_if_not_none(
|
|
220
|
-
model_endpoint=model_endpoint,
|
|
221
|
-
drift_threshold=drift_threshold,
|
|
222
|
-
possible_drift_threshold=possible_drift_threshold,
|
|
223
|
-
)
|
|
224
|
-
|
|
225
|
-
perform_drift_analysis(
|
|
226
|
-
project=project,
|
|
227
|
-
context=context,
|
|
228
|
-
sample_set_statistics=model_endpoint.status.feature_stats,
|
|
229
|
-
drift_threshold=drift_threshold,
|
|
230
|
-
possible_drift_threshold=possible_drift_threshold,
|
|
231
|
-
artifacts_tag=artifacts_tag,
|
|
232
|
-
endpoint_id=model_endpoint.metadata.uid,
|
|
233
|
-
db_session=db,
|
|
234
|
-
)
|
|
235
|
-
|
|
236
231
|
return model_endpoint
|
|
237
232
|
|
|
238
233
|
|
|
@@ -240,9 +235,7 @@ def _model_endpoint_validations(
|
|
|
240
235
|
model_endpoint: ModelEndpoint,
|
|
241
236
|
model_path: str = "",
|
|
242
237
|
sample_set_statistics: dict[str, typing.Any] = None,
|
|
243
|
-
|
|
244
|
-
possible_drift_threshold: float = None,
|
|
245
|
-
):
|
|
238
|
+
) -> None:
|
|
246
239
|
"""
|
|
247
240
|
Validate that provided model endpoint configurations match the stored fields of the provided `ModelEndpoint`
|
|
248
241
|
object. Usually, this method is called by `get_or_create_model_endpoint()` in cases that the model endpoint
|
|
@@ -256,20 +249,32 @@ def _model_endpoint_validations(
|
|
|
256
249
|
is forbidden to provide a different reference data to that model endpoint.
|
|
257
250
|
In case of discrepancy between the provided `sample_set_statistics` and the
|
|
258
251
|
`model_endpoints.spec.feature_stats`, a warning will be presented to the user.
|
|
259
|
-
:param drift_threshold: The threshold of which to mark drifts. Should be similar to the drift threshold
|
|
260
|
-
that has already assigned to the current model endpoint.
|
|
261
|
-
:param possible_drift_threshold: The threshold of which to mark possible drifts. Should be similar to the possible
|
|
262
|
-
drift threshold that has already assigned to the current model endpoint.
|
|
263
|
-
|
|
264
252
|
"""
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
253
|
+
|
|
254
|
+
# Model Path
|
|
255
|
+
if model_path:
|
|
256
|
+
# Generate the parsed model uri that is based on hash, key, iter, and tree
|
|
257
|
+
model_obj = mlrun.datastore.get_store_resource(model_path)
|
|
258
|
+
|
|
259
|
+
model_artifact_uri = mlrun.utils.helpers.generate_artifact_uri(
|
|
260
|
+
project=model_endpoint.metadata.project,
|
|
261
|
+
key=model_obj.key,
|
|
262
|
+
iter=model_obj.iter,
|
|
263
|
+
tree=model_obj.tree,
|
|
271
264
|
)
|
|
272
265
|
|
|
266
|
+
# Enrich the uri schema with the store prefix
|
|
267
|
+
model_artifact_uri = mlrun.datastore.get_store_uri(
|
|
268
|
+
kind=mlrun.utils.helpers.StorePrefix.Model, uri=model_artifact_uri
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
if model_endpoint.spec.model_uri != model_artifact_uri:
|
|
272
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
273
|
+
f"provided model store path {model_path} does not match "
|
|
274
|
+
f"the path that is stored under the existing model "
|
|
275
|
+
f"endpoint record: {model_endpoint.spec.model_uri}"
|
|
276
|
+
)
|
|
277
|
+
|
|
273
278
|
# Feature stats
|
|
274
279
|
if (
|
|
275
280
|
sample_set_statistics
|
|
@@ -279,62 +284,6 @@ def _model_endpoint_validations(
|
|
|
279
284
|
"Provided sample set statistics is different from the registered statistics. "
|
|
280
285
|
"If new sample set statistics is to be used, new model endpoint should be created"
|
|
281
286
|
)
|
|
282
|
-
# drift and possible drift thresholds
|
|
283
|
-
if drift_threshold:
|
|
284
|
-
current_drift_threshold = model_endpoint.spec.monitor_configuration.get(
|
|
285
|
-
EventFieldType.DRIFT_DETECTED_THRESHOLD,
|
|
286
|
-
mlrun.mlconf.model_endpoint_monitoring.drift_thresholds.default.drift_detected,
|
|
287
|
-
)
|
|
288
|
-
if current_drift_threshold != drift_threshold:
|
|
289
|
-
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
290
|
-
f"Cannot change existing drift threshold. Expected {current_drift_threshold}, got {drift_threshold} "
|
|
291
|
-
f"Please update drift threshold or generate a new model endpoint record"
|
|
292
|
-
)
|
|
293
|
-
|
|
294
|
-
if possible_drift_threshold:
|
|
295
|
-
current_possible_drift_threshold = model_endpoint.spec.monitor_configuration.get(
|
|
296
|
-
EventFieldType.POSSIBLE_DRIFT_THRESHOLD,
|
|
297
|
-
mlrun.mlconf.model_endpoint_monitoring.drift_thresholds.default.possible_drift,
|
|
298
|
-
)
|
|
299
|
-
if current_possible_drift_threshold != possible_drift_threshold:
|
|
300
|
-
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
301
|
-
f"Cannot change existing possible drift threshold. Expected {current_possible_drift_threshold}, "
|
|
302
|
-
f"got {possible_drift_threshold}. Please update drift threshold or generate a new model endpoint record"
|
|
303
|
-
)
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
def get_drift_thresholds_if_not_none(
|
|
307
|
-
model_endpoint: ModelEndpoint,
|
|
308
|
-
drift_threshold: float = None,
|
|
309
|
-
possible_drift_threshold: float = None,
|
|
310
|
-
) -> tuple[float, float]:
|
|
311
|
-
"""
|
|
312
|
-
Get drift and possible drift thresholds. If one of the thresholds is missing, will try to retrieve
|
|
313
|
-
it from the `ModelEndpoint` object. If not defined under the `ModelEndpoint` as well, will retrieve it from
|
|
314
|
-
the default mlrun configuration.
|
|
315
|
-
|
|
316
|
-
:param model_endpoint: `ModelEndpoint` object.
|
|
317
|
-
:param drift_threshold: The threshold of which to mark drifts.
|
|
318
|
-
:param possible_drift_threshold: The threshold of which to mark possible drifts.
|
|
319
|
-
|
|
320
|
-
:return: A Tuple of:
|
|
321
|
-
[0] drift threshold as a float
|
|
322
|
-
[1] possible drift threshold as a float
|
|
323
|
-
"""
|
|
324
|
-
if not drift_threshold:
|
|
325
|
-
# Getting drift threshold value from either model endpoint or monitoring default configurations
|
|
326
|
-
drift_threshold = model_endpoint.spec.monitor_configuration.get(
|
|
327
|
-
EventFieldType.DRIFT_DETECTED_THRESHOLD,
|
|
328
|
-
mlrun.mlconf.model_endpoint_monitoring.drift_thresholds.default.drift_detected,
|
|
329
|
-
)
|
|
330
|
-
if not possible_drift_threshold:
|
|
331
|
-
# Getting possible drift threshold value from either model endpoint or monitoring default configurations
|
|
332
|
-
possible_drift_threshold = model_endpoint.spec.monitor_configuration.get(
|
|
333
|
-
EventFieldType.POSSIBLE_DRIFT_THRESHOLD,
|
|
334
|
-
mlrun.mlconf.model_endpoint_monitoring.drift_thresholds.default.possible_drift,
|
|
335
|
-
)
|
|
336
|
-
|
|
337
|
-
return drift_threshold, possible_drift_threshold
|
|
338
287
|
|
|
339
288
|
|
|
340
289
|
def write_monitoring_df(
|
|
@@ -366,14 +315,14 @@ def write_monitoring_df(
|
|
|
366
315
|
)
|
|
367
316
|
|
|
368
317
|
# Modify the DataFrame to the required structure that will be used later by the monitoring batch job
|
|
369
|
-
if EventFieldType.TIMESTAMP not in infer_results_df.columns:
|
|
318
|
+
if mm_constants.EventFieldType.TIMESTAMP not in infer_results_df.columns:
|
|
370
319
|
# Initialize timestamp column with the current time
|
|
371
|
-
infer_results_df[EventFieldType.TIMESTAMP] = infer_datetime
|
|
320
|
+
infer_results_df[mm_constants.EventFieldType.TIMESTAMP] = infer_datetime
|
|
372
321
|
|
|
373
322
|
# `endpoint_id` is the monitoring feature set entity and therefore it should be defined as the df index before
|
|
374
323
|
# the ingest process
|
|
375
|
-
infer_results_df[EventFieldType.ENDPOINT_ID] = endpoint_id
|
|
376
|
-
infer_results_df.set_index(EventFieldType.ENDPOINT_ID, inplace=True)
|
|
324
|
+
infer_results_df[mm_constants.EventFieldType.ENDPOINT_ID] = endpoint_id
|
|
325
|
+
infer_results_df.set_index(mm_constants.EventFieldType.ENDPOINT_ID, inplace=True)
|
|
377
326
|
|
|
378
327
|
monitoring_feature_set.ingest(source=infer_results_df, overwrite=False)
|
|
379
328
|
|
|
@@ -387,9 +336,7 @@ def _generate_model_endpoint(
|
|
|
387
336
|
function_name: str,
|
|
388
337
|
context: mlrun.MLClientCtx,
|
|
389
338
|
sample_set_statistics: dict[str, typing.Any],
|
|
390
|
-
|
|
391
|
-
possible_drift_threshold: float,
|
|
392
|
-
monitoring_mode: ModelMonitoringMode = ModelMonitoringMode.disabled,
|
|
339
|
+
monitoring_mode: mm_constants.ModelMonitoringMode = mm_constants.ModelMonitoringMode.disabled,
|
|
393
340
|
) -> ModelEndpoint:
|
|
394
341
|
"""
|
|
395
342
|
Write a new model endpoint record.
|
|
@@ -407,8 +354,6 @@ def _generate_model_endpoint(
|
|
|
407
354
|
:param sample_set_statistics: Dictionary of sample set statistics that will be used as a reference data for
|
|
408
355
|
the current model endpoint. Will be stored under
|
|
409
356
|
`model_endpoint.status.feature_stats`.
|
|
410
|
-
:param drift_threshold: The threshold of which to mark drifts.
|
|
411
|
-
:param possible_drift_threshold: The threshold of which to mark possible drifts.
|
|
412
357
|
|
|
413
358
|
:return `mlrun.model_monitoring.model_endpoint.ModelEndpoint` object.
|
|
414
359
|
"""
|
|
@@ -426,15 +371,6 @@ def _generate_model_endpoint(
|
|
|
426
371
|
model_endpoint.spec.model_uri = model_path
|
|
427
372
|
model_endpoint.spec.model = model_endpoint_name
|
|
428
373
|
model_endpoint.spec.model_class = "drift-analysis"
|
|
429
|
-
if drift_threshold:
|
|
430
|
-
model_endpoint.spec.monitor_configuration[
|
|
431
|
-
EventFieldType.DRIFT_DETECTED_THRESHOLD
|
|
432
|
-
] = drift_threshold
|
|
433
|
-
if possible_drift_threshold:
|
|
434
|
-
model_endpoint.spec.monitor_configuration[
|
|
435
|
-
EventFieldType.POSSIBLE_DRIFT_THRESHOLD
|
|
436
|
-
] = possible_drift_threshold
|
|
437
|
-
|
|
438
374
|
model_endpoint.spec.monitoring_mode = monitoring_mode
|
|
439
375
|
model_endpoint.status.first_request = model_endpoint.status.last_request = (
|
|
440
376
|
datetime_now().isoformat()
|
|
@@ -449,71 +385,6 @@ def _generate_model_endpoint(
|
|
|
449
385
|
return db_session.get_model_endpoint(project=project, endpoint_id=endpoint_id)
|
|
450
386
|
|
|
451
387
|
|
|
452
|
-
def trigger_drift_batch_job(
|
|
453
|
-
project: str,
|
|
454
|
-
default_batch_image="mlrun/mlrun",
|
|
455
|
-
model_endpoints_ids: list[str] = None,
|
|
456
|
-
batch_intervals_dict: dict[str, float] = None,
|
|
457
|
-
db_session=None,
|
|
458
|
-
):
|
|
459
|
-
"""
|
|
460
|
-
Run model monitoring drift analysis job. If not exists, the monitoring batch function will be registered through
|
|
461
|
-
MLRun API with the provided image.
|
|
462
|
-
|
|
463
|
-
:param project: Project name.
|
|
464
|
-
:param default_batch_image: The image that will be used when registering the model monitoring batch job.
|
|
465
|
-
:param model_endpoints_ids: List of model endpoints to include in the current run.
|
|
466
|
-
:param batch_intervals_dict: Batch interval range (days, hours, minutes). By default, the batch interval is
|
|
467
|
-
configured to run through the last hour.
|
|
468
|
-
:param db_session: A runtime session that manages the current dialog with the database.
|
|
469
|
-
|
|
470
|
-
"""
|
|
471
|
-
if not model_endpoints_ids:
|
|
472
|
-
raise mlrun.errors.MLRunNotFoundError(
|
|
473
|
-
"No model endpoints provided",
|
|
474
|
-
)
|
|
475
|
-
if not db_session:
|
|
476
|
-
db_session = mlrun.get_run_db()
|
|
477
|
-
|
|
478
|
-
# Register the monitoring batch job (do nothing if already exist) and get the job function as a dictionary
|
|
479
|
-
batch_function_dict: dict[str, typing.Any] = db_session.deploy_monitoring_batch_job(
|
|
480
|
-
project=project,
|
|
481
|
-
default_batch_image=default_batch_image,
|
|
482
|
-
)
|
|
483
|
-
|
|
484
|
-
# Prepare current run params
|
|
485
|
-
job_params = _generate_job_params(
|
|
486
|
-
model_endpoints_ids=model_endpoints_ids,
|
|
487
|
-
batch_intervals_dict=batch_intervals_dict,
|
|
488
|
-
)
|
|
489
|
-
|
|
490
|
-
# Generate runtime and trigger the job function
|
|
491
|
-
batch_function = mlrun.new_function(runtime=batch_function_dict)
|
|
492
|
-
batch_function.run(name="model-monitoring-batch", params=job_params, watch=True)
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
def _generate_job_params(
|
|
496
|
-
model_endpoints_ids: list[str],
|
|
497
|
-
batch_intervals_dict: dict[str, float] = None,
|
|
498
|
-
):
|
|
499
|
-
"""
|
|
500
|
-
Generate the required params for the model monitoring batch job function.
|
|
501
|
-
|
|
502
|
-
:param model_endpoints_ids: List of model endpoints to include in the current run.
|
|
503
|
-
:param batch_intervals_dict: Batch interval range (days, hours, minutes). By default, the batch interval is
|
|
504
|
-
configured to run through the last hour.
|
|
505
|
-
|
|
506
|
-
"""
|
|
507
|
-
if not batch_intervals_dict:
|
|
508
|
-
# Generate default batch intervals dict
|
|
509
|
-
batch_intervals_dict = {"minutes": 0, "hours": 1, "days": 0}
|
|
510
|
-
|
|
511
|
-
return {
|
|
512
|
-
"model_endpoints": model_endpoints_ids,
|
|
513
|
-
"batch_intervals_dict": batch_intervals_dict,
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
|
|
517
388
|
def get_sample_set_statistics(
|
|
518
389
|
sample_set: DatasetType = None,
|
|
519
390
|
model_artifact_feature_stats: dict = None,
|
|
@@ -659,151 +530,6 @@ def read_dataset_as_dataframe(
|
|
|
659
530
|
return dataset, label_columns
|
|
660
531
|
|
|
661
532
|
|
|
662
|
-
def perform_drift_analysis(
|
|
663
|
-
project: str,
|
|
664
|
-
endpoint_id: str,
|
|
665
|
-
context: mlrun.MLClientCtx,
|
|
666
|
-
sample_set_statistics: dict,
|
|
667
|
-
drift_threshold: float,
|
|
668
|
-
possible_drift_threshold: float,
|
|
669
|
-
artifacts_tag: str = "",
|
|
670
|
-
db_session=None,
|
|
671
|
-
) -> None:
|
|
672
|
-
"""
|
|
673
|
-
Calculate drift per feature and produce the drift table artifact for logging post prediction. Note that most of
|
|
674
|
-
the calculations were already made through the monitoring batch job.
|
|
675
|
-
|
|
676
|
-
:param project: Project name.
|
|
677
|
-
:param endpoint_id: Model endpoint unique ID.
|
|
678
|
-
:param context: MLRun context. Will log the artifacts.
|
|
679
|
-
:param sample_set_statistics: The statistics of the sample set logged along a model.
|
|
680
|
-
:param drift_threshold: The threshold of which to mark drifts.
|
|
681
|
-
:param possible_drift_threshold: The threshold of which to mark possible drifts.
|
|
682
|
-
:param artifacts_tag: Tag to use for all the artifacts resulted from the function.
|
|
683
|
-
:param db_session: A runtime session that manages the current dialog with the database.
|
|
684
|
-
|
|
685
|
-
"""
|
|
686
|
-
if not db_session:
|
|
687
|
-
db_session = mlrun.get_run_db()
|
|
688
|
-
|
|
689
|
-
model_endpoint = db_session.get_model_endpoint(
|
|
690
|
-
project=project, endpoint_id=endpoint_id
|
|
691
|
-
)
|
|
692
|
-
|
|
693
|
-
# Get the drift metrics results along with the feature statistics from the latest batch
|
|
694
|
-
metrics = model_endpoint.status.drift_measures
|
|
695
|
-
inputs_statistics = model_endpoint.status.current_stats
|
|
696
|
-
|
|
697
|
-
inputs_statistics.pop(EventFieldType.TIMESTAMP, None)
|
|
698
|
-
|
|
699
|
-
# Calculate drift for each feature
|
|
700
|
-
virtual_drift = VirtualDrift()
|
|
701
|
-
drift_results = virtual_drift.check_for_drift_per_feature(
|
|
702
|
-
metrics_results_dictionary=metrics,
|
|
703
|
-
possible_drift_threshold=possible_drift_threshold,
|
|
704
|
-
drift_detected_threshold=drift_threshold,
|
|
705
|
-
)
|
|
706
|
-
|
|
707
|
-
# Drift table plot
|
|
708
|
-
html_plot = FeaturesDriftTablePlot().produce(
|
|
709
|
-
sample_set_statistics=sample_set_statistics,
|
|
710
|
-
inputs_statistics=inputs_statistics,
|
|
711
|
-
metrics=metrics,
|
|
712
|
-
drift_results=drift_results,
|
|
713
|
-
)
|
|
714
|
-
|
|
715
|
-
# Prepare drift result per feature dictionary
|
|
716
|
-
metrics_per_feature = {
|
|
717
|
-
feature: _get_drift_result(
|
|
718
|
-
tvd=metric_dictionary["tvd"],
|
|
719
|
-
hellinger=metric_dictionary["hellinger"],
|
|
720
|
-
threshold=drift_threshold,
|
|
721
|
-
)[1]
|
|
722
|
-
for feature, metric_dictionary in metrics.items()
|
|
723
|
-
if isinstance(metric_dictionary, dict)
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
# Calculate the final analysis result as well
|
|
727
|
-
drift_status, drift_metric = _get_drift_result(
|
|
728
|
-
tvd=metrics["tvd_mean"],
|
|
729
|
-
hellinger=metrics["hellinger_mean"],
|
|
730
|
-
threshold=drift_threshold,
|
|
731
|
-
)
|
|
732
|
-
# Log the different artifacts
|
|
733
|
-
_log_drift_artifacts(
|
|
734
|
-
context=context,
|
|
735
|
-
html_plot=html_plot,
|
|
736
|
-
metrics_per_feature=metrics_per_feature,
|
|
737
|
-
drift_status=drift_status,
|
|
738
|
-
drift_metric=drift_metric,
|
|
739
|
-
artifacts_tag=artifacts_tag,
|
|
740
|
-
)
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
def _log_drift_artifacts(
|
|
744
|
-
context: mlrun.MLClientCtx,
|
|
745
|
-
html_plot: str,
|
|
746
|
-
metrics_per_feature: dict[str, float],
|
|
747
|
-
drift_status: bool,
|
|
748
|
-
drift_metric: float,
|
|
749
|
-
artifacts_tag: str,
|
|
750
|
-
):
|
|
751
|
-
"""
|
|
752
|
-
Log the following artifacts/results:
|
|
753
|
-
1 - Drift table plot which includes a detailed drift analysis per feature
|
|
754
|
-
2 - Drift result per feature in a JSON format
|
|
755
|
-
3 - Results of the total drift analysis
|
|
756
|
-
|
|
757
|
-
:param context: MLRun context. Will log the artifacts.
|
|
758
|
-
:param html_plot: Body of the html file of the plot.
|
|
759
|
-
:param metrics_per_feature: Dictionary in which the key is a feature name and the value is the drift numerical
|
|
760
|
-
result.
|
|
761
|
-
:param drift_status: Boolean value that represents the final drift analysis result.
|
|
762
|
-
:param drift_metric: The final drift numerical result.
|
|
763
|
-
:param artifacts_tag: Tag to use for all the artifacts resulted from the function.
|
|
764
|
-
|
|
765
|
-
"""
|
|
766
|
-
context.log_artifact(
|
|
767
|
-
mlrun.artifacts.Artifact(
|
|
768
|
-
body=html_plot.encode("utf-8"), format="html", key="drift_table_plot"
|
|
769
|
-
),
|
|
770
|
-
tag=artifacts_tag,
|
|
771
|
-
)
|
|
772
|
-
context.log_artifact(
|
|
773
|
-
mlrun.artifacts.Artifact(
|
|
774
|
-
body=json.dumps(metrics_per_feature),
|
|
775
|
-
format="json",
|
|
776
|
-
key="features_drift_results",
|
|
777
|
-
),
|
|
778
|
-
tag=artifacts_tag,
|
|
779
|
-
)
|
|
780
|
-
context.log_results(
|
|
781
|
-
results={"drift_status": drift_status, "drift_metric": drift_metric}
|
|
782
|
-
)
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
def _get_drift_result(
|
|
786
|
-
tvd: float,
|
|
787
|
-
hellinger: float,
|
|
788
|
-
threshold: float,
|
|
789
|
-
) -> tuple[bool, float]:
|
|
790
|
-
"""
|
|
791
|
-
Calculate the drift result by the following equation: (tvd + hellinger) / 2
|
|
792
|
-
|
|
793
|
-
:param tvd: The feature's TVD value.
|
|
794
|
-
:param hellinger: The feature's Hellinger value.
|
|
795
|
-
:param threshold: The threshold from which the value is considered a drift.
|
|
796
|
-
|
|
797
|
-
:returns: A tuple of:
|
|
798
|
-
[0] = Boolean value as the drift status.
|
|
799
|
-
[1] = The result.
|
|
800
|
-
"""
|
|
801
|
-
result = (tvd + hellinger) / 2
|
|
802
|
-
if result >= threshold:
|
|
803
|
-
return True, result
|
|
804
|
-
return False, result
|
|
805
|
-
|
|
806
|
-
|
|
807
533
|
def log_result(
|
|
808
534
|
context: mlrun.MLClientCtx,
|
|
809
535
|
result_set_name: str,
|
|
@@ -826,3 +552,72 @@ def log_result(
|
|
|
826
552
|
key="batch_id",
|
|
827
553
|
value=batch_id,
|
|
828
554
|
)
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
def _create_model_monitoring_function_base(
|
|
558
|
+
*,
|
|
559
|
+
project: str,
|
|
560
|
+
func: typing.Union[str, None] = None,
|
|
561
|
+
application_class: typing.Union[
|
|
562
|
+
str,
|
|
563
|
+
mm_app.ModelMonitoringApplicationBase,
|
|
564
|
+
None,
|
|
565
|
+
] = None,
|
|
566
|
+
name: typing.Optional[str] = None,
|
|
567
|
+
image: typing.Optional[str] = None,
|
|
568
|
+
tag: typing.Optional[str] = None,
|
|
569
|
+
requirements: typing.Union[str, list[str], None] = None,
|
|
570
|
+
requirements_file: str = "",
|
|
571
|
+
**application_kwargs,
|
|
572
|
+
) -> mlrun.runtimes.ServingRuntime:
|
|
573
|
+
"""
|
|
574
|
+
Note: this is an internal API only.
|
|
575
|
+
This function does not set the labels or mounts v3io.
|
|
576
|
+
"""
|
|
577
|
+
if name in mm_constants._RESERVED_FUNCTION_NAMES:
|
|
578
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
579
|
+
"An application cannot have the following names: "
|
|
580
|
+
f"{mm_constants._RESERVED_FUNCTION_NAMES}"
|
|
581
|
+
)
|
|
582
|
+
if func is None:
|
|
583
|
+
func = ""
|
|
584
|
+
func_obj = typing.cast(
|
|
585
|
+
mlrun.runtimes.ServingRuntime,
|
|
586
|
+
mlrun.code_to_function(
|
|
587
|
+
filename=func,
|
|
588
|
+
name=name,
|
|
589
|
+
project=project,
|
|
590
|
+
tag=tag,
|
|
591
|
+
kind=mlrun.run.RuntimeKinds.serving,
|
|
592
|
+
image=image,
|
|
593
|
+
requirements=requirements,
|
|
594
|
+
requirements_file=requirements_file,
|
|
595
|
+
),
|
|
596
|
+
)
|
|
597
|
+
graph = func_obj.set_topology(mlrun.serving.states.StepKinds.flow)
|
|
598
|
+
prepare_step = graph.to(
|
|
599
|
+
class_name="mlrun.model_monitoring.applications._application_steps._PrepareMonitoringEvent",
|
|
600
|
+
name="PrepareMonitoringEvent",
|
|
601
|
+
application_name=name,
|
|
602
|
+
)
|
|
603
|
+
if isinstance(application_class, str):
|
|
604
|
+
app_step = prepare_step.to(class_name=application_class, **application_kwargs)
|
|
605
|
+
else:
|
|
606
|
+
app_step = prepare_step.to(class_name=application_class)
|
|
607
|
+
|
|
608
|
+
app_step.__class__ = mlrun.serving.MonitoringApplicationStep
|
|
609
|
+
|
|
610
|
+
app_step.error_handler(
|
|
611
|
+
name="ApplicationErrorHandler",
|
|
612
|
+
class_name="mlrun.model_monitoring.applications._application_steps._ApplicationErrorHandler",
|
|
613
|
+
full_event=True,
|
|
614
|
+
project=project,
|
|
615
|
+
)
|
|
616
|
+
|
|
617
|
+
app_step.to(
|
|
618
|
+
class_name="mlrun.model_monitoring.applications._application_steps._PushToMonitoringWriter",
|
|
619
|
+
name="PushToMonitoringWriter",
|
|
620
|
+
project=project,
|
|
621
|
+
writer_application_name=mm_constants.MonitoringFunctionNames.WRITER,
|
|
622
|
+
)
|
|
623
|
+
return func_obj
|
|
@@ -11,3 +11,13 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
+
#
|
|
15
|
+
|
|
16
|
+
from .base import ModelMonitoringApplicationBase
|
|
17
|
+
from .context import MonitoringApplicationContext
|
|
18
|
+
from .evidently_base import (
|
|
19
|
+
_HAS_EVIDENTLY,
|
|
20
|
+
SUPPORTED_EVIDENTLY_VERSION,
|
|
21
|
+
EvidentlyModelMonitoringApplicationBase,
|
|
22
|
+
)
|
|
23
|
+
from .results import ModelMonitoringApplicationMetric, ModelMonitoringApplicationResult
|