mlrun 1.7.1rc4__py3-none-any.whl → 1.8.0rc8__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 +23 -21
- mlrun/__main__.py +3 -3
- mlrun/alerts/alert.py +148 -14
- mlrun/artifacts/__init__.py +1 -2
- mlrun/artifacts/base.py +46 -12
- mlrun/artifacts/dataset.py +16 -16
- mlrun/artifacts/document.py +334 -0
- mlrun/artifacts/manager.py +15 -13
- mlrun/artifacts/model.py +66 -53
- mlrun/common/constants.py +7 -0
- mlrun/common/formatters/__init__.py +1 -0
- mlrun/common/formatters/feature_set.py +1 -0
- mlrun/common/formatters/function.py +1 -0
- mlrun/{model_monitoring/db/stores/base/__init__.py → common/formatters/model_endpoint.py} +16 -1
- mlrun/common/formatters/pipeline.py +1 -2
- mlrun/common/formatters/project.py +9 -0
- mlrun/common/model_monitoring/__init__.py +0 -5
- mlrun/common/model_monitoring/helpers.py +1 -29
- mlrun/common/runtimes/constants.py +1 -2
- mlrun/common/schemas/__init__.py +6 -2
- mlrun/common/schemas/alert.py +111 -19
- mlrun/common/schemas/api_gateway.py +3 -3
- mlrun/common/schemas/artifact.py +11 -7
- mlrun/common/schemas/auth.py +6 -4
- mlrun/common/schemas/background_task.py +7 -7
- mlrun/common/schemas/client_spec.py +2 -3
- mlrun/common/schemas/clusterization_spec.py +2 -2
- mlrun/common/schemas/common.py +53 -3
- mlrun/common/schemas/constants.py +15 -0
- mlrun/common/schemas/datastore_profile.py +1 -1
- mlrun/common/schemas/feature_store.py +9 -9
- mlrun/common/schemas/frontend_spec.py +4 -4
- mlrun/common/schemas/function.py +10 -10
- mlrun/common/schemas/hub.py +1 -1
- mlrun/common/schemas/k8s.py +3 -3
- mlrun/common/schemas/memory_reports.py +3 -3
- mlrun/common/schemas/model_monitoring/__init__.py +2 -1
- mlrun/common/schemas/model_monitoring/constants.py +66 -14
- mlrun/common/schemas/model_monitoring/grafana.py +1 -1
- mlrun/common/schemas/model_monitoring/model_endpoints.py +91 -147
- mlrun/common/schemas/notification.py +24 -3
- mlrun/common/schemas/object.py +1 -1
- mlrun/common/schemas/pagination.py +4 -4
- mlrun/common/schemas/partition.py +137 -0
- mlrun/common/schemas/pipeline.py +2 -2
- mlrun/common/schemas/project.py +25 -17
- mlrun/common/schemas/runs.py +2 -2
- mlrun/common/schemas/runtime_resource.py +5 -5
- mlrun/common/schemas/schedule.py +1 -1
- mlrun/common/schemas/secret.py +1 -1
- mlrun/common/schemas/tag.py +3 -3
- mlrun/common/schemas/workflow.py +5 -5
- mlrun/config.py +67 -10
- mlrun/data_types/__init__.py +0 -2
- mlrun/data_types/infer.py +3 -1
- mlrun/data_types/spark.py +2 -1
- 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 +79 -20
- 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 +52 -51
- mlrun/datastore/store_resources.py +0 -2
- mlrun/datastore/targets.py +21 -21
- mlrun/datastore/utils.py +2 -2
- mlrun/datastore/v3io.py +4 -1
- mlrun/datastore/vectorstore.py +194 -0
- mlrun/datastore/wasbfs/fs.py +13 -12
- mlrun/db/base.py +208 -82
- mlrun/db/factory.py +0 -3
- mlrun/db/httpdb.py +1237 -386
- mlrun/db/nopdb.py +201 -74
- mlrun/errors.py +2 -2
- mlrun/execution.py +136 -50
- mlrun/feature_store/__init__.py +0 -2
- mlrun/feature_store/api.py +41 -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 +117 -46
- mlrun/model_monitoring/__init__.py +4 -4
- mlrun/model_monitoring/api.py +61 -59
- mlrun/model_monitoring/applications/_application_steps.py +17 -17
- mlrun/model_monitoring/applications/base.py +165 -6
- mlrun/model_monitoring/applications/context.py +88 -37
- mlrun/model_monitoring/applications/evidently_base.py +1 -2
- mlrun/model_monitoring/applications/histogram_data_drift.py +43 -21
- mlrun/model_monitoring/applications/results.py +55 -3
- mlrun/model_monitoring/controller.py +207 -239
- mlrun/model_monitoring/db/__init__.py +0 -2
- mlrun/model_monitoring/db/_schedules.py +156 -0
- mlrun/model_monitoring/db/_stats.py +189 -0
- mlrun/model_monitoring/db/tsdb/base.py +78 -25
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +90 -16
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +33 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +279 -59
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +1 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +78 -17
- mlrun/model_monitoring/helpers.py +152 -49
- mlrun/model_monitoring/stream_processing.py +99 -283
- mlrun/model_monitoring/tracking_policy.py +10 -3
- mlrun/model_monitoring/writer.py +48 -36
- 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 +47 -16
- mlrun/platforms/iguazio.py +4 -1
- mlrun/projects/operations.py +27 -27
- mlrun/projects/pipelines.py +75 -38
- mlrun/projects/project.py +865 -206
- mlrun/run.py +53 -10
- mlrun/runtimes/__init__.py +1 -3
- mlrun/runtimes/base.py +15 -11
- mlrun/runtimes/daskjob.py +9 -9
- mlrun/runtimes/generators.py +2 -1
- mlrun/runtimes/kubejob.py +4 -5
- mlrun/runtimes/mounts.py +572 -0
- 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 +19 -17
- mlrun/runtimes/nuclio/serving.py +18 -11
- mlrun/runtimes/pod.py +154 -45
- 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 +185 -172
- mlrun/serving/server.py +7 -1
- mlrun/serving/states.py +97 -78
- mlrun/serving/utils.py +13 -2
- mlrun/serving/v1_serving.py +3 -2
- mlrun/serving/v2_serving.py +74 -65
- 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/clones.py +1 -1
- mlrun/utils/helpers.py +66 -18
- mlrun/utils/logger.py +106 -4
- mlrun/utils/notifications/notification/__init__.py +22 -19
- mlrun/utils/notifications/notification/base.py +33 -14
- mlrun/utils/notifications/notification/console.py +6 -6
- mlrun/utils/notifications/notification/git.py +11 -11
- mlrun/utils/notifications/notification/ipython.py +10 -9
- mlrun/utils/notifications/notification/mail.py +176 -0
- mlrun/utils/notifications/notification/slack.py +6 -6
- mlrun/utils/notifications/notification/webhook.py +6 -6
- mlrun/utils/notifications/notification_pusher.py +86 -44
- mlrun/utils/regex.py +3 -1
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.1rc4.dist-info → mlrun-1.8.0rc8.dist-info}/METADATA +191 -186
- mlrun-1.8.0rc8.dist-info/RECORD +347 -0
- {mlrun-1.7.1rc4.dist-info → mlrun-1.8.0rc8.dist-info}/WHEEL +1 -1
- mlrun/model_monitoring/db/stores/__init__.py +0 -136
- mlrun/model_monitoring/db/stores/base/store.py +0 -213
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +0 -13
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -71
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -190
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +0 -103
- mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -40
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +0 -659
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +0 -13
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +0 -726
- mlrun/model_monitoring/model_endpoint.py +0 -118
- mlrun-1.7.1rc4.dist-info/RECORD +0 -351
- {mlrun-1.7.1rc4.dist-info → mlrun-1.8.0rc8.dist-info}/LICENSE +0 -0
- {mlrun-1.7.1rc4.dist-info → mlrun-1.8.0rc8.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.1rc4.dist-info → mlrun-1.8.0rc8.dist-info}/top_level.txt +0 -0
mlrun/model.py
CHANGED
|
@@ -24,7 +24,7 @@ from datetime import datetime
|
|
|
24
24
|
from os import environ
|
|
25
25
|
from typing import Any, Optional, Union
|
|
26
26
|
|
|
27
|
-
import pydantic.error_wrappers
|
|
27
|
+
import pydantic.v1.error_wrappers
|
|
28
28
|
|
|
29
29
|
import mlrun
|
|
30
30
|
import mlrun.common.constants as mlrun_constants
|
|
@@ -74,7 +74,10 @@ class ModelObj:
|
|
|
74
74
|
|
|
75
75
|
@mlrun.utils.filter_warnings("ignore", FutureWarning)
|
|
76
76
|
def to_dict(
|
|
77
|
-
self,
|
|
77
|
+
self,
|
|
78
|
+
fields: Optional[list] = None,
|
|
79
|
+
exclude: Optional[list] = None,
|
|
80
|
+
strip: bool = False,
|
|
78
81
|
) -> dict:
|
|
79
82
|
"""
|
|
80
83
|
Convert the object to a dict
|
|
@@ -114,6 +117,8 @@ class ModelObj:
|
|
|
114
117
|
# If one of the attributes is a third party object that has to_dict method (such as k8s objects), then
|
|
115
118
|
# add it to the object's _fields_to_serialize attribute and handle it in the _serialize_field method.
|
|
116
119
|
if hasattr(field_value, "to_dict"):
|
|
120
|
+
# TODO: Allow passing fields to exclude from the parent object to the child object
|
|
121
|
+
# e.g.: run.to_dict(exclude=["status.artifacts"])
|
|
117
122
|
field_value = field_value.to_dict(strip=strip)
|
|
118
123
|
if self._is_valid_field_value_for_serialization(
|
|
119
124
|
field_name, field_value, strip
|
|
@@ -141,7 +146,7 @@ class ModelObj:
|
|
|
141
146
|
self._apply_enrichment_before_to_dict_completion(struct, strip=strip)
|
|
142
147
|
return struct
|
|
143
148
|
|
|
144
|
-
def _resolve_initial_to_dict_fields(self, fields: list = None) -> list:
|
|
149
|
+
def _resolve_initial_to_dict_fields(self, fields: Optional[list] = None) -> list:
|
|
145
150
|
"""
|
|
146
151
|
Resolve fields to be used in to_dict method.
|
|
147
152
|
If fields is None, use `_dict_fields` attribute of the object.
|
|
@@ -184,7 +189,7 @@ class ModelObj:
|
|
|
184
189
|
self,
|
|
185
190
|
struct: dict,
|
|
186
191
|
method: typing.Callable,
|
|
187
|
-
fields: typing.Union[list, set] = None,
|
|
192
|
+
fields: Optional[typing.Union[list, set]] = None,
|
|
188
193
|
strip: bool = False,
|
|
189
194
|
) -> dict:
|
|
190
195
|
for field_name in fields:
|
|
@@ -196,14 +201,14 @@ class ModelObj:
|
|
|
196
201
|
return struct
|
|
197
202
|
|
|
198
203
|
def _serialize_field(
|
|
199
|
-
self, struct: dict, field_name: str = None, strip: bool = False
|
|
204
|
+
self, struct: dict, field_name: Optional[str] = None, strip: bool = False
|
|
200
205
|
) -> typing.Any:
|
|
201
206
|
# We pull the field from self and not from struct because it was excluded from the struct when looping over
|
|
202
207
|
# the fields to save.
|
|
203
208
|
return getattr(self, field_name, None)
|
|
204
209
|
|
|
205
210
|
def _enrich_field(
|
|
206
|
-
self, struct: dict, field_name: str = None, strip: bool = False
|
|
211
|
+
self, struct: dict, field_name: Optional[str] = None, strip: bool = False
|
|
207
212
|
) -> typing.Any:
|
|
208
213
|
# We first try to pull from struct because the field might have been already serialized and if not,
|
|
209
214
|
# we pull from self
|
|
@@ -215,7 +220,9 @@ class ModelObj:
|
|
|
215
220
|
return struct
|
|
216
221
|
|
|
217
222
|
@classmethod
|
|
218
|
-
def from_dict(
|
|
223
|
+
def from_dict(
|
|
224
|
+
cls, struct=None, fields=None, deprecated_fields: Optional[dict] = None
|
|
225
|
+
):
|
|
219
226
|
"""create an object from a python dictionary"""
|
|
220
227
|
struct = {} if struct is None else struct
|
|
221
228
|
deprecated_fields = deprecated_fields or {}
|
|
@@ -430,7 +437,7 @@ class Credentials(ModelObj):
|
|
|
430
437
|
|
|
431
438
|
def __init__(
|
|
432
439
|
self,
|
|
433
|
-
access_key: str = None,
|
|
440
|
+
access_key: Optional[str] = None,
|
|
434
441
|
):
|
|
435
442
|
self.access_key = access_key
|
|
436
443
|
|
|
@@ -438,6 +445,7 @@ class Credentials(ModelObj):
|
|
|
438
445
|
class BaseMetadata(ModelObj):
|
|
439
446
|
_default_fields_to_strip = ModelObj._default_fields_to_strip + [
|
|
440
447
|
"hash",
|
|
448
|
+
"uid",
|
|
441
449
|
# Below are environment specific fields, no need to keep when stripping
|
|
442
450
|
"namespace",
|
|
443
451
|
"project",
|
|
@@ -460,10 +468,12 @@ class BaseMetadata(ModelObj):
|
|
|
460
468
|
categories=None,
|
|
461
469
|
updated=None,
|
|
462
470
|
credentials=None,
|
|
471
|
+
uid=None,
|
|
463
472
|
):
|
|
464
473
|
self.name = name
|
|
465
474
|
self.tag = tag
|
|
466
475
|
self.hash = hash
|
|
476
|
+
self.uid = uid
|
|
467
477
|
self.namespace = namespace
|
|
468
478
|
self.project = project or ""
|
|
469
479
|
self.labels = labels or {}
|
|
@@ -500,7 +510,7 @@ class ImageBuilder(ModelObj):
|
|
|
500
510
|
origin_filename=None,
|
|
501
511
|
with_mlrun=None,
|
|
502
512
|
auto_build=None,
|
|
503
|
-
requirements: list = None,
|
|
513
|
+
requirements: Optional[list] = None,
|
|
504
514
|
extra_args=None,
|
|
505
515
|
builder_env=None,
|
|
506
516
|
source_code_target_dir=None,
|
|
@@ -549,7 +559,7 @@ class ImageBuilder(ModelObj):
|
|
|
549
559
|
self,
|
|
550
560
|
image="",
|
|
551
561
|
base_image=None,
|
|
552
|
-
commands: list = None,
|
|
562
|
+
commands: Optional[list] = None,
|
|
553
563
|
secret=None,
|
|
554
564
|
source=None,
|
|
555
565
|
extra=None,
|
|
@@ -734,7 +744,7 @@ class Notification(ModelObj):
|
|
|
734
744
|
def validate_notification(self):
|
|
735
745
|
try:
|
|
736
746
|
mlrun.common.schemas.notification.Notification(**self.to_dict())
|
|
737
|
-
except pydantic.error_wrappers.ValidationError as exc:
|
|
747
|
+
except pydantic.v1.error_wrappers.ValidationError as exc:
|
|
738
748
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
739
749
|
"Invalid notification object"
|
|
740
750
|
) from exc
|
|
@@ -750,14 +760,14 @@ class Notification(ModelObj):
|
|
|
750
760
|
"Notification params size exceeds max size of 1 MB"
|
|
751
761
|
)
|
|
752
762
|
|
|
753
|
-
def validate_notification_params(self):
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
763
|
+
def validate_notification_params(self, default_notification_params=None):
|
|
764
|
+
default_notification_params = default_notification_params or {}
|
|
765
|
+
notification_type = mlrun.utils.notifications.NotificationTypes(self.kind)
|
|
766
|
+
notification_class = notification_type.get_notification()
|
|
758
767
|
secret_params = self.secret_params or {}
|
|
759
768
|
params = self.params or {}
|
|
760
|
-
|
|
769
|
+
default_params = default_notification_params.get(notification_type, {})
|
|
770
|
+
params = notification_class.enrich_default_params(params, default_params)
|
|
761
771
|
# if the secret_params are already masked - no need to validate
|
|
762
772
|
params_secret = secret_params.get("secret", "")
|
|
763
773
|
if params_secret:
|
|
@@ -973,7 +983,7 @@ class RunSpec(ModelObj):
|
|
|
973
983
|
self.node_selector = node_selector or {}
|
|
974
984
|
|
|
975
985
|
def _serialize_field(
|
|
976
|
-
self, struct: dict, field_name: str = None, strip: bool = False
|
|
986
|
+
self, struct: dict, field_name: Optional[str] = None, strip: bool = False
|
|
977
987
|
) -> Optional[str]:
|
|
978
988
|
# We pull the field from self and not from struct because it was excluded from the struct
|
|
979
989
|
if field_name == "handler":
|
|
@@ -1262,6 +1272,8 @@ class RunSpec(ModelObj):
|
|
|
1262
1272
|
class RunStatus(ModelObj):
|
|
1263
1273
|
"""Run status"""
|
|
1264
1274
|
|
|
1275
|
+
_default_fields_to_strip = ModelObj._default_fields_to_strip + ["artifacts"]
|
|
1276
|
+
|
|
1265
1277
|
def __init__(
|
|
1266
1278
|
self,
|
|
1267
1279
|
state=None,
|
|
@@ -1275,9 +1287,9 @@ class RunStatus(ModelObj):
|
|
|
1275
1287
|
last_update=None,
|
|
1276
1288
|
iterations=None,
|
|
1277
1289
|
ui_url=None,
|
|
1278
|
-
reason: str = None,
|
|
1279
|
-
notifications: dict[str, Notification] = None,
|
|
1280
|
-
artifact_uris: dict[str, str] = None,
|
|
1290
|
+
reason: Optional[str] = None,
|
|
1291
|
+
notifications: Optional[dict[str, Notification]] = None,
|
|
1292
|
+
artifact_uris: Optional[dict[str, str]] = None,
|
|
1281
1293
|
):
|
|
1282
1294
|
self.state = state or "created"
|
|
1283
1295
|
self.status_text = status_text
|
|
@@ -1285,7 +1297,7 @@ class RunStatus(ModelObj):
|
|
|
1285
1297
|
self.host = host
|
|
1286
1298
|
self.commit = commit
|
|
1287
1299
|
self.results = results
|
|
1288
|
-
self.
|
|
1300
|
+
self._artifacts = artifacts
|
|
1289
1301
|
self.start_time = start_time
|
|
1290
1302
|
self.last_update = last_update
|
|
1291
1303
|
self.iterations = iterations
|
|
@@ -1293,7 +1305,59 @@ class RunStatus(ModelObj):
|
|
|
1293
1305
|
self.reason = reason
|
|
1294
1306
|
self.notifications = notifications or {}
|
|
1295
1307
|
# Artifact key -> URI mapping, since the full artifacts are not stored in the runs DB table
|
|
1296
|
-
self.
|
|
1308
|
+
self._artifact_uris = artifact_uris or {}
|
|
1309
|
+
|
|
1310
|
+
@classmethod
|
|
1311
|
+
def from_dict(
|
|
1312
|
+
cls, struct=None, fields=None, deprecated_fields: Optional[dict] = None
|
|
1313
|
+
):
|
|
1314
|
+
deprecated_fields = {
|
|
1315
|
+
# Set artifacts as deprecated for lazy loading
|
|
1316
|
+
"artifacts": "artifact_uris"
|
|
1317
|
+
}
|
|
1318
|
+
return super().from_dict(
|
|
1319
|
+
struct, fields=fields, deprecated_fields=deprecated_fields
|
|
1320
|
+
)
|
|
1321
|
+
|
|
1322
|
+
@property
|
|
1323
|
+
def artifacts(self):
|
|
1324
|
+
"""
|
|
1325
|
+
Artifacts are lazy loaded to reduce memory consumption.
|
|
1326
|
+
We keep artifact_uris (key -> store URI dictionary) to be able to get the run artifacts easily.
|
|
1327
|
+
If the artifact is not already in the cache, we get it from the store (DB).
|
|
1328
|
+
:return: List of artifact dictionaries
|
|
1329
|
+
"""
|
|
1330
|
+
self._artifacts = self._artifacts or []
|
|
1331
|
+
existing_artifact_keys = {
|
|
1332
|
+
artifact["metadata"]["key"] for artifact in self._artifacts
|
|
1333
|
+
}
|
|
1334
|
+
for key, uri in self.artifact_uris.items():
|
|
1335
|
+
if key not in existing_artifact_keys:
|
|
1336
|
+
artifact = mlrun.datastore.get_store_resource(uri)
|
|
1337
|
+
self._artifacts.append(artifact.to_dict())
|
|
1338
|
+
return self._artifacts
|
|
1339
|
+
|
|
1340
|
+
@artifacts.setter
|
|
1341
|
+
def artifacts(self, artifacts):
|
|
1342
|
+
self._artifacts = artifacts
|
|
1343
|
+
|
|
1344
|
+
@property
|
|
1345
|
+
def artifact_uris(self):
|
|
1346
|
+
return self._artifact_uris
|
|
1347
|
+
|
|
1348
|
+
@artifact_uris.setter
|
|
1349
|
+
def artifact_uris(self, artifact_uris):
|
|
1350
|
+
resolved_artifact_uris = {}
|
|
1351
|
+
if isinstance(artifact_uris, list):
|
|
1352
|
+
# artifact_uris is the deprecated list of artifacts - convert to new form
|
|
1353
|
+
for artifact in artifact_uris:
|
|
1354
|
+
if isinstance(artifact, dict):
|
|
1355
|
+
artifact = mlrun.artifacts.dict_to_artifact(artifact)
|
|
1356
|
+
resolved_artifact_uris[artifact.key] = artifact.uri
|
|
1357
|
+
else:
|
|
1358
|
+
resolved_artifact_uris = artifact_uris
|
|
1359
|
+
|
|
1360
|
+
self._artifact_uris = resolved_artifact_uris
|
|
1297
1361
|
|
|
1298
1362
|
def is_failed(self) -> Optional[bool]:
|
|
1299
1363
|
"""
|
|
@@ -1601,7 +1665,7 @@ class RunObject(RunTemplate):
|
|
|
1601
1665
|
|
|
1602
1666
|
return outputs
|
|
1603
1667
|
|
|
1604
|
-
def artifact(self, key: str) -> "mlrun.DataItem":
|
|
1668
|
+
def artifact(self, key: str) -> typing.Optional["mlrun.DataItem"]:
|
|
1605
1669
|
"""Return artifact DataItem by key.
|
|
1606
1670
|
|
|
1607
1671
|
This method waits for the outputs to complete, searches for the artifact matching the given key,
|
|
@@ -1644,7 +1708,7 @@ class RunObject(RunTemplate):
|
|
|
1644
1708
|
:param key: The key of the artifact to retrieve.
|
|
1645
1709
|
:return: The last artifact DataItem with the given key, or None if no such artifact is found.
|
|
1646
1710
|
"""
|
|
1647
|
-
if not self.status.artifacts:
|
|
1711
|
+
if not self.status.artifacts and not self.status.artifact_uris:
|
|
1648
1712
|
return None
|
|
1649
1713
|
|
|
1650
1714
|
# Collect artifacts that match the key
|
|
@@ -1655,7 +1719,12 @@ class RunObject(RunTemplate):
|
|
|
1655
1719
|
]
|
|
1656
1720
|
|
|
1657
1721
|
if not matching_artifacts:
|
|
1658
|
-
|
|
1722
|
+
if key not in self.status.artifact_uris:
|
|
1723
|
+
return None
|
|
1724
|
+
|
|
1725
|
+
# Get artifact by store URI sanity (should have been enriched by now in status.artifacts property)
|
|
1726
|
+
artifact_uri = self.status.artifact_uris[key]
|
|
1727
|
+
return mlrun.datastore.get_store_resource(artifact_uri)
|
|
1659
1728
|
|
|
1660
1729
|
# Sort matching artifacts by creation date in ascending order.
|
|
1661
1730
|
# The last element in the list will be the one created most recently.
|
|
@@ -1870,7 +1939,7 @@ class EntrypointParam(ModelObj):
|
|
|
1870
1939
|
default=None,
|
|
1871
1940
|
doc="",
|
|
1872
1941
|
required=None,
|
|
1873
|
-
choices: list = None,
|
|
1942
|
+
choices: Optional[list] = None,
|
|
1874
1943
|
):
|
|
1875
1944
|
self.name = name
|
|
1876
1945
|
self.type = type
|
|
@@ -2065,12 +2134,12 @@ class DataSource(ModelObj):
|
|
|
2065
2134
|
|
|
2066
2135
|
def __init__(
|
|
2067
2136
|
self,
|
|
2068
|
-
name: str = None,
|
|
2069
|
-
path: str = None,
|
|
2070
|
-
attributes: dict[str, object] = None,
|
|
2071
|
-
key_field: str = None,
|
|
2072
|
-
time_field: str = None,
|
|
2073
|
-
schedule: str = None,
|
|
2137
|
+
name: Optional[str] = None,
|
|
2138
|
+
path: Optional[str] = None,
|
|
2139
|
+
attributes: Optional[dict[str, object]] = None,
|
|
2140
|
+
key_field: Optional[str] = None,
|
|
2141
|
+
time_field: Optional[str] = None,
|
|
2142
|
+
schedule: Optional[str] = None,
|
|
2074
2143
|
start_time: Optional[Union[datetime, str]] = None,
|
|
2075
2144
|
end_time: Optional[Union[datetime, str]] = None,
|
|
2076
2145
|
):
|
|
@@ -2092,7 +2161,7 @@ class DataSource(ModelObj):
|
|
|
2092
2161
|
self._secrets = secrets
|
|
2093
2162
|
|
|
2094
2163
|
def _serialize_field(
|
|
2095
|
-
self, struct: dict, field_name: str = None, strip: bool = False
|
|
2164
|
+
self, struct: dict, field_name: Optional[str] = None, strip: bool = False
|
|
2096
2165
|
) -> typing.Any:
|
|
2097
2166
|
value = super()._serialize_field(struct, field_name, strip)
|
|
2098
2167
|
# We pull the field from self and not from struct because it was excluded from the struct when looping over
|
|
@@ -2124,7 +2193,9 @@ class DataTargetBase(ModelObj):
|
|
|
2124
2193
|
]
|
|
2125
2194
|
|
|
2126
2195
|
@classmethod
|
|
2127
|
-
def from_dict(
|
|
2196
|
+
def from_dict(
|
|
2197
|
+
cls, struct=None, fields=None, deprecated_fields: Optional[dict] = None
|
|
2198
|
+
):
|
|
2128
2199
|
return super().from_dict(struct, fields=fields)
|
|
2129
2200
|
|
|
2130
2201
|
def get_path(self):
|
|
@@ -2140,10 +2211,10 @@ class DataTargetBase(ModelObj):
|
|
|
2140
2211
|
|
|
2141
2212
|
def __init__(
|
|
2142
2213
|
self,
|
|
2143
|
-
kind: str = None,
|
|
2214
|
+
kind: Optional[str] = None,
|
|
2144
2215
|
name: str = "",
|
|
2145
2216
|
path=None,
|
|
2146
|
-
attributes: dict[str, str] = None,
|
|
2217
|
+
attributes: Optional[dict[str, str]] = None,
|
|
2147
2218
|
after_step=None,
|
|
2148
2219
|
partitioned: bool = False,
|
|
2149
2220
|
key_bucketing_number: Optional[int] = None,
|
|
@@ -2151,8 +2222,8 @@ class DataTargetBase(ModelObj):
|
|
|
2151
2222
|
time_partitioning_granularity: Optional[str] = None,
|
|
2152
2223
|
max_events: Optional[int] = None,
|
|
2153
2224
|
flush_after_seconds: Optional[int] = None,
|
|
2154
|
-
storage_options: dict[str, str] = None,
|
|
2155
|
-
schema: dict[str, Any] = None,
|
|
2225
|
+
storage_options: Optional[dict[str, str]] = None,
|
|
2226
|
+
schema: Optional[dict[str, Any]] = None,
|
|
2156
2227
|
credentials_prefix=None,
|
|
2157
2228
|
):
|
|
2158
2229
|
self.name = name
|
|
@@ -2208,7 +2279,7 @@ class DataTarget(DataTargetBase):
|
|
|
2208
2279
|
|
|
2209
2280
|
def __init__(
|
|
2210
2281
|
self,
|
|
2211
|
-
kind: str = None,
|
|
2282
|
+
kind: Optional[str] = None,
|
|
2212
2283
|
name: str = "",
|
|
2213
2284
|
path=None,
|
|
2214
2285
|
online=None,
|
|
@@ -2237,12 +2308,12 @@ class DataTarget(DataTargetBase):
|
|
|
2237
2308
|
class VersionedObjMetadata(ModelObj):
|
|
2238
2309
|
def __init__(
|
|
2239
2310
|
self,
|
|
2240
|
-
name: str = None,
|
|
2241
|
-
tag: str = None,
|
|
2242
|
-
uid: str = None,
|
|
2243
|
-
project: str = None,
|
|
2244
|
-
labels: dict[str, str] = None,
|
|
2245
|
-
annotations: dict[str, str] = None,
|
|
2311
|
+
name: Optional[str] = None,
|
|
2312
|
+
tag: Optional[str] = None,
|
|
2313
|
+
uid: Optional[str] = None,
|
|
2314
|
+
project: Optional[str] = None,
|
|
2315
|
+
labels: Optional[dict[str, str]] = None,
|
|
2316
|
+
annotations: Optional[dict[str, str]] = None,
|
|
2246
2317
|
updated=None,
|
|
2247
2318
|
):
|
|
2248
2319
|
self.name = name
|
|
@@ -11,11 +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
|
-
# flake8: noqa - this is until we take care of the F401 violations with respect to __all__ & sphinx
|
|
14
|
+
|
|
16
15
|
# for backwards compatibility
|
|
17
16
|
|
|
18
|
-
from .
|
|
17
|
+
from mlrun.common.schemas import ModelEndpoint, ModelEndpointList
|
|
18
|
+
|
|
19
|
+
from .db import get_tsdb_connector
|
|
19
20
|
from .helpers import get_stream_path
|
|
20
|
-
from .model_endpoint import ModelEndpoint
|
|
21
21
|
from .tracking_policy import TrackingPolicy
|
mlrun/model_monitoring/api.py
CHANGED
|
@@ -23,18 +23,28 @@ import pandas as pd
|
|
|
23
23
|
import mlrun.artifacts
|
|
24
24
|
import mlrun.common.helpers
|
|
25
25
|
import mlrun.common.schemas.model_monitoring.constants as mm_constants
|
|
26
|
+
import mlrun.datastore.base
|
|
26
27
|
import mlrun.feature_store
|
|
27
28
|
import mlrun.model_monitoring.applications as mm_app
|
|
28
29
|
import mlrun.serving
|
|
30
|
+
from mlrun.common.schemas import ModelEndpoint
|
|
31
|
+
from mlrun.common.schemas.model_monitoring import (
|
|
32
|
+
FunctionURI,
|
|
33
|
+
)
|
|
29
34
|
from mlrun.data_types.infer import InferOptions, get_df_stats
|
|
30
35
|
from mlrun.utils import datetime_now, logger
|
|
31
36
|
|
|
32
37
|
from .helpers import update_model_endpoint_last_request
|
|
33
|
-
from .model_endpoint import ModelEndpoint
|
|
34
38
|
|
|
35
39
|
# A union of all supported dataset types:
|
|
36
40
|
DatasetType = typing.Union[
|
|
37
|
-
mlrun.
|
|
41
|
+
mlrun.datastore.base.DataItem,
|
|
42
|
+
list,
|
|
43
|
+
dict,
|
|
44
|
+
pd.DataFrame,
|
|
45
|
+
pd.Series,
|
|
46
|
+
np.ndarray,
|
|
47
|
+
typing.Any,
|
|
38
48
|
]
|
|
39
49
|
|
|
40
50
|
|
|
@@ -44,10 +54,8 @@ def get_or_create_model_endpoint(
|
|
|
44
54
|
model_endpoint_name: str = "",
|
|
45
55
|
endpoint_id: str = "",
|
|
46
56
|
function_name: str = "",
|
|
47
|
-
context: mlrun.MLClientCtx = None,
|
|
48
|
-
sample_set_statistics: dict[str, typing.Any] = None,
|
|
49
|
-
drift_threshold: typing.Optional[float] = None,
|
|
50
|
-
possible_drift_threshold: typing.Optional[float] = None,
|
|
57
|
+
context: typing.Optional["mlrun.MLClientCtx"] = None,
|
|
58
|
+
sample_set_statistics: typing.Optional[dict[str, typing.Any]] = None,
|
|
51
59
|
monitoring_mode: mm_constants.ModelMonitoringMode = mm_constants.ModelMonitoringMode.disabled,
|
|
52
60
|
db_session=None,
|
|
53
61
|
) -> ModelEndpoint:
|
|
@@ -68,10 +76,6 @@ def get_or_create_model_endpoint(
|
|
|
68
76
|
full function hash.
|
|
69
77
|
:param sample_set_statistics: Dictionary of sample set statistics that will be used as a reference data for
|
|
70
78
|
the new model endpoint (applicable only to new endpoint_id).
|
|
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
|
|
74
|
-
endpoint_id).
|
|
75
79
|
:param monitoring_mode: If enabled, apply model monitoring features on the provided endpoint id
|
|
76
80
|
(applicable only to new endpoint_id).
|
|
77
81
|
:param db_session: A runtime session that manages the current dialog with the database.
|
|
@@ -79,18 +83,15 @@ def get_or_create_model_endpoint(
|
|
|
79
83
|
:return: A ModelEndpoint object
|
|
80
84
|
"""
|
|
81
85
|
|
|
82
|
-
if not endpoint_id:
|
|
83
|
-
# Generate a new model endpoint id based on the project name and model name
|
|
84
|
-
endpoint_id = hashlib.sha1(
|
|
85
|
-
f"{project}_{model_endpoint_name}".encode()
|
|
86
|
-
).hexdigest()
|
|
87
|
-
|
|
88
86
|
if not db_session:
|
|
89
87
|
# Generate a runtime database
|
|
90
88
|
db_session = mlrun.get_run_db()
|
|
91
89
|
try:
|
|
92
90
|
model_endpoint = db_session.get_model_endpoint(
|
|
93
|
-
project=project,
|
|
91
|
+
project=project,
|
|
92
|
+
name=model_endpoint_name,
|
|
93
|
+
endpoint_id=endpoint_id,
|
|
94
|
+
function_name=function_name,
|
|
94
95
|
)
|
|
95
96
|
# If other fields provided, validate that they are correspond to the existing model endpoint data
|
|
96
97
|
_model_endpoint_validations(
|
|
@@ -104,7 +105,6 @@ def get_or_create_model_endpoint(
|
|
|
104
105
|
model_endpoint = _generate_model_endpoint(
|
|
105
106
|
project=project,
|
|
106
107
|
db_session=db_session,
|
|
107
|
-
endpoint_id=endpoint_id,
|
|
108
108
|
model_path=model_path,
|
|
109
109
|
model_endpoint_name=model_endpoint_name,
|
|
110
110
|
function_name=function_name,
|
|
@@ -121,7 +121,7 @@ def record_results(
|
|
|
121
121
|
model_endpoint_name: str,
|
|
122
122
|
endpoint_id: str = "",
|
|
123
123
|
function_name: str = "",
|
|
124
|
-
context: typing.Optional[mlrun.MLClientCtx] = None,
|
|
124
|
+
context: typing.Optional["mlrun.MLClientCtx"] = None,
|
|
125
125
|
infer_results_df: typing.Optional[pd.DataFrame] = None,
|
|
126
126
|
sample_set_statistics: typing.Optional[dict[str, typing.Any]] = None,
|
|
127
127
|
monitoring_mode: mm_constants.ModelMonitoringMode = mm_constants.ModelMonitoringMode.enabled,
|
|
@@ -208,13 +208,13 @@ def record_results(
|
|
|
208
208
|
monitoring_mode=monitoring_mode,
|
|
209
209
|
db_session=db,
|
|
210
210
|
)
|
|
211
|
-
logger.debug("Model endpoint", endpoint=model_endpoint
|
|
211
|
+
logger.debug("Model endpoint", endpoint=model_endpoint)
|
|
212
212
|
|
|
213
213
|
timestamp = datetime_now()
|
|
214
214
|
if infer_results_df is not None:
|
|
215
215
|
# Write the monitoring parquet to the relevant model endpoint context
|
|
216
216
|
write_monitoring_df(
|
|
217
|
-
feature_set_uri=model_endpoint.
|
|
217
|
+
feature_set_uri=model_endpoint.spec.monitoring_feature_set_uri,
|
|
218
218
|
infer_datetime=timestamp,
|
|
219
219
|
endpoint_id=model_endpoint.metadata.uid,
|
|
220
220
|
infer_results_df=infer_results_df,
|
|
@@ -234,7 +234,7 @@ def record_results(
|
|
|
234
234
|
def _model_endpoint_validations(
|
|
235
235
|
model_endpoint: ModelEndpoint,
|
|
236
236
|
model_path: str = "",
|
|
237
|
-
sample_set_statistics: dict[str, typing.Any] = None,
|
|
237
|
+
sample_set_statistics: typing.Optional[dict[str, typing.Any]] = None,
|
|
238
238
|
) -> None:
|
|
239
239
|
"""
|
|
240
240
|
Validate that provided model endpoint configurations match the stored fields of the provided `ModelEndpoint`
|
|
@@ -278,7 +278,7 @@ def _model_endpoint_validations(
|
|
|
278
278
|
# Feature stats
|
|
279
279
|
if (
|
|
280
280
|
sample_set_statistics
|
|
281
|
-
and sample_set_statistics != model_endpoint.
|
|
281
|
+
and sample_set_statistics != model_endpoint.spec.feature_stats
|
|
282
282
|
):
|
|
283
283
|
logger.warning(
|
|
284
284
|
"Provided sample set statistics is different from the registered statistics. "
|
|
@@ -290,7 +290,7 @@ def write_monitoring_df(
|
|
|
290
290
|
endpoint_id: str,
|
|
291
291
|
infer_results_df: pd.DataFrame,
|
|
292
292
|
infer_datetime: datetime,
|
|
293
|
-
monitoring_feature_set: typing.Optional[mlrun.feature_store.FeatureSet] = None,
|
|
293
|
+
monitoring_feature_set: typing.Optional["mlrun.feature_store.FeatureSet"] = None,
|
|
294
294
|
feature_set_uri: str = "",
|
|
295
295
|
) -> None:
|
|
296
296
|
"""Write infer results dataframe to the monitoring parquet target of the current model endpoint. The dataframe will
|
|
@@ -330,11 +330,10 @@ def write_monitoring_df(
|
|
|
330
330
|
def _generate_model_endpoint(
|
|
331
331
|
project: str,
|
|
332
332
|
db_session,
|
|
333
|
-
endpoint_id: str,
|
|
334
333
|
model_path: str,
|
|
335
334
|
model_endpoint_name: str,
|
|
336
335
|
function_name: str,
|
|
337
|
-
context: mlrun.MLClientCtx,
|
|
336
|
+
context: "mlrun.MLClientCtx",
|
|
338
337
|
sample_set_statistics: dict[str, typing.Any],
|
|
339
338
|
monitoring_mode: mm_constants.ModelMonitoringMode = mm_constants.ModelMonitoringMode.disabled,
|
|
340
339
|
) -> ModelEndpoint:
|
|
@@ -344,7 +343,6 @@ def _generate_model_endpoint(
|
|
|
344
343
|
:param project: Project name.
|
|
345
344
|
|
|
346
345
|
:param db_session: A session that manages the current dialog with the database.
|
|
347
|
-
:param endpoint_id: Model endpoint unique ID.
|
|
348
346
|
:param model_path: The model Store path.
|
|
349
347
|
:param model_endpoint_name: Model endpoint name will be presented under the new model endpoint.
|
|
350
348
|
:param function_name: If a new model endpoint is created, use this function name for generating the
|
|
@@ -355,39 +353,45 @@ def _generate_model_endpoint(
|
|
|
355
353
|
the current model endpoint. Will be stored under
|
|
356
354
|
`model_endpoint.status.feature_stats`.
|
|
357
355
|
|
|
358
|
-
:return `mlrun.
|
|
356
|
+
:return `mlrun.common.schemas.ModelEndpoint` object.
|
|
359
357
|
"""
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
358
|
+
if not function_name and context:
|
|
359
|
+
function_name = FunctionURI.from_string(
|
|
360
|
+
context.to_dict()["spec"]["function"]
|
|
361
|
+
).function
|
|
362
|
+
model_obj = None
|
|
363
|
+
if model_path:
|
|
364
|
+
model_obj: mlrun.artifacts.ModelArtifact = (
|
|
365
|
+
mlrun.datastore.store_resources.get_store_resource(
|
|
366
|
+
model_path, db=db_session
|
|
367
|
+
)
|
|
368
368
|
)
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
369
|
+
current_time = datetime_now()
|
|
370
|
+
model_endpoint = mlrun.common.schemas.ModelEndpoint(
|
|
371
|
+
metadata=mlrun.common.schemas.ModelEndpointMetadata(
|
|
372
|
+
project=project,
|
|
373
|
+
name=model_endpoint_name,
|
|
374
|
+
endpoint_type=mlrun.common.schemas.model_monitoring.EndpointType.BATCH_EP,
|
|
375
|
+
),
|
|
376
|
+
spec=mlrun.common.schemas.ModelEndpointSpec(
|
|
377
|
+
function_name=function_name,
|
|
378
|
+
model_name=model_obj.metadata.key if model_path else None,
|
|
379
|
+
model_uid=model_obj.metadata.uid if model_path else None,
|
|
380
|
+
model_class="drift-analysis",
|
|
381
|
+
),
|
|
382
|
+
status=mlrun.common.schemas.ModelEndpointStatus(
|
|
383
|
+
monitoring_mode=monitoring_mode,
|
|
384
|
+
first_request=current_time,
|
|
385
|
+
last_request=current_time,
|
|
386
|
+
),
|
|
383
387
|
)
|
|
384
388
|
|
|
385
|
-
return db_session.
|
|
389
|
+
return db_session.create_model_endpoint(model_endpoint=model_endpoint)
|
|
386
390
|
|
|
387
391
|
|
|
388
392
|
def get_sample_set_statistics(
|
|
389
393
|
sample_set: DatasetType = None,
|
|
390
|
-
model_artifact_feature_stats: dict = None,
|
|
394
|
+
model_artifact_feature_stats: typing.Optional[dict] = None,
|
|
391
395
|
sample_set_columns: typing.Optional[list] = None,
|
|
392
396
|
sample_set_drop_columns: typing.Optional[list] = None,
|
|
393
397
|
sample_set_label_columns: typing.Optional[list] = None,
|
|
@@ -445,9 +449,9 @@ def get_sample_set_statistics(
|
|
|
445
449
|
|
|
446
450
|
def read_dataset_as_dataframe(
|
|
447
451
|
dataset: DatasetType,
|
|
448
|
-
feature_columns: typing.Union[str, list[str]] = None,
|
|
449
|
-
label_columns: typing.Union[str, list[str]] = None,
|
|
450
|
-
drop_columns: typing.Union[str, list[str], int, list[int]] = None,
|
|
452
|
+
feature_columns: typing.Optional[typing.Union[str, list[str]]] = None,
|
|
453
|
+
label_columns: typing.Optional[typing.Union[str, list[str]]] = None,
|
|
454
|
+
drop_columns: typing.Optional[typing.Union[str, list[str], int, list[int]]] = None,
|
|
451
455
|
) -> tuple[pd.DataFrame, list[str]]:
|
|
452
456
|
"""
|
|
453
457
|
Parse the given dataset into a DataFrame and drop the columns accordingly. In addition, the label columns will be
|
|
@@ -531,7 +535,7 @@ def read_dataset_as_dataframe(
|
|
|
531
535
|
|
|
532
536
|
|
|
533
537
|
def log_result(
|
|
534
|
-
context: mlrun.MLClientCtx,
|
|
538
|
+
context: "mlrun.MLClientCtx",
|
|
535
539
|
result_set_name: str,
|
|
536
540
|
result_set: pd.DataFrame,
|
|
537
541
|
artifacts_tag: str,
|
|
@@ -559,9 +563,7 @@ def _create_model_monitoring_function_base(
|
|
|
559
563
|
project: str,
|
|
560
564
|
func: typing.Union[str, None] = None,
|
|
561
565
|
application_class: typing.Union[
|
|
562
|
-
str,
|
|
563
|
-
mm_app.ModelMonitoringApplicationBase,
|
|
564
|
-
None,
|
|
566
|
+
str, "mm_app.ModelMonitoringApplicationBase", None
|
|
565
567
|
] = None,
|
|
566
568
|
name: typing.Optional[str] = None,
|
|
567
569
|
image: typing.Optional[str] = None,
|