mlrun 1.7.0rc48__py3-none-any.whl → 1.7.0rc50__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/common/formatters/run.py +3 -0
- mlrun/common/schemas/auth.py +3 -0
- mlrun/common/schemas/model_monitoring/constants.py +0 -7
- mlrun/common/schemas/workflow.py +9 -2
- mlrun/data_types/data_types.py +1 -1
- mlrun/db/httpdb.py +11 -4
- mlrun/execution.py +7 -1
- mlrun/feature_store/retrieval/spark_merger.py +0 -4
- mlrun/model_monitoring/api.py +1 -12
- mlrun/model_monitoring/applications/__init__.py +1 -2
- mlrun/model_monitoring/applications/base.py +2 -182
- mlrun/model_monitoring/applications/context.py +2 -9
- mlrun/model_monitoring/applications/evidently_base.py +0 -74
- mlrun/model_monitoring/applications/histogram_data_drift.py +2 -2
- mlrun/model_monitoring/controller.py +45 -208
- mlrun/projects/operations.py +11 -8
- mlrun/projects/pipelines.py +12 -7
- mlrun/projects/project.py +1 -4
- mlrun/runtimes/nuclio/api_gateway.py +6 -0
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.0rc48.dist-info → mlrun-1.7.0rc50.dist-info}/METADATA +99 -21
- {mlrun-1.7.0rc48.dist-info → mlrun-1.7.0rc50.dist-info}/RECORD +26 -28
- mlrun/model_monitoring/application.py +0 -19
- mlrun/model_monitoring/evidently_application.py +0 -20
- {mlrun-1.7.0rc48.dist-info → mlrun-1.7.0rc50.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc48.dist-info → mlrun-1.7.0rc50.dist-info}/WHEEL +0 -0
- {mlrun-1.7.0rc48.dist-info → mlrun-1.7.0rc50.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc48.dist-info → mlrun-1.7.0rc50.dist-info}/top_level.txt +0 -0
mlrun/common/formatters/run.py
CHANGED
|
@@ -22,5 +22,8 @@ class RunFormat(ObjectFormat, mlrun.common.types.StrEnum):
|
|
|
22
22
|
# No enrichment, data is pulled as-is from the database.
|
|
23
23
|
standard = "standard"
|
|
24
24
|
|
|
25
|
+
# Enrich run with full notifications since the notification params are subtracted from the run body.
|
|
26
|
+
notifications = "notifications"
|
|
27
|
+
|
|
25
28
|
# Performs run enrichment, including the run's artifacts. Only available for the `get` run API.
|
|
26
29
|
full = "full"
|
mlrun/common/schemas/auth.py
CHANGED
|
@@ -141,6 +141,9 @@ class AuthInfo(pydantic.BaseModel):
|
|
|
141
141
|
member_ids.extend(self.user_group_ids)
|
|
142
142
|
return member_ids
|
|
143
143
|
|
|
144
|
+
def get_session(self) -> str:
|
|
145
|
+
return self.data_session or self.session
|
|
146
|
+
|
|
144
147
|
|
|
145
148
|
class Credentials(pydantic.BaseModel):
|
|
146
149
|
access_key: typing.Optional[str]
|
|
@@ -105,15 +105,8 @@ class ApplicationEvent:
|
|
|
105
105
|
APPLICATION_NAME = "application_name"
|
|
106
106
|
START_INFER_TIME = "start_infer_time"
|
|
107
107
|
END_INFER_TIME = "end_infer_time"
|
|
108
|
-
LAST_REQUEST = "last_request"
|
|
109
108
|
ENDPOINT_ID = "endpoint_id"
|
|
110
109
|
OUTPUT_STREAM_URI = "output_stream_uri"
|
|
111
|
-
MLRUN_CONTEXT = "mlrun_context"
|
|
112
|
-
|
|
113
|
-
# Deprecated fields - TODO : delete in 1.9.0 (V1 app deprecation)
|
|
114
|
-
SAMPLE_PARQUET_PATH = "sample_parquet_path"
|
|
115
|
-
CURRENT_STATS = "current_stats"
|
|
116
|
-
FEATURE_STATS = "feature_stats"
|
|
117
110
|
|
|
118
111
|
|
|
119
112
|
class WriterEvent(MonitoringStrEnum):
|
mlrun/common/schemas/workflow.py
CHANGED
|
@@ -16,8 +16,9 @@ import typing
|
|
|
16
16
|
|
|
17
17
|
import pydantic
|
|
18
18
|
|
|
19
|
-
from .notification import Notification
|
|
20
|
-
from .schedule import ScheduleCronTrigger
|
|
19
|
+
from mlrun.common.schemas.notification import Notification
|
|
20
|
+
from mlrun.common.schemas.schedule import ScheduleCronTrigger
|
|
21
|
+
from mlrun.common.types import StrEnum
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
class WorkflowSpec(pydantic.BaseModel):
|
|
@@ -55,3 +56,9 @@ class WorkflowResponse(pydantic.BaseModel):
|
|
|
55
56
|
|
|
56
57
|
class GetWorkflowResponse(pydantic.BaseModel):
|
|
57
58
|
workflow_id: str = None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class EngineType(StrEnum):
|
|
62
|
+
LOCAL = "local"
|
|
63
|
+
REMOTE = "remote"
|
|
64
|
+
KFP = "kfp"
|
mlrun/data_types/data_types.py
CHANGED
mlrun/db/httpdb.py
CHANGED
|
@@ -2754,7 +2754,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2754
2754
|
deletion_strategy: Union[
|
|
2755
2755
|
str, mlrun.common.schemas.DeletionStrategy
|
|
2756
2756
|
] = mlrun.common.schemas.DeletionStrategy.default(),
|
|
2757
|
-
):
|
|
2757
|
+
) -> None:
|
|
2758
2758
|
"""Delete a project.
|
|
2759
2759
|
|
|
2760
2760
|
:param name: Name of the project to delete.
|
|
@@ -2773,7 +2773,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2773
2773
|
"DELETE", f"projects/{name}", error_message, headers=headers, version="v2"
|
|
2774
2774
|
)
|
|
2775
2775
|
if response.status_code == http.HTTPStatus.ACCEPTED:
|
|
2776
|
-
logger.info("
|
|
2776
|
+
logger.info("Waiting for project to be deleted", project_name=name)
|
|
2777
2777
|
background_task = mlrun.common.schemas.BackgroundTask(**response.json())
|
|
2778
2778
|
background_task = self._wait_for_background_task_to_reach_terminal_state(
|
|
2779
2779
|
background_task.metadata.name
|
|
@@ -2783,10 +2783,17 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2783
2783
|
== mlrun.common.schemas.BackgroundTaskState.succeeded
|
|
2784
2784
|
):
|
|
2785
2785
|
logger.info("Project deleted", project_name=name)
|
|
2786
|
-
|
|
2786
|
+
elif (
|
|
2787
|
+
background_task.status.state
|
|
2788
|
+
== mlrun.common.schemas.BackgroundTaskState.failed
|
|
2789
|
+
):
|
|
2790
|
+
logger.error(
|
|
2791
|
+
"Project deletion failed",
|
|
2792
|
+
project_name=name,
|
|
2793
|
+
error=background_task.status.error,
|
|
2794
|
+
)
|
|
2787
2795
|
elif response.status_code == http.HTTPStatus.NO_CONTENT:
|
|
2788
2796
|
logger.info("Project deleted", project_name=name)
|
|
2789
|
-
return
|
|
2790
2797
|
|
|
2791
2798
|
def store_project(
|
|
2792
2799
|
self,
|
mlrun/execution.py
CHANGED
|
@@ -24,6 +24,7 @@ from dateutil import parser
|
|
|
24
24
|
|
|
25
25
|
import mlrun
|
|
26
26
|
import mlrun.common.constants as mlrun_constants
|
|
27
|
+
import mlrun.common.formatters
|
|
27
28
|
from mlrun.artifacts import ModelArtifact
|
|
28
29
|
from mlrun.datastore.store_resources import get_store_resource
|
|
29
30
|
from mlrun.errors import MLRunInvalidArgumentError
|
|
@@ -928,9 +929,14 @@ class MLClientCtx:
|
|
|
928
929
|
|
|
929
930
|
def get_notifications(self):
|
|
930
931
|
"""Get the list of notifications"""
|
|
932
|
+
|
|
933
|
+
# Get the full notifications from the DB since the run context does not contain the params due to bloating
|
|
934
|
+
run = self._rundb.read_run(
|
|
935
|
+
self.uid, format_=mlrun.common.formatters.RunFormat.notifications
|
|
936
|
+
)
|
|
931
937
|
return [
|
|
932
938
|
mlrun.model.Notification.from_dict(notification)
|
|
933
|
-
for notification in
|
|
939
|
+
for notification in run["spec"]["notifications"]
|
|
934
940
|
]
|
|
935
941
|
|
|
936
942
|
def to_dict(self):
|
|
@@ -206,10 +206,6 @@ class SparkFeatureMerger(BaseMerger):
|
|
|
206
206
|
time_column=None,
|
|
207
207
|
additional_filters=None,
|
|
208
208
|
):
|
|
209
|
-
mlrun.utils.helpers.additional_filters_warning(
|
|
210
|
-
additional_filters, self.__class__
|
|
211
|
-
)
|
|
212
|
-
|
|
213
209
|
source_kwargs = {}
|
|
214
210
|
if feature_set.spec.passthrough:
|
|
215
211
|
if not feature_set.spec.source:
|
mlrun/model_monitoring/api.py
CHANGED
|
@@ -24,7 +24,6 @@ import mlrun.artifacts
|
|
|
24
24
|
import mlrun.common.helpers
|
|
25
25
|
import mlrun.common.schemas.model_monitoring.constants as mm_constants
|
|
26
26
|
import mlrun.feature_store
|
|
27
|
-
import mlrun.model_monitoring.application
|
|
28
27
|
import mlrun.model_monitoring.applications as mm_app
|
|
29
28
|
import mlrun.serving
|
|
30
29
|
from mlrun.data_types.infer import InferOptions, get_df_stats
|
|
@@ -561,8 +560,7 @@ def _create_model_monitoring_function_base(
|
|
|
561
560
|
func: typing.Union[str, None] = None,
|
|
562
561
|
application_class: typing.Union[
|
|
563
562
|
str,
|
|
564
|
-
|
|
565
|
-
mm_app.ModelMonitoringApplicationBaseV2,
|
|
563
|
+
mm_app.ModelMonitoringApplicationBase,
|
|
566
564
|
None,
|
|
567
565
|
] = None,
|
|
568
566
|
name: typing.Optional[str] = None,
|
|
@@ -576,15 +574,6 @@ def _create_model_monitoring_function_base(
|
|
|
576
574
|
Note: this is an internal API only.
|
|
577
575
|
This function does not set the labels or mounts v3io.
|
|
578
576
|
"""
|
|
579
|
-
if isinstance(
|
|
580
|
-
application_class,
|
|
581
|
-
mlrun.model_monitoring.application.ModelMonitoringApplicationBase,
|
|
582
|
-
):
|
|
583
|
-
warnings.warn(
|
|
584
|
-
"The `ModelMonitoringApplicationBase` class is deprecated from version 1.7.0, "
|
|
585
|
-
"please use `ModelMonitoringApplicationBaseV2`. It will be removed in 1.9.0.",
|
|
586
|
-
FutureWarning,
|
|
587
|
-
)
|
|
588
577
|
if name in mm_constants._RESERVED_FUNCTION_NAMES:
|
|
589
578
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
590
579
|
"An application cannot have the following names: "
|
|
@@ -13,12 +13,11 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
#
|
|
15
15
|
|
|
16
|
-
from .base import ModelMonitoringApplicationBase
|
|
16
|
+
from .base import ModelMonitoringApplicationBase
|
|
17
17
|
from .context import MonitoringApplicationContext
|
|
18
18
|
from .evidently_base import (
|
|
19
19
|
_HAS_EVIDENTLY,
|
|
20
20
|
SUPPORTED_EVIDENTLY_VERSION,
|
|
21
21
|
EvidentlyModelMonitoringApplicationBase,
|
|
22
|
-
EvidentlyModelMonitoringApplicationBaseV2,
|
|
23
22
|
)
|
|
24
23
|
from .results import ModelMonitoringApplicationMetric, ModelMonitoringApplicationResult
|
|
@@ -13,19 +13,14 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
from abc import ABC, abstractmethod
|
|
16
|
-
from typing import Any, Union
|
|
16
|
+
from typing import Any, Union
|
|
17
17
|
|
|
18
|
-
import numpy as np
|
|
19
|
-
import pandas as pd
|
|
20
|
-
from deprecated import deprecated
|
|
21
|
-
|
|
22
|
-
import mlrun
|
|
23
18
|
import mlrun.model_monitoring.applications.context as mm_context
|
|
24
19
|
import mlrun.model_monitoring.applications.results as mm_results
|
|
25
20
|
from mlrun.serving.utils import MonitoringApplicationToDict
|
|
26
21
|
|
|
27
22
|
|
|
28
|
-
class
|
|
23
|
+
class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
|
|
29
24
|
"""
|
|
30
25
|
A base class for a model monitoring application.
|
|
31
26
|
Inherit from this class to create a custom model monitoring application.
|
|
@@ -111,178 +106,3 @@ class ModelMonitoringApplicationBaseV2(MonitoringApplicationToDict, ABC):
|
|
|
111
106
|
each metric name is the key and the metric value is the corresponding value).
|
|
112
107
|
"""
|
|
113
108
|
raise NotImplementedError
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
# TODO: Remove in 1.9.0
|
|
117
|
-
@deprecated(
|
|
118
|
-
version="1.7.0",
|
|
119
|
-
reason="The `ModelMonitoringApplicationBase` class is deprecated from "
|
|
120
|
-
"version 1.7.0 and will be removed in version 1.9.0. "
|
|
121
|
-
"Use `ModelMonitoringApplicationBaseV2` as your application's base class.",
|
|
122
|
-
)
|
|
123
|
-
class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
|
|
124
|
-
"""
|
|
125
|
-
A base class for a model monitoring application.
|
|
126
|
-
Inherit from this class to create a custom model monitoring application.
|
|
127
|
-
|
|
128
|
-
example for very simple custom application::
|
|
129
|
-
|
|
130
|
-
class MyApp(ApplicationBase):
|
|
131
|
-
def do_tracking(
|
|
132
|
-
self,
|
|
133
|
-
sample_df_stats: mlrun.common.model_monitoring.helpers.FeatureStats,
|
|
134
|
-
feature_stats: mlrun.common.model_monitoring.helpers.FeatureStats,
|
|
135
|
-
start_infer_time: pd.Timestamp,
|
|
136
|
-
end_infer_time: pd.Timestamp,
|
|
137
|
-
schedule_time: pd.Timestamp,
|
|
138
|
-
latest_request: pd.Timestamp,
|
|
139
|
-
endpoint_id: str,
|
|
140
|
-
output_stream_uri: str,
|
|
141
|
-
) -> ModelMonitoringApplicationResult:
|
|
142
|
-
self.context.log_artifact(
|
|
143
|
-
TableArtifact(
|
|
144
|
-
"sample_df_stats", df=self.dict_to_histogram(sample_df_stats)
|
|
145
|
-
)
|
|
146
|
-
)
|
|
147
|
-
return ModelMonitoringApplicationResult(
|
|
148
|
-
name="data_drift_test",
|
|
149
|
-
value=0.5,
|
|
150
|
-
kind=mm_constant.ResultKindApp.data_drift,
|
|
151
|
-
status=mm_constant.ResultStatusApp.detected,
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
"""
|
|
156
|
-
|
|
157
|
-
kind = "monitoring_application"
|
|
158
|
-
|
|
159
|
-
def do(
|
|
160
|
-
self, monitoring_context: mm_context.MonitoringApplicationContext
|
|
161
|
-
) -> tuple[
|
|
162
|
-
list[mm_results.ModelMonitoringApplicationResult],
|
|
163
|
-
mm_context.MonitoringApplicationContext,
|
|
164
|
-
]:
|
|
165
|
-
"""
|
|
166
|
-
Process the monitoring event and return application results.
|
|
167
|
-
|
|
168
|
-
:param monitoring_context: (MonitoringApplicationContext) The monitoring context to process.
|
|
169
|
-
:returns: A tuple of:
|
|
170
|
-
[0] = list of application results that can be either from type
|
|
171
|
-
`ModelMonitoringApplicationResult` or from type
|
|
172
|
-
`ModelMonitoringApplicationResult`.
|
|
173
|
-
[1] = the original application event, wrapped in `MonitoringApplicationContext`
|
|
174
|
-
object
|
|
175
|
-
"""
|
|
176
|
-
resolved_event = self._resolve_event(monitoring_context)
|
|
177
|
-
if not (
|
|
178
|
-
hasattr(self, "context") and isinstance(self.context, mlrun.MLClientCtx)
|
|
179
|
-
):
|
|
180
|
-
self._lazy_init(monitoring_context)
|
|
181
|
-
results = self.do_tracking(*resolved_event)
|
|
182
|
-
results = results if isinstance(results, list) else [results]
|
|
183
|
-
return results, monitoring_context
|
|
184
|
-
|
|
185
|
-
def _lazy_init(self, monitoring_context: mm_context.MonitoringApplicationContext):
|
|
186
|
-
self.context = cast(mlrun.MLClientCtx, monitoring_context)
|
|
187
|
-
|
|
188
|
-
@abstractmethod
|
|
189
|
-
def do_tracking(
|
|
190
|
-
self,
|
|
191
|
-
application_name: str,
|
|
192
|
-
sample_df_stats: pd.DataFrame,
|
|
193
|
-
feature_stats: pd.DataFrame,
|
|
194
|
-
sample_df: pd.DataFrame,
|
|
195
|
-
start_infer_time: pd.Timestamp,
|
|
196
|
-
end_infer_time: pd.Timestamp,
|
|
197
|
-
latest_request: pd.Timestamp,
|
|
198
|
-
endpoint_id: str,
|
|
199
|
-
output_stream_uri: str,
|
|
200
|
-
) -> Union[
|
|
201
|
-
mm_results.ModelMonitoringApplicationResult,
|
|
202
|
-
list[mm_results.ModelMonitoringApplicationResult],
|
|
203
|
-
]:
|
|
204
|
-
"""
|
|
205
|
-
Implement this method with your custom monitoring logic.
|
|
206
|
-
|
|
207
|
-
:param application_name: (str) the app name
|
|
208
|
-
:param sample_df_stats: (pd.DataFrame) The new sample distribution.
|
|
209
|
-
:param feature_stats: (pd.DataFrame) The train sample distribution.
|
|
210
|
-
:param sample_df: (pd.DataFrame) The new sample DataFrame.
|
|
211
|
-
:param start_infer_time: (pd.Timestamp) Start time of the monitoring schedule.
|
|
212
|
-
:param end_infer_time: (pd.Timestamp) End time of the monitoring schedule.
|
|
213
|
-
:param latest_request: (pd.Timestamp) Timestamp of the latest request on this endpoint_id.
|
|
214
|
-
:param endpoint_id: (str) ID of the monitored model endpoint
|
|
215
|
-
:param output_stream_uri: (str) URI of the output stream for results
|
|
216
|
-
|
|
217
|
-
:returns: (ModelMonitoringApplicationResult) or
|
|
218
|
-
(list[ModelMonitoringApplicationResult]) of the application results.
|
|
219
|
-
"""
|
|
220
|
-
raise NotImplementedError
|
|
221
|
-
|
|
222
|
-
@classmethod
|
|
223
|
-
def _resolve_event(
|
|
224
|
-
cls,
|
|
225
|
-
monitoring_context: mm_context.MonitoringApplicationContext,
|
|
226
|
-
) -> tuple[
|
|
227
|
-
str,
|
|
228
|
-
pd.DataFrame,
|
|
229
|
-
pd.DataFrame,
|
|
230
|
-
pd.DataFrame,
|
|
231
|
-
pd.Timestamp,
|
|
232
|
-
pd.Timestamp,
|
|
233
|
-
pd.Timestamp,
|
|
234
|
-
str,
|
|
235
|
-
str,
|
|
236
|
-
]:
|
|
237
|
-
"""
|
|
238
|
-
Converting the event into a single tuple that will be used for passing the event arguments to the running
|
|
239
|
-
application
|
|
240
|
-
|
|
241
|
-
:param monitoring_context: (MonitoringApplicationContext) The monitoring context to process.
|
|
242
|
-
|
|
243
|
-
:return: A tuple of:
|
|
244
|
-
[0] = (str) application name
|
|
245
|
-
[1] = (pd.DataFrame) current input statistics
|
|
246
|
-
[2] = (pd.DataFrame) train statistics
|
|
247
|
-
[3] = (pd.DataFrame) current input data
|
|
248
|
-
[4] = (pd.Timestamp) start time of the monitoring schedule
|
|
249
|
-
[5] = (pd.Timestamp) end time of the monitoring schedule
|
|
250
|
-
[6] = (pd.Timestamp) timestamp of the latest request
|
|
251
|
-
[7] = (str) endpoint id
|
|
252
|
-
[8] = (str) output stream uri
|
|
253
|
-
"""
|
|
254
|
-
return (
|
|
255
|
-
monitoring_context.application_name,
|
|
256
|
-
cls.dict_to_histogram(monitoring_context.sample_df_stats),
|
|
257
|
-
cls.dict_to_histogram(monitoring_context.feature_stats),
|
|
258
|
-
monitoring_context.sample_df,
|
|
259
|
-
monitoring_context.start_infer_time,
|
|
260
|
-
monitoring_context.end_infer_time,
|
|
261
|
-
monitoring_context.latest_request,
|
|
262
|
-
monitoring_context.endpoint_id,
|
|
263
|
-
monitoring_context.output_stream_uri,
|
|
264
|
-
)
|
|
265
|
-
|
|
266
|
-
@staticmethod
|
|
267
|
-
def dict_to_histogram(
|
|
268
|
-
histogram_dict: mlrun.common.model_monitoring.helpers.FeatureStats,
|
|
269
|
-
) -> pd.DataFrame:
|
|
270
|
-
"""
|
|
271
|
-
Convert histogram dictionary to pandas DataFrame with feature histograms as columns
|
|
272
|
-
|
|
273
|
-
:param histogram_dict: Histogram dictionary
|
|
274
|
-
|
|
275
|
-
:returns: Histogram dataframe
|
|
276
|
-
"""
|
|
277
|
-
|
|
278
|
-
# Create a dictionary with feature histograms as values
|
|
279
|
-
histograms = {}
|
|
280
|
-
for feature, stats in histogram_dict.items():
|
|
281
|
-
if "hist" in stats:
|
|
282
|
-
# Normalize to probability distribution of each feature
|
|
283
|
-
histograms[feature] = np.array(stats["hist"][0]) / stats["count"]
|
|
284
|
-
|
|
285
|
-
# Convert the dictionary to pandas DataFrame
|
|
286
|
-
histograms = pd.DataFrame(histograms)
|
|
287
|
-
|
|
288
|
-
return histograms
|
|
@@ -98,9 +98,6 @@ class MonitoringApplicationContext:
|
|
|
98
98
|
self.end_infer_time = pd.Timestamp(
|
|
99
99
|
cast(str, event.get(mm_constants.ApplicationEvent.END_INFER_TIME))
|
|
100
100
|
)
|
|
101
|
-
self.latest_request = pd.Timestamp(
|
|
102
|
-
cast(str, event.get(mm_constants.ApplicationEvent.LAST_REQUEST))
|
|
103
|
-
)
|
|
104
101
|
self.endpoint_id = cast(
|
|
105
102
|
str, event.get(mm_constants.ApplicationEvent.ENDPOINT_ID)
|
|
106
103
|
)
|
|
@@ -108,12 +105,8 @@ class MonitoringApplicationContext:
|
|
|
108
105
|
str, event.get(mm_constants.ApplicationEvent.OUTPUT_STREAM_URI)
|
|
109
106
|
)
|
|
110
107
|
|
|
111
|
-
self._feature_stats: Optional[FeatureStats] =
|
|
112
|
-
|
|
113
|
-
)
|
|
114
|
-
self._sample_df_stats: Optional[FeatureStats] = json.loads(
|
|
115
|
-
event.get(mm_constants.ApplicationEvent.CURRENT_STATS, "{}")
|
|
116
|
-
)
|
|
108
|
+
self._feature_stats: Optional[FeatureStats] = None
|
|
109
|
+
self._sample_df_stats: Optional[FeatureStats] = None
|
|
117
110
|
|
|
118
111
|
# Default labels for the artifacts
|
|
119
112
|
self._default_labels = self._get_default_labels()
|
|
@@ -18,7 +18,6 @@ from abc import ABC
|
|
|
18
18
|
|
|
19
19
|
import pandas as pd
|
|
20
20
|
import semver
|
|
21
|
-
from deprecated import deprecated
|
|
22
21
|
|
|
23
22
|
import mlrun.model_monitoring.applications.base as mm_base
|
|
24
23
|
import mlrun.model_monitoring.applications.context as mm_context
|
|
@@ -64,13 +63,6 @@ if _HAS_EVIDENTLY:
|
|
|
64
63
|
from evidently.utils.dashboard import TemplateParams, file_html_template
|
|
65
64
|
|
|
66
65
|
|
|
67
|
-
# TODO: Remove in 1.9.0
|
|
68
|
-
@deprecated(
|
|
69
|
-
version="1.7.0",
|
|
70
|
-
reason="The `EvidentlyModelMonitoringApplicationBase` class is deprecated from "
|
|
71
|
-
"version 1.7.0 and will be removed in version 1.9.0. "
|
|
72
|
-
"Use `EvidentlyModelMonitoringApplicationBaseV2` as your application's base class.",
|
|
73
|
-
)
|
|
74
66
|
class EvidentlyModelMonitoringApplicationBase(
|
|
75
67
|
mm_base.ModelMonitoringApplicationBase, ABC
|
|
76
68
|
):
|
|
@@ -85,72 +77,6 @@ class EvidentlyModelMonitoringApplicationBase(
|
|
|
85
77
|
:param evidently_workspace_path: (str) The path to the Evidently workspace.
|
|
86
78
|
:param evidently_project_id: (str) The ID of the Evidently project.
|
|
87
79
|
|
|
88
|
-
"""
|
|
89
|
-
if not _HAS_EVIDENTLY:
|
|
90
|
-
raise ModuleNotFoundError("Evidently is not installed - the app cannot run")
|
|
91
|
-
self.evidently_workspace = Workspace.create(evidently_workspace_path)
|
|
92
|
-
self.evidently_project_id = evidently_project_id
|
|
93
|
-
self.evidently_project = self.evidently_workspace.get_project(
|
|
94
|
-
evidently_project_id
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
def log_evidently_object(
|
|
98
|
-
self, evidently_object: "Display", artifact_name: str
|
|
99
|
-
) -> None:
|
|
100
|
-
"""
|
|
101
|
-
Logs an Evidently report or suite as an artifact.
|
|
102
|
-
|
|
103
|
-
:param evidently_object: (Display) The Evidently display to log, e.g. a report or a test suite object.
|
|
104
|
-
:param artifact_name: (str) The name for the logged artifact.
|
|
105
|
-
"""
|
|
106
|
-
evidently_object_html = evidently_object.get_html()
|
|
107
|
-
self.context.log_artifact(
|
|
108
|
-
artifact_name, body=evidently_object_html.encode("utf-8"), format="html"
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
def log_project_dashboard(
|
|
112
|
-
self,
|
|
113
|
-
timestamp_start: pd.Timestamp,
|
|
114
|
-
timestamp_end: pd.Timestamp,
|
|
115
|
-
artifact_name: str = "dashboard",
|
|
116
|
-
):
|
|
117
|
-
"""
|
|
118
|
-
Logs an Evidently project dashboard.
|
|
119
|
-
|
|
120
|
-
:param timestamp_start: (pd.Timestamp) The start timestamp for the dashboard data.
|
|
121
|
-
:param timestamp_end: (pd.Timestamp) The end timestamp for the dashboard data.
|
|
122
|
-
:param artifact_name: (str) The name for the logged artifact.
|
|
123
|
-
"""
|
|
124
|
-
|
|
125
|
-
dashboard_info = self.evidently_project.build_dashboard_info(
|
|
126
|
-
timestamp_start, timestamp_end
|
|
127
|
-
)
|
|
128
|
-
template_params = TemplateParams(
|
|
129
|
-
dashboard_id="pd_" + str(uuid.uuid4()).replace("-", ""),
|
|
130
|
-
dashboard_info=dashboard_info,
|
|
131
|
-
additional_graphs={},
|
|
132
|
-
)
|
|
133
|
-
|
|
134
|
-
dashboard_html = file_html_template(params=template_params)
|
|
135
|
-
self.context.log_artifact(
|
|
136
|
-
artifact_name, body=dashboard_html.encode("utf-8"), format="html"
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
class EvidentlyModelMonitoringApplicationBaseV2(
|
|
141
|
-
mm_base.ModelMonitoringApplicationBaseV2, ABC
|
|
142
|
-
):
|
|
143
|
-
def __init__(
|
|
144
|
-
self, evidently_workspace_path: str, evidently_project_id: "STR_UUID"
|
|
145
|
-
) -> None:
|
|
146
|
-
"""
|
|
147
|
-
A class for integrating Evidently for mlrun model monitoring within a monitoring application.
|
|
148
|
-
Note: evidently is not installed by default in the mlrun/mlrun image.
|
|
149
|
-
It must be installed separately to use this class.
|
|
150
|
-
|
|
151
|
-
:param evidently_workspace_path: (str) The path to the Evidently workspace.
|
|
152
|
-
:param evidently_project_id: (str) The ID of the Evidently project.
|
|
153
|
-
|
|
154
80
|
"""
|
|
155
81
|
|
|
156
82
|
# TODO : more then one project (mep -> project)
|
|
@@ -31,7 +31,7 @@ from mlrun.common.schemas.model_monitoring.constants import (
|
|
|
31
31
|
ResultStatusApp,
|
|
32
32
|
)
|
|
33
33
|
from mlrun.model_monitoring.applications import (
|
|
34
|
-
|
|
34
|
+
ModelMonitoringApplicationBase,
|
|
35
35
|
)
|
|
36
36
|
from mlrun.model_monitoring.metrics.histogram_distance import (
|
|
37
37
|
HellingerDistance,
|
|
@@ -87,7 +87,7 @@ class DataDriftClassifier:
|
|
|
87
87
|
return ResultStatusApp.no_detection
|
|
88
88
|
|
|
89
89
|
|
|
90
|
-
class HistogramDataDriftApplication(
|
|
90
|
+
class HistogramDataDriftApplication(ModelMonitoringApplicationBase):
|
|
91
91
|
"""
|
|
92
92
|
MLRun's default data drift application for model monitoring.
|
|
93
93
|
|