mlrun 1.7.0rc4__py3-none-any.whl → 1.7.0rc20__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 +25 -111
- mlrun/{datastore/helpers.py → alerts/__init__.py} +2 -5
- mlrun/alerts/alert.py +144 -0
- mlrun/api/schemas/__init__.py +4 -3
- mlrun/artifacts/__init__.py +8 -3
- mlrun/artifacts/base.py +38 -254
- mlrun/artifacts/dataset.py +9 -190
- mlrun/artifacts/manager.py +41 -47
- mlrun/artifacts/model.py +30 -158
- mlrun/artifacts/plots.py +23 -380
- mlrun/common/constants.py +68 -0
- mlrun/common/formatters/__init__.py +19 -0
- mlrun/{model_monitoring/stores/models/sqlite.py → common/formatters/artifact.py} +6 -8
- mlrun/common/formatters/base.py +78 -0
- mlrun/common/formatters/function.py +41 -0
- mlrun/common/formatters/pipeline.py +53 -0
- mlrun/common/formatters/project.py +51 -0
- mlrun/{runtimes → common/runtimes}/constants.py +32 -4
- mlrun/common/schemas/__init__.py +25 -4
- mlrun/common/schemas/alert.py +203 -0
- mlrun/common/schemas/api_gateway.py +148 -0
- mlrun/common/schemas/artifact.py +15 -5
- mlrun/common/schemas/auth.py +8 -2
- mlrun/common/schemas/client_spec.py +2 -0
- mlrun/common/schemas/frontend_spec.py +1 -0
- mlrun/common/schemas/function.py +4 -0
- mlrun/common/schemas/hub.py +7 -9
- mlrun/common/schemas/model_monitoring/__init__.py +19 -3
- mlrun/common/schemas/model_monitoring/constants.py +96 -26
- mlrun/common/schemas/model_monitoring/grafana.py +9 -5
- mlrun/common/schemas/model_monitoring/model_endpoints.py +86 -2
- mlrun/{runtimes/mpijob/v1alpha1.py → common/schemas/pagination.py} +10 -13
- mlrun/common/schemas/pipeline.py +0 -9
- mlrun/common/schemas/project.py +22 -21
- mlrun/common/types.py +7 -1
- mlrun/config.py +87 -19
- mlrun/data_types/data_types.py +4 -0
- mlrun/data_types/to_pandas.py +9 -9
- mlrun/datastore/__init__.py +5 -8
- mlrun/datastore/alibaba_oss.py +130 -0
- mlrun/datastore/azure_blob.py +4 -5
- mlrun/datastore/base.py +69 -30
- mlrun/datastore/datastore.py +10 -2
- mlrun/datastore/datastore_profile.py +90 -6
- mlrun/datastore/google_cloud_storage.py +1 -1
- mlrun/datastore/hdfs.py +5 -0
- mlrun/datastore/inmem.py +2 -2
- mlrun/datastore/redis.py +2 -2
- mlrun/datastore/s3.py +5 -0
- mlrun/datastore/snowflake_utils.py +43 -0
- mlrun/datastore/sources.py +172 -44
- mlrun/datastore/store_resources.py +7 -7
- mlrun/datastore/targets.py +285 -41
- mlrun/datastore/utils.py +68 -5
- mlrun/datastore/v3io.py +27 -50
- mlrun/db/auth_utils.py +152 -0
- mlrun/db/base.py +149 -14
- mlrun/db/factory.py +1 -1
- mlrun/db/httpdb.py +608 -178
- mlrun/db/nopdb.py +191 -7
- mlrun/errors.py +11 -0
- mlrun/execution.py +37 -20
- mlrun/feature_store/__init__.py +0 -2
- mlrun/feature_store/api.py +21 -52
- mlrun/feature_store/feature_set.py +48 -23
- mlrun/feature_store/feature_vector.py +2 -1
- mlrun/feature_store/ingestion.py +7 -6
- mlrun/feature_store/retrieval/base.py +9 -4
- mlrun/feature_store/retrieval/conversion.py +9 -9
- mlrun/feature_store/retrieval/dask_merger.py +2 -0
- mlrun/feature_store/retrieval/job.py +9 -3
- mlrun/feature_store/retrieval/local_merger.py +2 -0
- mlrun/feature_store/retrieval/spark_merger.py +34 -24
- mlrun/feature_store/steps.py +30 -19
- mlrun/features.py +4 -13
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +7 -12
- 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 +2 -1
- mlrun/frameworks/pytorch/__init__.py +2 -2
- mlrun/frameworks/sklearn/__init__.py +1 -1
- 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 +10 -11
- mlrun/launcher/__init__.py +1 -1
- mlrun/launcher/base.py +6 -5
- mlrun/launcher/client.py +8 -6
- mlrun/launcher/factory.py +1 -1
- mlrun/launcher/local.py +9 -3
- mlrun/launcher/remote.py +9 -3
- mlrun/lists.py +6 -2
- mlrun/model.py +58 -19
- mlrun/model_monitoring/__init__.py +1 -1
- mlrun/model_monitoring/api.py +127 -301
- mlrun/model_monitoring/application.py +5 -296
- mlrun/model_monitoring/applications/__init__.py +11 -0
- mlrun/model_monitoring/applications/_application_steps.py +157 -0
- mlrun/model_monitoring/applications/base.py +282 -0
- mlrun/model_monitoring/applications/context.py +214 -0
- mlrun/model_monitoring/applications/evidently_base.py +211 -0
- mlrun/model_monitoring/applications/histogram_data_drift.py +224 -93
- mlrun/model_monitoring/applications/results.py +99 -0
- mlrun/model_monitoring/controller.py +30 -36
- mlrun/model_monitoring/db/__init__.py +18 -0
- mlrun/model_monitoring/{stores → db/stores}/__init__.py +43 -36
- mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
- mlrun/model_monitoring/{stores/model_endpoint_store.py → db/stores/base/store.py} +58 -32
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
- mlrun/model_monitoring/{stores → db/stores/sqldb}/models/base.py +109 -5
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +88 -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 +684 -0
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
- mlrun/model_monitoring/{stores/kv_model_endpoint_store.py → db/stores/v3io_kv/kv_store.py} +302 -155
- mlrun/model_monitoring/db/tsdb/__init__.py +100 -0
- mlrun/model_monitoring/db/tsdb/base.py +329 -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 +240 -0
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +45 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +397 -0
- mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +117 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +630 -0
- mlrun/model_monitoring/evidently_application.py +6 -118
- mlrun/model_monitoring/features_drift_table.py +34 -22
- mlrun/model_monitoring/helpers.py +100 -7
- mlrun/model_monitoring/model_endpoint.py +3 -2
- mlrun/model_monitoring/stream_processing.py +93 -228
- mlrun/model_monitoring/tracking_policy.py +7 -1
- mlrun/model_monitoring/writer.py +152 -124
- mlrun/package/packagers_manager.py +1 -0
- mlrun/package/utils/_formatter.py +2 -2
- mlrun/platforms/__init__.py +11 -10
- mlrun/platforms/iguazio.py +21 -202
- mlrun/projects/operations.py +30 -16
- mlrun/projects/pipelines.py +92 -99
- mlrun/projects/project.py +757 -268
- mlrun/render.py +15 -14
- mlrun/run.py +160 -162
- mlrun/runtimes/__init__.py +55 -3
- mlrun/runtimes/base.py +33 -19
- mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
- mlrun/runtimes/funcdoc.py +0 -28
- mlrun/runtimes/kubejob.py +28 -122
- mlrun/runtimes/local.py +5 -2
- 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 +709 -0
- mlrun/runtimes/nuclio/application/__init__.py +15 -0
- mlrun/runtimes/nuclio/application/application.py +523 -0
- mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
- mlrun/runtimes/nuclio/function.py +98 -58
- mlrun/runtimes/nuclio/serving.py +36 -42
- mlrun/runtimes/pod.py +196 -45
- mlrun/runtimes/remotesparkjob.py +1 -1
- mlrun/runtimes/sparkjob/spark3job.py +1 -1
- mlrun/runtimes/utils.py +6 -73
- mlrun/secrets.py +6 -2
- mlrun/serving/remote.py +2 -3
- mlrun/serving/routers.py +7 -4
- mlrun/serving/server.py +7 -8
- mlrun/serving/states.py +73 -43
- mlrun/serving/v2_serving.py +8 -7
- mlrun/track/tracker.py +2 -1
- mlrun/utils/async_http.py +25 -5
- mlrun/utils/helpers.py +141 -75
- mlrun/utils/http.py +1 -1
- mlrun/utils/logger.py +39 -7
- mlrun/utils/notifications/notification/__init__.py +14 -9
- mlrun/utils/notifications/notification/base.py +12 -0
- mlrun/utils/notifications/notification/console.py +2 -0
- mlrun/utils/notifications/notification/git.py +3 -1
- mlrun/utils/notifications/notification/ipython.py +2 -0
- mlrun/utils/notifications/notification/slack.py +101 -21
- mlrun/utils/notifications/notification/webhook.py +11 -1
- mlrun/utils/notifications/notification_pusher.py +147 -16
- mlrun/utils/retryer.py +3 -2
- mlrun/utils/v3io_clients.py +0 -1
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/METADATA +33 -18
- mlrun-1.7.0rc20.dist-info/RECORD +353 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/WHEEL +1 -1
- mlrun/kfpops.py +0 -868
- mlrun/model_monitoring/batch.py +0 -974
- mlrun/model_monitoring/stores/models/__init__.py +0 -27
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -382
- mlrun/platforms/other.py +0 -305
- mlrun-1.7.0rc4.dist-info/RECORD +0 -321
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/top_level.txt +0 -0
|
@@ -12,121 +12,9 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
import
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
from mlrun.errors import MLRunIncompatibleVersionError
|
|
23
|
-
from mlrun.model_monitoring.application import ModelMonitoringApplicationBase
|
|
24
|
-
|
|
25
|
-
SUPPORTED_EVIDENTLY_VERSION = semver.Version.parse("0.4.11")
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def _check_evidently_version(*, cur: semver.Version, ref: semver.Version) -> None:
|
|
29
|
-
if ref.is_compatible(cur) or (
|
|
30
|
-
cur.major == ref.major == 0 and cur.minor == ref.minor and cur.patch > ref.patch
|
|
31
|
-
):
|
|
32
|
-
return
|
|
33
|
-
if cur.major == ref.major == 0 and cur.minor > ref.minor:
|
|
34
|
-
warnings.warn(
|
|
35
|
-
f"Evidently version {cur} is not compatible with the tested "
|
|
36
|
-
f"version {ref}, use at your own risk."
|
|
37
|
-
)
|
|
38
|
-
else:
|
|
39
|
-
raise MLRunIncompatibleVersionError(
|
|
40
|
-
f"Evidently version {cur} is not supported, please change to "
|
|
41
|
-
f"{ref} (or another compatible version)."
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
_HAS_EVIDENTLY = False
|
|
46
|
-
try:
|
|
47
|
-
import evidently # noqa: F401
|
|
48
|
-
|
|
49
|
-
_check_evidently_version(
|
|
50
|
-
cur=semver.Version.parse(evidently.__version__),
|
|
51
|
-
ref=SUPPORTED_EVIDENTLY_VERSION,
|
|
52
|
-
)
|
|
53
|
-
_HAS_EVIDENTLY = True
|
|
54
|
-
except ModuleNotFoundError:
|
|
55
|
-
pass
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if _HAS_EVIDENTLY:
|
|
59
|
-
from evidently.renderers.notebook_utils import determine_template
|
|
60
|
-
from evidently.report.report import Report
|
|
61
|
-
from evidently.suite.base_suite import Suite
|
|
62
|
-
from evidently.ui.type_aliases import STR_UUID
|
|
63
|
-
from evidently.ui.workspace import Workspace
|
|
64
|
-
from evidently.utils.dashboard import TemplateParams
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
class EvidentlyModelMonitoringApplicationBase(ModelMonitoringApplicationBase):
|
|
68
|
-
def __init__(
|
|
69
|
-
self, evidently_workspace_path: str, evidently_project_id: "STR_UUID"
|
|
70
|
-
) -> None:
|
|
71
|
-
"""
|
|
72
|
-
A class for integrating Evidently for mlrun model monitoring within a monitoring application.
|
|
73
|
-
Note: evidently is not installed by default in the mlrun/mlrun image.
|
|
74
|
-
It must be installed separately to use this class.
|
|
75
|
-
|
|
76
|
-
:param evidently_workspace_path: (str) The path to the Evidently workspace.
|
|
77
|
-
:param evidently_project_id: (str) The ID of the Evidently project.
|
|
78
|
-
|
|
79
|
-
"""
|
|
80
|
-
if not _HAS_EVIDENTLY:
|
|
81
|
-
raise ModuleNotFoundError("Evidently is not installed - the app cannot run")
|
|
82
|
-
self.evidently_workspace = Workspace.create(evidently_workspace_path)
|
|
83
|
-
self.evidently_project_id = evidently_project_id
|
|
84
|
-
self.evidently_project = self.evidently_workspace.get_project(
|
|
85
|
-
evidently_project_id
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
def log_evidently_object(
|
|
89
|
-
self, evidently_object: Union["Report", "Suite"], artifact_name: str
|
|
90
|
-
):
|
|
91
|
-
"""
|
|
92
|
-
Logs an Evidently report or suite as an artifact.
|
|
93
|
-
|
|
94
|
-
:param evidently_object: (Union[Report, Suite]) The Evidently report or suite object.
|
|
95
|
-
:param artifact_name: (str) The name for the logged artifact.
|
|
96
|
-
"""
|
|
97
|
-
evidently_object_html = evidently_object.get_html()
|
|
98
|
-
self.context.log_artifact(
|
|
99
|
-
artifact_name, body=evidently_object_html.encode("utf-8"), format="html"
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
def log_project_dashboard(
|
|
103
|
-
self,
|
|
104
|
-
timestamp_start: pd.Timestamp,
|
|
105
|
-
timestamp_end: pd.Timestamp,
|
|
106
|
-
artifact_name: str = "dashboard",
|
|
107
|
-
):
|
|
108
|
-
"""
|
|
109
|
-
Logs an Evidently project dashboard.
|
|
110
|
-
|
|
111
|
-
:param timestamp_start: (pd.Timestamp) The start timestamp for the dashboard data.
|
|
112
|
-
:param timestamp_end: (pd.Timestamp) The end timestamp for the dashboard data.
|
|
113
|
-
:param artifact_name: (str) The name for the logged artifact.
|
|
114
|
-
"""
|
|
115
|
-
|
|
116
|
-
dashboard_info = self.evidently_project.build_dashboard_info(
|
|
117
|
-
timestamp_start, timestamp_end
|
|
118
|
-
)
|
|
119
|
-
template_params = TemplateParams(
|
|
120
|
-
dashboard_id="pd_" + str(uuid.uuid4()).replace("-", ""),
|
|
121
|
-
dashboard_info=dashboard_info,
|
|
122
|
-
additional_graphs={},
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
dashboard_html = self._render(determine_template("inline"), template_params)
|
|
126
|
-
self.context.log_artifact(
|
|
127
|
-
artifact_name, body=dashboard_html.encode("utf-8"), format="html"
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
@staticmethod
|
|
131
|
-
def _render(temple_func, template_params: "TemplateParams"):
|
|
132
|
-
return temple_func(params=template_params)
|
|
15
|
+
# TODO : delete this file in 1.9.0
|
|
16
|
+
from mlrun.model_monitoring.applications import ( # noqa: F401
|
|
17
|
+
_HAS_EVIDENTLY,
|
|
18
|
+
SUPPORTED_EVIDENTLY_VERSION,
|
|
19
|
+
EvidentlyModelMonitoringApplicationBase,
|
|
20
|
+
)
|
|
@@ -21,9 +21,34 @@ import plotly.graph_objects as go
|
|
|
21
21
|
from plotly.subplots import make_subplots
|
|
22
22
|
|
|
23
23
|
import mlrun.common.schemas.model_monitoring
|
|
24
|
+
from mlrun.artifacts import PlotlyArtifact
|
|
24
25
|
|
|
25
26
|
# A type for representing a drift result, a tuple of the status and the drift mean:
|
|
26
|
-
DriftResultType = tuple[
|
|
27
|
+
DriftResultType = tuple[
|
|
28
|
+
mlrun.common.schemas.model_monitoring.constants.ResultStatusApp, float
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class _PlotlyTableArtifact(PlotlyArtifact):
|
|
33
|
+
"""A custom class for plotly table artifacts"""
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def _disable_table_dragging(figure_html: str) -> str:
|
|
37
|
+
"""
|
|
38
|
+
Disable the table columns dragging by adding the following
|
|
39
|
+
JavaScript code
|
|
40
|
+
"""
|
|
41
|
+
start, end = figure_html.rsplit(";", 1)
|
|
42
|
+
middle = (
|
|
43
|
+
';for (const element of document.getElementsByClassName("table")) '
|
|
44
|
+
'{element.style.pointerEvents = "none";}'
|
|
45
|
+
)
|
|
46
|
+
figure_html = start + middle + end
|
|
47
|
+
return figure_html
|
|
48
|
+
|
|
49
|
+
def get_body(self) -> str:
|
|
50
|
+
"""Get the adjusted HTML representation of the figure"""
|
|
51
|
+
return self._disable_table_dragging(super().get_body())
|
|
27
52
|
|
|
28
53
|
|
|
29
54
|
class FeaturesDriftTablePlot:
|
|
@@ -62,9 +87,9 @@ class FeaturesDriftTablePlot:
|
|
|
62
87
|
|
|
63
88
|
# Status configurations:
|
|
64
89
|
_STATUS_COLORS = {
|
|
65
|
-
mlrun.common.schemas.model_monitoring.
|
|
66
|
-
mlrun.common.schemas.model_monitoring.
|
|
67
|
-
mlrun.common.schemas.model_monitoring.
|
|
90
|
+
mlrun.common.schemas.model_monitoring.constants.ResultStatusApp.no_detection: "rgb(0,176,80)", # Green
|
|
91
|
+
mlrun.common.schemas.model_monitoring.constants.ResultStatusApp.potential_detection: "rgb(255,192,0)", # Orange
|
|
92
|
+
mlrun.common.schemas.model_monitoring.constants.ResultStatusApp.detected: "rgb(208,0,106)", # Magenta
|
|
68
93
|
}
|
|
69
94
|
|
|
70
95
|
# Font configurations:
|
|
@@ -97,7 +122,7 @@ class FeaturesDriftTablePlot:
|
|
|
97
122
|
inputs_statistics: dict,
|
|
98
123
|
metrics: dict[str, Union[dict, float]],
|
|
99
124
|
drift_results: dict[str, DriftResultType],
|
|
100
|
-
) ->
|
|
125
|
+
) -> _PlotlyTableArtifact:
|
|
101
126
|
"""
|
|
102
127
|
Produce the html code of the table plot with the given information and the stored configurations in the class.
|
|
103
128
|
|
|
@@ -106,9 +131,8 @@ class FeaturesDriftTablePlot:
|
|
|
106
131
|
:param metrics: The drift detection metrics calculated on the sample set and inputs.
|
|
107
132
|
:param drift_results: The drift results per feature according to the rules of the monitor.
|
|
108
133
|
|
|
109
|
-
:return: The
|
|
134
|
+
:return: The drift table as a plotly artifact.
|
|
110
135
|
"""
|
|
111
|
-
# Plot the drift table:
|
|
112
136
|
figure = self._plot(
|
|
113
137
|
features=list(inputs_statistics.keys()),
|
|
114
138
|
sample_set_statistics=sample_set_statistics,
|
|
@@ -116,19 +140,7 @@ class FeaturesDriftTablePlot:
|
|
|
116
140
|
metrics=metrics,
|
|
117
141
|
drift_results=drift_results,
|
|
118
142
|
)
|
|
119
|
-
|
|
120
|
-
# Get its HTML representation:
|
|
121
|
-
figure_html = figure.to_html()
|
|
122
|
-
|
|
123
|
-
# Turn off the table columns dragging by injecting the following JavaScript code:
|
|
124
|
-
start, end = figure_html.rsplit(";", 1)
|
|
125
|
-
middle = (
|
|
126
|
-
';for (const element of document.getElementsByClassName("table")) '
|
|
127
|
-
'{element.style.pointerEvents = "none";}'
|
|
128
|
-
)
|
|
129
|
-
figure_html = start + middle + end
|
|
130
|
-
|
|
131
|
-
return figure_html
|
|
143
|
+
return _PlotlyTableArtifact(figure=figure, key="drift_table_plot")
|
|
132
144
|
|
|
133
145
|
def _read_columns_names(self, statistics_dictionary: dict, drift_metrics: dict):
|
|
134
146
|
"""
|
|
@@ -366,10 +378,10 @@ class FeaturesDriftTablePlot:
|
|
|
366
378
|
bins = np.array(bins)
|
|
367
379
|
if bins[0] == -sys.float_info.max:
|
|
368
380
|
bins[0] = bins[1] - (bins[2] - bins[1])
|
|
369
|
-
hovertext[0] = f"(
|
|
381
|
+
hovertext[0] = f"(-inf, {bins[1]})"
|
|
370
382
|
if bins[-1] == sys.float_info.max:
|
|
371
383
|
bins[-1] = bins[-2] + (bins[-2] - bins[-3])
|
|
372
|
-
hovertext[-1] = f"({bins[-2]},
|
|
384
|
+
hovertext[-1] = f"({bins[-2]}, inf)"
|
|
373
385
|
# Center the bins (leave the first one):
|
|
374
386
|
bins = 0.5 * (bins[:-1] + bins[1:])
|
|
375
387
|
# Plot the histogram as a line with filled background below it:
|
|
@@ -15,12 +15,19 @@
|
|
|
15
15
|
import datetime
|
|
16
16
|
import typing
|
|
17
17
|
|
|
18
|
+
import numpy as np
|
|
19
|
+
import pandas as pd
|
|
20
|
+
|
|
18
21
|
import mlrun
|
|
19
22
|
import mlrun.common.model_monitoring.helpers
|
|
20
23
|
import mlrun.common.schemas
|
|
21
24
|
from mlrun.common.schemas.model_monitoring import (
|
|
22
25
|
EventFieldType,
|
|
23
26
|
)
|
|
27
|
+
from mlrun.common.schemas.model_monitoring.model_endpoints import (
|
|
28
|
+
ModelEndpointMonitoringMetricType,
|
|
29
|
+
_compose_full_name,
|
|
30
|
+
)
|
|
24
31
|
from mlrun.model_monitoring.model_endpoint import ModelEndpoint
|
|
25
32
|
from mlrun.utils import logger
|
|
26
33
|
|
|
@@ -36,14 +43,10 @@ class _BatchDict(typing.TypedDict):
|
|
|
36
43
|
days: int
|
|
37
44
|
|
|
38
45
|
|
|
39
|
-
class _MLRunNoRunsFoundError(Exception):
|
|
40
|
-
pass
|
|
41
|
-
|
|
42
|
-
|
|
43
46
|
def get_stream_path(
|
|
44
47
|
project: str = None,
|
|
45
48
|
function_name: str = mm_constants.MonitoringFunctionNames.STREAM,
|
|
46
|
-
):
|
|
49
|
+
) -> str:
|
|
47
50
|
"""
|
|
48
51
|
Get stream path from the project secret. If wasn't set, take it from the system configurations
|
|
49
52
|
|
|
@@ -55,8 +58,6 @@ def get_stream_path(
|
|
|
55
58
|
|
|
56
59
|
stream_uri = mlrun.get_secret_or_env(
|
|
57
60
|
mlrun.common.schemas.model_monitoring.ProjectSecretKeys.STREAM_PATH
|
|
58
|
-
if function_name is mm_constants.MonitoringFunctionNames.STREAM
|
|
59
|
-
else ""
|
|
60
61
|
) or mlrun.mlconf.get_model_monitoring_file_target_path(
|
|
61
62
|
project=project,
|
|
62
63
|
kind=mlrun.common.schemas.model_monitoring.FileTargetKind.STREAM,
|
|
@@ -64,6 +65,8 @@ def get_stream_path(
|
|
|
64
65
|
function_name=function_name,
|
|
65
66
|
)
|
|
66
67
|
|
|
68
|
+
if isinstance(stream_uri, list): # ML-6043 - user side gets only the new stream uri
|
|
69
|
+
stream_uri = stream_uri[1] # get new stream path, under projects
|
|
67
70
|
return mlrun.common.model_monitoring.helpers.parse_monitoring_stream_path(
|
|
68
71
|
stream_uri=stream_uri, project=project, function_name=function_name
|
|
69
72
|
)
|
|
@@ -112,6 +115,24 @@ def get_connection_string(secret_provider: typing.Callable = None) -> str:
|
|
|
112
115
|
)
|
|
113
116
|
|
|
114
117
|
|
|
118
|
+
def get_tsdb_connection_string(
|
|
119
|
+
secret_provider: typing.Optional[typing.Callable] = None,
|
|
120
|
+
) -> str:
|
|
121
|
+
"""Get TSDB connection string from the project secret. If wasn't set, take it from the system
|
|
122
|
+
configurations.
|
|
123
|
+
:param secret_provider: An optional secret provider to get the connection string secret.
|
|
124
|
+
:return: Valid TSDB connection string.
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
return (
|
|
128
|
+
mlrun.get_secret_or_env(
|
|
129
|
+
key=mlrun.common.schemas.model_monitoring.ProjectSecretKeys.TSDB_CONNECTION,
|
|
130
|
+
secret_provider=secret_provider,
|
|
131
|
+
)
|
|
132
|
+
or mlrun.mlconf.model_endpoint_monitoring.tsdb_connection
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
|
|
115
136
|
def batch_dict2timedelta(batch_dict: _BatchDict) -> datetime.timedelta:
|
|
116
137
|
"""
|
|
117
138
|
Convert a batch dictionary to timedelta.
|
|
@@ -212,3 +233,75 @@ def update_model_endpoint_last_request(
|
|
|
212
233
|
endpoint_id=model_endpoint.metadata.uid,
|
|
213
234
|
attributes={EventFieldType.LAST_REQUEST: bumped_last_request},
|
|
214
235
|
)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def calculate_inputs_statistics(
|
|
239
|
+
sample_set_statistics: dict, inputs: pd.DataFrame
|
|
240
|
+
) -> mlrun.common.model_monitoring.helpers.FeatureStats:
|
|
241
|
+
"""
|
|
242
|
+
Calculate the inputs data statistics for drift monitoring purpose.
|
|
243
|
+
|
|
244
|
+
:param sample_set_statistics: The sample set (stored end point's dataset to reference) statistics. The bins of the
|
|
245
|
+
histograms of each feature will be used to recalculate the histograms of the inputs.
|
|
246
|
+
:param inputs: The inputs to calculate their statistics and later on - the drift with respect to the
|
|
247
|
+
sample set.
|
|
248
|
+
|
|
249
|
+
:returns: The calculated statistics of the inputs data.
|
|
250
|
+
"""
|
|
251
|
+
|
|
252
|
+
# Use `DFDataInfer` to calculate the statistics over the inputs:
|
|
253
|
+
inputs_statistics = mlrun.data_types.infer.DFDataInfer.get_stats(
|
|
254
|
+
df=inputs,
|
|
255
|
+
options=mlrun.data_types.infer.InferOptions.Histogram,
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
# Recalculate the histograms over the bins that are set in the sample-set of the end point:
|
|
259
|
+
for feature in inputs_statistics.keys():
|
|
260
|
+
if feature in sample_set_statistics:
|
|
261
|
+
counts, bins = np.histogram(
|
|
262
|
+
inputs[feature].to_numpy(),
|
|
263
|
+
bins=sample_set_statistics[feature]["hist"][1],
|
|
264
|
+
)
|
|
265
|
+
inputs_statistics[feature]["hist"] = [
|
|
266
|
+
counts.tolist(),
|
|
267
|
+
bins.tolist(),
|
|
268
|
+
]
|
|
269
|
+
elif "hist" in inputs_statistics[feature]:
|
|
270
|
+
# Comply with the other common features' histogram length
|
|
271
|
+
mlrun.common.model_monitoring.helpers.pad_hist(
|
|
272
|
+
mlrun.common.model_monitoring.helpers.Histogram(
|
|
273
|
+
inputs_statistics[feature]["hist"]
|
|
274
|
+
)
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
return inputs_statistics
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def get_endpoint_record(project: str, endpoint_id: str):
|
|
281
|
+
model_endpoint_store = mlrun.model_monitoring.get_store_object(
|
|
282
|
+
project=project,
|
|
283
|
+
)
|
|
284
|
+
return model_endpoint_store.get_model_endpoint(endpoint_id=endpoint_id)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def get_result_instance_fqn(
|
|
288
|
+
model_endpoint_id: str, app_name: str, result_name: str
|
|
289
|
+
) -> str:
|
|
290
|
+
return f"{model_endpoint_id}.{app_name}.result.{result_name}"
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def get_default_result_instance_fqn(model_endpoint_id: str) -> str:
|
|
294
|
+
return get_result_instance_fqn(
|
|
295
|
+
model_endpoint_id,
|
|
296
|
+
mm_constants.HistogramDataDriftApplicationConstants.NAME,
|
|
297
|
+
mm_constants.HistogramDataDriftApplicationConstants.GENERAL_RESULT_NAME,
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def get_invocations_fqn(project: str) -> str:
|
|
302
|
+
return _compose_full_name(
|
|
303
|
+
project=project,
|
|
304
|
+
app=mm_constants.SpecialApps.MLRUN_INFRA,
|
|
305
|
+
name=mm_constants.PredictionsQueryConstants.INVOCATIONS,
|
|
306
|
+
type=ModelEndpointMonitoringMetricType.METRIC,
|
|
307
|
+
)
|
|
@@ -17,6 +17,7 @@ from dataclasses import dataclass, field
|
|
|
17
17
|
from typing import Any
|
|
18
18
|
|
|
19
19
|
import mlrun.model
|
|
20
|
+
from mlrun.common.model_monitoring.helpers import FeatureStats
|
|
20
21
|
from mlrun.common.schemas.model_monitoring.constants import (
|
|
21
22
|
EndpointType,
|
|
22
23
|
EventKeyMetrics,
|
|
@@ -42,8 +43,8 @@ class ModelEndpointSpec(mlrun.model.ModelObj):
|
|
|
42
43
|
|
|
43
44
|
@dataclass
|
|
44
45
|
class ModelEndpointStatus(mlrun.model.ModelObj):
|
|
45
|
-
feature_stats:
|
|
46
|
-
current_stats:
|
|
46
|
+
feature_stats: FeatureStats = field(default_factory=dict)
|
|
47
|
+
current_stats: FeatureStats = field(default_factory=dict)
|
|
47
48
|
first_request: str = ""
|
|
48
49
|
last_request: str = ""
|
|
49
50
|
error_count: int = 0
|