mlrun 1.7.2__py3-none-any.whl → 1.8.0rc1__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 +14 -12
- mlrun/__main__.py +3 -3
- mlrun/alerts/alert.py +19 -12
- mlrun/artifacts/__init__.py +0 -2
- mlrun/artifacts/base.py +34 -11
- mlrun/artifacts/dataset.py +16 -16
- mlrun/artifacts/manager.py +13 -13
- mlrun/artifacts/model.py +66 -53
- mlrun/common/constants.py +6 -0
- mlrun/common/formatters/__init__.py +1 -0
- mlrun/common/formatters/feature_set.py +1 -0
- mlrun/common/formatters/function.py +1 -0
- mlrun/common/formatters/model_endpoint.py +30 -0
- mlrun/common/formatters/pipeline.py +1 -2
- mlrun/common/model_monitoring/__init__.py +0 -3
- mlrun/common/model_monitoring/helpers.py +1 -1
- mlrun/common/runtimes/constants.py +1 -2
- mlrun/common/schemas/__init__.py +4 -2
- mlrun/common/schemas/artifact.py +0 -6
- mlrun/common/schemas/common.py +50 -0
- mlrun/common/schemas/model_monitoring/__init__.py +8 -1
- mlrun/common/schemas/model_monitoring/constants.py +62 -12
- mlrun/common/schemas/model_monitoring/model_endpoint_v2.py +149 -0
- mlrun/common/schemas/model_monitoring/model_endpoints.py +21 -5
- mlrun/common/schemas/partition.py +122 -0
- mlrun/config.py +43 -15
- mlrun/data_types/__init__.py +0 -2
- mlrun/data_types/data_types.py +0 -1
- mlrun/data_types/infer.py +3 -1
- mlrun/data_types/spark.py +4 -4
- mlrun/data_types/to_pandas.py +2 -11
- mlrun/datastore/__init__.py +0 -2
- mlrun/datastore/alibaba_oss.py +4 -1
- mlrun/datastore/azure_blob.py +4 -1
- mlrun/datastore/base.py +12 -4
- mlrun/datastore/datastore.py +9 -3
- mlrun/datastore/datastore_profile.py +1 -1
- mlrun/datastore/dbfs_store.py +4 -1
- mlrun/datastore/filestore.py +4 -1
- mlrun/datastore/google_cloud_storage.py +4 -1
- mlrun/datastore/hdfs.py +4 -1
- mlrun/datastore/inmem.py +4 -1
- mlrun/datastore/redis.py +4 -1
- mlrun/datastore/s3.py +4 -1
- mlrun/datastore/sources.py +51 -49
- mlrun/datastore/store_resources.py +0 -2
- mlrun/datastore/targets.py +22 -23
- mlrun/datastore/utils.py +2 -2
- mlrun/datastore/v3io.py +4 -1
- mlrun/datastore/wasbfs/fs.py +13 -12
- mlrun/db/base.py +126 -62
- mlrun/db/factory.py +3 -0
- mlrun/db/httpdb.py +767 -231
- mlrun/db/nopdb.py +126 -57
- mlrun/errors.py +2 -2
- mlrun/execution.py +55 -29
- mlrun/feature_store/__init__.py +0 -2
- mlrun/feature_store/api.py +40 -40
- mlrun/feature_store/common.py +9 -9
- mlrun/feature_store/feature_set.py +20 -18
- mlrun/feature_store/feature_vector.py +27 -24
- mlrun/feature_store/retrieval/base.py +14 -9
- mlrun/feature_store/retrieval/job.py +2 -1
- mlrun/feature_store/steps.py +2 -2
- mlrun/features.py +30 -13
- mlrun/frameworks/__init__.py +1 -2
- mlrun/frameworks/_common/__init__.py +1 -2
- mlrun/frameworks/_common/artifacts_library.py +2 -2
- mlrun/frameworks/_common/mlrun_interface.py +10 -6
- mlrun/frameworks/_common/model_handler.py +29 -27
- mlrun/frameworks/_common/producer.py +3 -1
- mlrun/frameworks/_dl_common/__init__.py +1 -2
- mlrun/frameworks/_dl_common/loggers/__init__.py +1 -2
- mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +4 -4
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +3 -3
- mlrun/frameworks/_ml_common/__init__.py +1 -2
- mlrun/frameworks/_ml_common/loggers/__init__.py +1 -2
- mlrun/frameworks/_ml_common/model_handler.py +21 -21
- mlrun/frameworks/_ml_common/plans/__init__.py +1 -2
- mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +3 -1
- mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
- mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
- mlrun/frameworks/auto_mlrun/__init__.py +1 -2
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +22 -15
- mlrun/frameworks/huggingface/__init__.py +1 -2
- mlrun/frameworks/huggingface/model_server.py +9 -9
- mlrun/frameworks/lgbm/__init__.py +47 -44
- mlrun/frameworks/lgbm/callbacks/__init__.py +1 -2
- mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -2
- mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -2
- mlrun/frameworks/lgbm/mlrun_interfaces/__init__.py +1 -2
- mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +5 -5
- mlrun/frameworks/lgbm/model_handler.py +15 -11
- mlrun/frameworks/lgbm/model_server.py +11 -7
- mlrun/frameworks/lgbm/utils.py +2 -2
- mlrun/frameworks/onnx/__init__.py +1 -2
- mlrun/frameworks/onnx/dataset.py +3 -3
- mlrun/frameworks/onnx/mlrun_interface.py +2 -2
- mlrun/frameworks/onnx/model_handler.py +7 -5
- mlrun/frameworks/onnx/model_server.py +8 -6
- mlrun/frameworks/parallel_coordinates.py +11 -11
- mlrun/frameworks/pytorch/__init__.py +22 -23
- mlrun/frameworks/pytorch/callbacks/__init__.py +1 -2
- mlrun/frameworks/pytorch/callbacks/callback.py +2 -1
- mlrun/frameworks/pytorch/callbacks/logging_callback.py +15 -8
- mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +19 -12
- mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +22 -15
- mlrun/frameworks/pytorch/callbacks_handler.py +36 -30
- mlrun/frameworks/pytorch/mlrun_interface.py +17 -17
- mlrun/frameworks/pytorch/model_handler.py +21 -17
- mlrun/frameworks/pytorch/model_server.py +13 -9
- mlrun/frameworks/sklearn/__init__.py +19 -18
- mlrun/frameworks/sklearn/estimator.py +2 -2
- mlrun/frameworks/sklearn/metric.py +3 -3
- mlrun/frameworks/sklearn/metrics_library.py +8 -6
- mlrun/frameworks/sklearn/mlrun_interface.py +3 -2
- mlrun/frameworks/sklearn/model_handler.py +4 -3
- mlrun/frameworks/tf_keras/__init__.py +11 -12
- mlrun/frameworks/tf_keras/callbacks/__init__.py +1 -2
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +17 -14
- mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +15 -12
- mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +21 -18
- mlrun/frameworks/tf_keras/model_handler.py +17 -13
- mlrun/frameworks/tf_keras/model_server.py +12 -8
- mlrun/frameworks/xgboost/__init__.py +19 -18
- mlrun/frameworks/xgboost/model_handler.py +13 -9
- mlrun/launcher/base.py +3 -4
- mlrun/launcher/local.py +1 -1
- mlrun/launcher/remote.py +1 -1
- mlrun/lists.py +4 -3
- mlrun/model.py +108 -44
- mlrun/model_monitoring/__init__.py +1 -2
- mlrun/model_monitoring/api.py +6 -6
- mlrun/model_monitoring/applications/_application_steps.py +13 -15
- mlrun/model_monitoring/applications/histogram_data_drift.py +41 -15
- mlrun/model_monitoring/applications/results.py +55 -3
- mlrun/model_monitoring/controller.py +185 -223
- mlrun/model_monitoring/db/_schedules.py +156 -0
- mlrun/model_monitoring/db/_stats.py +189 -0
- mlrun/model_monitoring/db/stores/__init__.py +1 -1
- mlrun/model_monitoring/db/stores/base/store.py +6 -65
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -25
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -97
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +2 -58
- mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -15
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +6 -257
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +9 -271
- mlrun/model_monitoring/db/tsdb/base.py +74 -22
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +66 -35
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +33 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +284 -51
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +1 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +35 -17
- mlrun/model_monitoring/helpers.py +97 -1
- mlrun/model_monitoring/model_endpoint.py +4 -2
- mlrun/model_monitoring/stream_processing.py +2 -2
- mlrun/model_monitoring/tracking_policy.py +10 -3
- mlrun/model_monitoring/writer.py +47 -26
- mlrun/package/__init__.py +3 -6
- mlrun/package/context_handler.py +1 -1
- mlrun/package/packager.py +12 -9
- mlrun/package/packagers/__init__.py +0 -2
- mlrun/package/packagers/default_packager.py +14 -11
- mlrun/package/packagers/numpy_packagers.py +16 -7
- mlrun/package/packagers/pandas_packagers.py +18 -18
- mlrun/package/packagers/python_standard_library_packagers.py +25 -11
- mlrun/package/packagers_manager.py +31 -14
- mlrun/package/utils/__init__.py +0 -3
- mlrun/package/utils/_pickler.py +6 -6
- mlrun/platforms/__init__.py +3 -3
- mlrun/platforms/iguazio.py +4 -1
- mlrun/projects/__init__.py +1 -6
- mlrun/projects/operations.py +27 -27
- mlrun/projects/pipelines.py +85 -215
- mlrun/projects/project.py +444 -158
- mlrun/run.py +9 -9
- mlrun/runtimes/__init__.py +1 -3
- mlrun/runtimes/base.py +13 -10
- mlrun/runtimes/daskjob.py +9 -9
- mlrun/runtimes/generators.py +2 -1
- mlrun/runtimes/kubejob.py +4 -5
- mlrun/runtimes/mpijob/__init__.py +0 -2
- mlrun/runtimes/mpijob/abstract.py +7 -6
- mlrun/runtimes/nuclio/api_gateway.py +7 -7
- mlrun/runtimes/nuclio/application/application.py +11 -11
- mlrun/runtimes/nuclio/function.py +14 -14
- mlrun/runtimes/nuclio/serving.py +9 -9
- mlrun/runtimes/pod.py +74 -29
- mlrun/runtimes/remotesparkjob.py +3 -2
- mlrun/runtimes/sparkjob/__init__.py +0 -2
- mlrun/runtimes/sparkjob/spark3job.py +21 -11
- mlrun/runtimes/utils.py +6 -5
- mlrun/serving/merger.py +6 -4
- mlrun/serving/remote.py +18 -17
- mlrun/serving/routers.py +27 -27
- mlrun/serving/server.py +1 -1
- mlrun/serving/states.py +76 -71
- mlrun/serving/utils.py +13 -2
- mlrun/serving/v1_serving.py +3 -2
- mlrun/serving/v2_serving.py +4 -4
- mlrun/track/__init__.py +1 -1
- mlrun/track/tracker.py +2 -2
- mlrun/track/trackers/mlflow_tracker.py +6 -5
- mlrun/utils/async_http.py +1 -1
- mlrun/utils/helpers.py +72 -28
- mlrun/utils/logger.py +104 -2
- mlrun/utils/notifications/notification/base.py +23 -4
- mlrun/utils/notifications/notification/console.py +1 -1
- mlrun/utils/notifications/notification/git.py +6 -6
- mlrun/utils/notifications/notification/ipython.py +5 -4
- mlrun/utils/notifications/notification/slack.py +1 -1
- mlrun/utils/notifications/notification/webhook.py +13 -17
- mlrun/utils/notifications/notification_pusher.py +23 -19
- mlrun/utils/regex.py +1 -1
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.2.dist-info → mlrun-1.8.0rc1.dist-info}/METADATA +187 -199
- mlrun-1.8.0rc1.dist-info/RECORD +356 -0
- {mlrun-1.7.2.dist-info → mlrun-1.8.0rc1.dist-info}/WHEEL +1 -1
- mlrun-1.7.2.dist-info/RECORD +0 -351
- {mlrun-1.7.2.dist-info → mlrun-1.8.0rc1.dist-info}/LICENSE +0 -0
- {mlrun-1.7.2.dist-info → mlrun-1.8.0rc1.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.2.dist-info → mlrun-1.8.0rc1.dist-info}/top_level.txt +0 -0
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
import datetime
|
|
16
|
+
import os
|
|
16
17
|
import typing
|
|
17
18
|
|
|
18
19
|
import numpy as np
|
|
@@ -27,7 +28,9 @@ import mlrun.artifacts
|
|
|
27
28
|
import mlrun.common.model_monitoring.helpers
|
|
28
29
|
import mlrun.common.schemas.model_monitoring.constants as mm_constants
|
|
29
30
|
import mlrun.data_types.infer
|
|
31
|
+
import mlrun.datastore
|
|
30
32
|
import mlrun.model_monitoring
|
|
33
|
+
import mlrun.utils.helpers
|
|
31
34
|
from mlrun.common.schemas.model_monitoring.model_endpoints import (
|
|
32
35
|
ModelEndpointMonitoringMetric,
|
|
33
36
|
_compose_full_name,
|
|
@@ -98,7 +101,74 @@ def get_monitoring_parquet_path(
|
|
|
98
101
|
return parquet_path
|
|
99
102
|
|
|
100
103
|
|
|
101
|
-
def
|
|
104
|
+
def get_monitoring_stats_directory_path(
|
|
105
|
+
project: str,
|
|
106
|
+
kind: str = mm_constants.FileTargetKind.STATS,
|
|
107
|
+
) -> str:
|
|
108
|
+
"""
|
|
109
|
+
Get model monitoring stats target for the current project and kind. The stats target path is based on the
|
|
110
|
+
project artifact path. If project artifact path is not defined, the stats target path will be based on MLRun
|
|
111
|
+
artifact path.
|
|
112
|
+
:param project: Project object.
|
|
113
|
+
:param kind: indicate the kind of the stats path
|
|
114
|
+
:return: Monitoring stats target path.
|
|
115
|
+
"""
|
|
116
|
+
stats_path = mlrun.mlconf.get_model_monitoring_file_target_path(
|
|
117
|
+
project=project,
|
|
118
|
+
kind=kind,
|
|
119
|
+
)
|
|
120
|
+
return stats_path
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _get_monitoring_current_stats_file_path(project: str, endpoint_id: str) -> str:
|
|
124
|
+
return os.path.join(
|
|
125
|
+
get_monitoring_stats_directory_path(project),
|
|
126
|
+
f"{endpoint_id}_current_stats.json",
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _get_monitoring_drift_measures_file_path(project: str, endpoint_id: str) -> str:
|
|
131
|
+
return os.path.join(
|
|
132
|
+
get_monitoring_stats_directory_path(project),
|
|
133
|
+
f"{endpoint_id}_drift_measures.json",
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def get_monitoring_current_stats_data(
|
|
138
|
+
project: str, endpoint_id: str
|
|
139
|
+
) -> mlrun.datastore.DataItem:
|
|
140
|
+
"""
|
|
141
|
+
getter for data item of current stats for project and endpoint
|
|
142
|
+
:param project: project name str
|
|
143
|
+
:param endpoint_id: endpoint id str
|
|
144
|
+
:return: DataItem
|
|
145
|
+
"""
|
|
146
|
+
return mlrun.datastore.store_manager.object(
|
|
147
|
+
_get_monitoring_current_stats_file_path(
|
|
148
|
+
project=project, endpoint_id=endpoint_id
|
|
149
|
+
)
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def get_monitoring_drift_measures_data(
|
|
154
|
+
project: str, endpoint_id: str
|
|
155
|
+
) -> mlrun.datastore.DataItem:
|
|
156
|
+
"""
|
|
157
|
+
getter for data item of drift measures for project and endpoint
|
|
158
|
+
:param project: project name str
|
|
159
|
+
:param endpoint_id: endpoint id str
|
|
160
|
+
:return: DataItem
|
|
161
|
+
"""
|
|
162
|
+
return mlrun.datastore.store_manager.object(
|
|
163
|
+
_get_monitoring_drift_measures_file_path(
|
|
164
|
+
project=project, endpoint_id=endpoint_id
|
|
165
|
+
)
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def get_connection_string(
|
|
170
|
+
secret_provider: typing.Optional[typing.Callable[[str], str]] = None,
|
|
171
|
+
) -> str:
|
|
102
172
|
"""Get endpoint store connection string from the project secret. If wasn't set, take it from the system
|
|
103
173
|
configurations.
|
|
104
174
|
|
|
@@ -350,3 +420,29 @@ def enrich_model_endpoint_with_model_uri(
|
|
|
350
420
|
model_endpoint.spec.model_uri = mlrun.datastore.get_store_uri(
|
|
351
421
|
kind=mlrun.utils.helpers.StorePrefix.Model, uri=model_artifact_uri
|
|
352
422
|
)
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def _get_monitoring_schedules_folder_path(project: str) -> str:
|
|
426
|
+
return typing.cast(
|
|
427
|
+
str,
|
|
428
|
+
mlrun.mlconf.get_model_monitoring_file_target_path(
|
|
429
|
+
project=project, kind=mm_constants.FileTargetKind.MONITORING_SCHEDULES
|
|
430
|
+
),
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def _get_monitoring_schedules_file_path(*, project: str, endpoint_id: str) -> str:
|
|
435
|
+
return os.path.join(
|
|
436
|
+
_get_monitoring_schedules_folder_path(project), f"{endpoint_id}.json"
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def get_monitoring_schedules_data(
|
|
441
|
+
*, project: str, endpoint_id: str
|
|
442
|
+
) -> mlrun.datastore.DataItem:
|
|
443
|
+
"""
|
|
444
|
+
Get the model monitoring schedules' data item of the project's model endpoint.
|
|
445
|
+
"""
|
|
446
|
+
return mlrun.datastore.store_manager.object(
|
|
447
|
+
_get_monitoring_schedules_file_path(project=project, endpoint_id=endpoint_id)
|
|
448
|
+
)
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
#
|
|
15
15
|
|
|
16
16
|
from dataclasses import dataclass, field
|
|
17
|
-
from typing import Any
|
|
17
|
+
from typing import Any, Optional
|
|
18
18
|
|
|
19
19
|
import mlrun.model
|
|
20
20
|
from mlrun.common.model_monitoring.helpers import FeatureStats
|
|
@@ -104,7 +104,9 @@ class ModelEndpoint(mlrun.model.ModelObj):
|
|
|
104
104
|
)
|
|
105
105
|
|
|
106
106
|
@classmethod
|
|
107
|
-
def from_flat_dict(
|
|
107
|
+
def from_flat_dict(
|
|
108
|
+
cls, struct=None, fields=None, deprecated_fields: Optional[dict] = None
|
|
109
|
+
):
|
|
108
110
|
new_obj = cls()
|
|
109
111
|
new_obj._metadata = mlrun.model.VersionedObjMetadata().from_dict(
|
|
110
112
|
struct=struct, fields=fields, deprecated_fields=deprecated_fields
|
|
@@ -51,7 +51,7 @@ class EventStreamProcessor:
|
|
|
51
51
|
parquet_target: str,
|
|
52
52
|
aggregate_windows: typing.Optional[list[str]] = None,
|
|
53
53
|
aggregate_period: str = "5m",
|
|
54
|
-
model_monitoring_access_key: str = None,
|
|
54
|
+
model_monitoring_access_key: typing.Optional[str] = None,
|
|
55
55
|
):
|
|
56
56
|
# General configurations, mainly used for the storey steps in the future serving graph
|
|
57
57
|
self.project = project
|
|
@@ -85,7 +85,7 @@ class EventStreamProcessor:
|
|
|
85
85
|
v3io_access_key: typing.Optional[str] = None,
|
|
86
86
|
v3io_framesd: typing.Optional[str] = None,
|
|
87
87
|
v3io_api: typing.Optional[str] = None,
|
|
88
|
-
model_monitoring_access_key: str = None,
|
|
88
|
+
model_monitoring_access_key: typing.Optional[str] = None,
|
|
89
89
|
):
|
|
90
90
|
# Get the V3IO configurations
|
|
91
91
|
self.v3io_framesd = v3io_framesd or mlrun.mlconf.v3io_framesd
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
import warnings
|
|
16
|
-
from typing import Union
|
|
16
|
+
from typing import Optional, Union
|
|
17
17
|
|
|
18
18
|
import mlrun.common.schemas.schedule
|
|
19
19
|
import mlrun.model
|
|
@@ -74,7 +74,9 @@ class TrackingPolicy(mlrun.model.ModelObj):
|
|
|
74
74
|
self.default_controller_image = default_controller_image
|
|
75
75
|
|
|
76
76
|
@classmethod
|
|
77
|
-
def from_dict(
|
|
77
|
+
def from_dict(
|
|
78
|
+
cls, struct=None, fields=None, deprecated_fields: Optional[dict] = None
|
|
79
|
+
):
|
|
78
80
|
new_obj = super().from_dict(
|
|
79
81
|
struct, fields=cls._dict_fields, deprecated_fields=deprecated_fields
|
|
80
82
|
)
|
|
@@ -102,7 +104,12 @@ class TrackingPolicy(mlrun.model.ModelObj):
|
|
|
102
104
|
)
|
|
103
105
|
return new_obj
|
|
104
106
|
|
|
105
|
-
def to_dict(
|
|
107
|
+
def to_dict(
|
|
108
|
+
self,
|
|
109
|
+
fields: Optional[list] = None,
|
|
110
|
+
exclude: Optional[list] = None,
|
|
111
|
+
strip: bool = False,
|
|
112
|
+
):
|
|
106
113
|
struct = super().to_dict(
|
|
107
114
|
fields,
|
|
108
115
|
exclude=[
|
mlrun/model_monitoring/writer.py
CHANGED
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
import json
|
|
16
|
-
from
|
|
16
|
+
from datetime import datetime, timezone
|
|
17
|
+
from typing import Any, Callable, NewType, Optional
|
|
17
18
|
|
|
18
19
|
import mlrun.common.model_monitoring
|
|
19
20
|
import mlrun.common.schemas
|
|
@@ -26,10 +27,16 @@ from mlrun.common.schemas.model_monitoring.constants import (
|
|
|
26
27
|
ResultData,
|
|
27
28
|
ResultKindApp,
|
|
28
29
|
ResultStatusApp,
|
|
30
|
+
StatsData,
|
|
31
|
+
StatsKind,
|
|
29
32
|
WriterEvent,
|
|
30
33
|
WriterEventKind,
|
|
31
34
|
)
|
|
32
35
|
from mlrun.common.schemas.notification import NotificationKind, NotificationSeverity
|
|
36
|
+
from mlrun.model_monitoring.db._stats import (
|
|
37
|
+
ModelMonitoringCurrentStatsFile,
|
|
38
|
+
ModelMonitoringDriftMeasuresFile,
|
|
39
|
+
)
|
|
33
40
|
from mlrun.model_monitoring.helpers import get_result_instance_fqn
|
|
34
41
|
from mlrun.serving.utils import StepToDict
|
|
35
42
|
from mlrun.utils import logger
|
|
@@ -105,7 +112,7 @@ class ModelMonitoringWriter(StepToDict):
|
|
|
105
112
|
def __init__(
|
|
106
113
|
self,
|
|
107
114
|
project: str,
|
|
108
|
-
secret_provider: Callable = None,
|
|
115
|
+
secret_provider: Optional[Callable] = None,
|
|
109
116
|
) -> None:
|
|
110
117
|
self.project = project
|
|
111
118
|
self.name = project # required for the deployment process
|
|
@@ -190,6 +197,8 @@ class ModelMonitoringWriter(StepToDict):
|
|
|
190
197
|
expected_keys.extend(MetricData.list())
|
|
191
198
|
elif kind == WriterEventKind.RESULT:
|
|
192
199
|
expected_keys.extend(ResultData.list())
|
|
200
|
+
elif kind == WriterEventKind.STATS:
|
|
201
|
+
expected_keys.extend(StatsData.list())
|
|
193
202
|
else:
|
|
194
203
|
raise _WriterEventValueError(
|
|
195
204
|
f"Unknown event kind: {kind}, expected one of: {WriterEventKind.list()}"
|
|
@@ -198,16 +207,50 @@ class ModelMonitoringWriter(StepToDict):
|
|
|
198
207
|
if missing_keys:
|
|
199
208
|
raise _WriterEventValueError(
|
|
200
209
|
f"The received event misses some keys compared to the expected "
|
|
201
|
-
f"monitoring application event schema: {missing_keys}"
|
|
210
|
+
f"monitoring application event schema: {missing_keys} for event kind {kind}"
|
|
202
211
|
)
|
|
203
212
|
|
|
204
213
|
return result_event, kind
|
|
205
214
|
|
|
215
|
+
def write_stats(self, event: _AppResultEvent) -> None:
|
|
216
|
+
"""
|
|
217
|
+
Write to file the application stats event
|
|
218
|
+
:param event: application stats event
|
|
219
|
+
"""
|
|
220
|
+
endpoint_id = event[WriterEvent.ENDPOINT_ID]
|
|
221
|
+
logger.debug(
|
|
222
|
+
"Updating the model endpoint with stats",
|
|
223
|
+
endpoint_id=endpoint_id,
|
|
224
|
+
)
|
|
225
|
+
stat_kind = event.get(StatsData.STATS_NAME)
|
|
226
|
+
data, timestamp_str = event.get(StatsData.STATS), event.get(StatsData.TIMESTAMP)
|
|
227
|
+
timestamp = datetime.fromisoformat(timestamp_str).astimezone(tz=timezone.utc)
|
|
228
|
+
if stat_kind == StatsKind.CURRENT_STATS.value:
|
|
229
|
+
ModelMonitoringCurrentStatsFile(self.project, endpoint_id).write(
|
|
230
|
+
data, timestamp
|
|
231
|
+
)
|
|
232
|
+
elif stat_kind == StatsKind.DRIFT_MEASURES.value:
|
|
233
|
+
ModelMonitoringDriftMeasuresFile(self.project, endpoint_id).write(
|
|
234
|
+
data, timestamp
|
|
235
|
+
)
|
|
236
|
+
logger.info(
|
|
237
|
+
"Updating the model endpoint statistics",
|
|
238
|
+
endpoint_id=endpoint_id,
|
|
239
|
+
stats_kind=stat_kind,
|
|
240
|
+
)
|
|
241
|
+
|
|
206
242
|
def do(self, event: _RawEvent) -> None:
|
|
207
243
|
event, kind = self._reconstruct_event(event)
|
|
208
244
|
logger.info("Starting to write event", event=event)
|
|
245
|
+
if (
|
|
246
|
+
kind == WriterEventKind.STATS
|
|
247
|
+
and event[WriterEvent.APPLICATION_NAME]
|
|
248
|
+
== HistogramDataDriftApplicationConstants.NAME
|
|
249
|
+
):
|
|
250
|
+
self.write_stats(event)
|
|
251
|
+
logger.info("Model monitoring writer finished handling event")
|
|
252
|
+
return
|
|
209
253
|
self._tsdb_connector.write_application_event(event=event.copy(), kind=kind)
|
|
210
|
-
self._app_result_store.write_application_event(event=event.copy(), kind=kind)
|
|
211
254
|
|
|
212
255
|
logger.info("Completed event DB writes")
|
|
213
256
|
|
|
@@ -247,26 +290,4 @@ class ModelMonitoringWriter(StepToDict):
|
|
|
247
290
|
result_kind=event[ResultData.RESULT_KIND],
|
|
248
291
|
)
|
|
249
292
|
|
|
250
|
-
if (
|
|
251
|
-
kind == WriterEventKind.RESULT
|
|
252
|
-
and event[WriterEvent.APPLICATION_NAME]
|
|
253
|
-
== HistogramDataDriftApplicationConstants.NAME
|
|
254
|
-
and event[ResultData.RESULT_NAME]
|
|
255
|
-
== HistogramDataDriftApplicationConstants.GENERAL_RESULT_NAME
|
|
256
|
-
):
|
|
257
|
-
endpoint_id = event[WriterEvent.ENDPOINT_ID]
|
|
258
|
-
logger.info(
|
|
259
|
-
"Updating the model endpoint with metadata specific to the histogram "
|
|
260
|
-
"data drift app",
|
|
261
|
-
endpoint_id=endpoint_id,
|
|
262
|
-
)
|
|
263
|
-
attributes = json.loads(event[ResultData.RESULT_EXTRA_DATA])
|
|
264
|
-
attributes[EventFieldType.DRIFT_STATUS] = str(
|
|
265
|
-
attributes[EventFieldType.DRIFT_STATUS]
|
|
266
|
-
)
|
|
267
|
-
self._app_result_store.update_model_endpoint(
|
|
268
|
-
endpoint_id=endpoint_id,
|
|
269
|
-
attributes=attributes,
|
|
270
|
-
)
|
|
271
|
-
|
|
272
293
|
logger.info("Model monitoring writer finished handling event")
|
mlrun/package/__init__.py
CHANGED
|
@@ -11,14 +11,11 @@
|
|
|
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
|
-
# flake8: noqa - this is until we take care of the F401 violations with respect to __all__ & sphinx
|
|
17
14
|
|
|
18
15
|
import functools
|
|
19
16
|
import inspect
|
|
20
17
|
from collections import OrderedDict
|
|
21
|
-
from typing import Callable, Union
|
|
18
|
+
from typing import Callable, Optional, Union
|
|
22
19
|
|
|
23
20
|
from ..config import config
|
|
24
21
|
from .context_handler import ContextHandler
|
|
@@ -40,8 +37,8 @@ from .utils import (
|
|
|
40
37
|
|
|
41
38
|
|
|
42
39
|
def handler(
|
|
43
|
-
labels: dict[str, str] = None,
|
|
44
|
-
outputs: list[Union[str, dict[str, str]]] = None,
|
|
40
|
+
labels: Optional[dict[str, str]] = None,
|
|
41
|
+
outputs: Optional[list[Union[str, dict[str, str]]]] = None,
|
|
45
42
|
inputs: Union[bool, dict[str, Union[str, type]]] = True,
|
|
46
43
|
):
|
|
47
44
|
"""
|
mlrun/package/context_handler.py
CHANGED
|
@@ -216,7 +216,7 @@ class ContextHandler:
|
|
|
216
216
|
)
|
|
217
217
|
# Link packages:
|
|
218
218
|
self._packagers_manager.link_packages(
|
|
219
|
-
|
|
219
|
+
additional_artifact_uris=self._context.artifact_uris,
|
|
220
220
|
additional_results=self._context.results,
|
|
221
221
|
)
|
|
222
222
|
# Log the packed results and artifacts:
|
mlrun/package/packager.py
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
#
|
|
15
15
|
from abc import ABC, abstractmethod
|
|
16
16
|
from pathlib import Path
|
|
17
|
-
from typing import Any, Union
|
|
17
|
+
from typing import Any, Optional, Union
|
|
18
18
|
|
|
19
19
|
from mlrun.artifacts import Artifact
|
|
20
20
|
from mlrun.datastore import DataItem
|
|
@@ -144,9 +144,9 @@ class Packager(ABC):
|
|
|
144
144
|
def pack(
|
|
145
145
|
self,
|
|
146
146
|
obj: Any,
|
|
147
|
-
key: str = None,
|
|
148
|
-
artifact_type: str = None,
|
|
149
|
-
configurations: dict = None,
|
|
147
|
+
key: Optional[str] = None,
|
|
148
|
+
artifact_type: Optional[str] = None,
|
|
149
|
+
configurations: Optional[dict] = None,
|
|
150
150
|
) -> Union[tuple[Artifact, dict], dict]:
|
|
151
151
|
"""
|
|
152
152
|
Pack an object as the given artifact type using the provided configurations.
|
|
@@ -165,8 +165,8 @@ class Packager(ABC):
|
|
|
165
165
|
def unpack(
|
|
166
166
|
self,
|
|
167
167
|
data_item: DataItem,
|
|
168
|
-
artifact_type: str = None,
|
|
169
|
-
instructions: dict = None,
|
|
168
|
+
artifact_type: Optional[str] = None,
|
|
169
|
+
instructions: Optional[dict] = None,
|
|
170
170
|
) -> Any:
|
|
171
171
|
"""
|
|
172
172
|
Unpack the data item's artifact by the provided type using the given instructions.
|
|
@@ -180,7 +180,10 @@ class Packager(ABC):
|
|
|
180
180
|
pass
|
|
181
181
|
|
|
182
182
|
def is_packable(
|
|
183
|
-
self,
|
|
183
|
+
self,
|
|
184
|
+
obj: Any,
|
|
185
|
+
artifact_type: Optional[str] = None,
|
|
186
|
+
configurations: Optional[dict] = None,
|
|
184
187
|
) -> bool:
|
|
185
188
|
"""
|
|
186
189
|
Check if this packager can pack an object of the provided type as the provided artifact type.
|
|
@@ -212,7 +215,7 @@ class Packager(ABC):
|
|
|
212
215
|
return True
|
|
213
216
|
|
|
214
217
|
def is_unpackable(
|
|
215
|
-
self, data_item: DataItem, type_hint: type, artifact_type: str = None
|
|
218
|
+
self, data_item: DataItem, type_hint: type, artifact_type: Optional[str] = None
|
|
216
219
|
) -> bool:
|
|
217
220
|
"""
|
|
218
221
|
Check if this packager can unpack an input according to the user-given type hint and the provided artifact type.
|
|
@@ -315,7 +318,7 @@ class Packager(ABC):
|
|
|
315
318
|
)
|
|
316
319
|
|
|
317
320
|
def get_data_item_local_path(
|
|
318
|
-
self, data_item: DataItem, add_to_future_clearing_path: bool = None
|
|
321
|
+
self, data_item: DataItem, add_to_future_clearing_path: Optional[bool] = None
|
|
319
322
|
) -> str:
|
|
320
323
|
"""
|
|
321
324
|
Get the local path to the item handled by the data item provided. The local path can be the same as the data
|
|
@@ -11,8 +11,6 @@
|
|
|
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
14
|
|
|
16
|
-
# flake8: noqa - this is until we take care of the F401 violations with respect to __all__ & sphinx
|
|
17
15
|
from .default_packager import DefaultPackager
|
|
18
16
|
from .numpy_packagers import NumPySupportedFormat
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
import inspect
|
|
16
16
|
from abc import ABCMeta
|
|
17
17
|
from types import MethodType
|
|
18
|
-
from typing import Any, Union
|
|
18
|
+
from typing import Any, Optional, Union
|
|
19
19
|
|
|
20
20
|
import docstring_parser
|
|
21
21
|
|
|
@@ -323,9 +323,9 @@ class DefaultPackager(Packager, metaclass=_DefaultPackagerMeta):
|
|
|
323
323
|
def pack(
|
|
324
324
|
self,
|
|
325
325
|
obj: Any,
|
|
326
|
-
key: str = None,
|
|
327
|
-
artifact_type: str = None,
|
|
328
|
-
configurations: dict = None,
|
|
326
|
+
key: Optional[str] = None,
|
|
327
|
+
artifact_type: Optional[str] = None,
|
|
328
|
+
configurations: Optional[dict] = None,
|
|
329
329
|
) -> Union[tuple[Artifact, dict], dict]:
|
|
330
330
|
"""
|
|
331
331
|
Pack an object as the given artifact type using the provided configurations.
|
|
@@ -361,8 +361,8 @@ class DefaultPackager(Packager, metaclass=_DefaultPackagerMeta):
|
|
|
361
361
|
def unpack(
|
|
362
362
|
self,
|
|
363
363
|
data_item: DataItem,
|
|
364
|
-
artifact_type: str = None,
|
|
365
|
-
instructions: dict = None,
|
|
364
|
+
artifact_type: Optional[str] = None,
|
|
365
|
+
instructions: Optional[dict] = None,
|
|
366
366
|
) -> Any:
|
|
367
367
|
"""
|
|
368
368
|
Unpack the data item's artifact by the provided type using the given instructions.
|
|
@@ -399,7 +399,10 @@ class DefaultPackager(Packager, metaclass=_DefaultPackagerMeta):
|
|
|
399
399
|
return unpack_method(data_item, **instructions)
|
|
400
400
|
|
|
401
401
|
def is_packable(
|
|
402
|
-
self,
|
|
402
|
+
self,
|
|
403
|
+
obj: Any,
|
|
404
|
+
artifact_type: Optional[str] = None,
|
|
405
|
+
configurations: Optional[dict] = None,
|
|
403
406
|
) -> bool:
|
|
404
407
|
"""
|
|
405
408
|
Check if this packager can pack an object of the provided type as the provided artifact type.
|
|
@@ -480,10 +483,10 @@ class DefaultPackager(Packager, metaclass=_DefaultPackagerMeta):
|
|
|
480
483
|
self,
|
|
481
484
|
data_item: DataItem,
|
|
482
485
|
pickle_module_name: str = DEFAULT_PICKLE_MODULE,
|
|
483
|
-
object_module_name: str = None,
|
|
484
|
-
python_version: str = None,
|
|
485
|
-
pickle_module_version: str = None,
|
|
486
|
-
object_module_version: str = None,
|
|
486
|
+
object_module_name: Optional[str] = None,
|
|
487
|
+
python_version: Optional[str] = None,
|
|
488
|
+
pickle_module_version: Optional[str] = None,
|
|
489
|
+
object_module_version: Optional[str] = None,
|
|
487
490
|
) -> Any:
|
|
488
491
|
"""
|
|
489
492
|
Unpack the data item's object, unpickle it using the instructions, and return.
|
|
@@ -16,7 +16,7 @@ import os
|
|
|
16
16
|
import pathlib
|
|
17
17
|
import tempfile
|
|
18
18
|
from abc import ABC, abstractmethod
|
|
19
|
-
from typing import Any, Union
|
|
19
|
+
from typing import Any, Optional, Union
|
|
20
20
|
|
|
21
21
|
import numpy as np
|
|
22
22
|
import pandas as pd
|
|
@@ -371,7 +371,10 @@ class NumPyNDArrayPackager(DefaultPackager):
|
|
|
371
371
|
return artifact, {}
|
|
372
372
|
|
|
373
373
|
def unpack_file(
|
|
374
|
-
self,
|
|
374
|
+
self,
|
|
375
|
+
data_item: DataItem,
|
|
376
|
+
file_format: Optional[str] = None,
|
|
377
|
+
allow_pickle: bool = False,
|
|
375
378
|
) -> np.ndarray:
|
|
376
379
|
"""
|
|
377
380
|
Unpack a numppy array from file.
|
|
@@ -474,7 +477,7 @@ class _NumPyNDArrayCollectionPackager(DefaultPackager):
|
|
|
474
477
|
def unpack_file(
|
|
475
478
|
self,
|
|
476
479
|
data_item: DataItem,
|
|
477
|
-
file_format: str = None,
|
|
480
|
+
file_format: Optional[str] = None,
|
|
478
481
|
allow_pickle: bool = False,
|
|
479
482
|
) -> dict[str, np.ndarray]:
|
|
480
483
|
"""
|
|
@@ -548,7 +551,10 @@ class NumPyNDArrayDictPackager(_NumPyNDArrayCollectionPackager):
|
|
|
548
551
|
PACKABLE_OBJECT_TYPE = dict[str, np.ndarray]
|
|
549
552
|
|
|
550
553
|
def is_packable(
|
|
551
|
-
self,
|
|
554
|
+
self,
|
|
555
|
+
obj: Any,
|
|
556
|
+
artifact_type: Optional[str] = None,
|
|
557
|
+
configurations: Optional[dict] = None,
|
|
552
558
|
) -> bool:
|
|
553
559
|
"""
|
|
554
560
|
Check if the object provided is a dictionary of numpy arrays.
|
|
@@ -602,7 +608,7 @@ class NumPyNDArrayDictPackager(_NumPyNDArrayCollectionPackager):
|
|
|
602
608
|
def unpack_file(
|
|
603
609
|
self,
|
|
604
610
|
data_item: DataItem,
|
|
605
|
-
file_format: str = None,
|
|
611
|
+
file_format: Optional[str] = None,
|
|
606
612
|
allow_pickle: bool = False,
|
|
607
613
|
) -> dict[str, np.ndarray]:
|
|
608
614
|
"""
|
|
@@ -633,7 +639,10 @@ class NumPyNDArrayListPackager(_NumPyNDArrayCollectionPackager):
|
|
|
633
639
|
PACKABLE_OBJECT_TYPE = list[np.ndarray]
|
|
634
640
|
|
|
635
641
|
def is_packable(
|
|
636
|
-
self,
|
|
642
|
+
self,
|
|
643
|
+
obj: Any,
|
|
644
|
+
artifact_type: Optional[str] = None,
|
|
645
|
+
configurations: Optional[dict] = None,
|
|
637
646
|
) -> bool:
|
|
638
647
|
"""
|
|
639
648
|
Check if the object provided is a list of numpy arrays.
|
|
@@ -679,7 +688,7 @@ class NumPyNDArrayListPackager(_NumPyNDArrayCollectionPackager):
|
|
|
679
688
|
def unpack_file(
|
|
680
689
|
self,
|
|
681
690
|
data_item: DataItem,
|
|
682
|
-
file_format: str = None,
|
|
691
|
+
file_format: Optional[str] = None,
|
|
683
692
|
allow_pickle: bool = False,
|
|
684
693
|
) -> list[np.ndarray]:
|
|
685
694
|
"""
|