mlrun 1.5.0rc12__py3-none-any.whl → 1.5.0rc13__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/__main__.py +31 -2
- mlrun/api/api/endpoints/functions.py +110 -52
- mlrun/api/crud/model_monitoring/deployment.py +208 -38
- mlrun/api/crud/model_monitoring/helpers.py +19 -6
- mlrun/api/crud/model_monitoring/model_endpoints.py +14 -1
- mlrun/api/db/sqldb/db.py +3 -1
- mlrun/api/utils/builder.py +2 -4
- mlrun/common/model_monitoring/helpers.py +19 -5
- mlrun/common/schemas/model_monitoring/constants.py +69 -0
- mlrun/common/schemas/model_monitoring/model_endpoints.py +10 -0
- mlrun/config.py +30 -12
- mlrun/datastore/__init__.py +1 -0
- mlrun/datastore/sources.py +4 -30
- mlrun/datastore/targets.py +68 -31
- mlrun/db/httpdb.py +20 -6
- mlrun/feature_store/api.py +3 -31
- mlrun/feature_store/feature_vector.py +1 -1
- mlrun/feature_store/retrieval/base.py +8 -3
- mlrun/launcher/remote.py +3 -3
- mlrun/lists.py +11 -0
- mlrun/model_monitoring/__init__.py +0 -1
- mlrun/model_monitoring/api.py +1 -1
- mlrun/model_monitoring/application.py +313 -0
- mlrun/model_monitoring/batch_application.py +526 -0
- mlrun/model_monitoring/batch_application_handler.py +32 -0
- mlrun/model_monitoring/evidently_application.py +89 -0
- mlrun/model_monitoring/helpers.py +39 -3
- mlrun/model_monitoring/stores/kv_model_endpoint_store.py +37 -0
- mlrun/model_monitoring/tracking_policy.py +4 -4
- mlrun/model_monitoring/writer.py +37 -0
- mlrun/projects/pipelines.py +38 -4
- mlrun/projects/project.py +257 -43
- mlrun/run.py +5 -2
- mlrun/runtimes/__init__.py +2 -0
- mlrun/runtimes/function.py +2 -1
- mlrun/utils/helpers.py +12 -0
- mlrun/utils/http.py +3 -0
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/METADATA +5 -5
- {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/RECORD +45 -40
- /mlrun/model_monitoring/{model_monitoring_batch.py → batch.py} +0 -0
- {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/LICENSE +0 -0
- {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/WHEEL +0 -0
- {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/entry_points.txt +0 -0
- {mlrun-1.5.0rc12.dist-info → mlrun-1.5.0rc13.dist-info}/top_level.txt +0 -0
|
@@ -20,20 +20,56 @@ import mlrun.common.model_monitoring.helpers
|
|
|
20
20
|
import mlrun.common.schemas
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
def get_stream_path(project: str = None):
|
|
24
|
-
"""
|
|
23
|
+
def get_stream_path(project: str = None, application_name: str = None):
|
|
24
|
+
"""
|
|
25
|
+
Get stream path from the project secret. If wasn't set, take it from the system configurations
|
|
26
|
+
|
|
27
|
+
:param project: Project name.
|
|
28
|
+
:param application_name: Application name, None for model_monitoring_stream.
|
|
29
|
+
|
|
30
|
+
:return: Monitoring stream path to the relevant application.
|
|
31
|
+
"""
|
|
25
32
|
|
|
26
33
|
stream_uri = mlrun.get_secret_or_env(
|
|
27
34
|
mlrun.common.schemas.model_monitoring.ProjectSecretKeys.STREAM_PATH
|
|
35
|
+
if application_name is None
|
|
36
|
+
else ""
|
|
28
37
|
) or mlrun.mlconf.get_model_monitoring_file_target_path(
|
|
29
38
|
project=project,
|
|
30
39
|
kind=mlrun.common.schemas.model_monitoring.FileTargetKind.STREAM,
|
|
31
40
|
target="online",
|
|
41
|
+
application_name=application_name,
|
|
32
42
|
)
|
|
33
43
|
|
|
34
44
|
return mlrun.common.model_monitoring.helpers.parse_monitoring_stream_path(
|
|
35
|
-
stream_uri=stream_uri, project=project
|
|
45
|
+
stream_uri=stream_uri, project=project, application_name=application_name
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_monitoring_parquet_path(
|
|
50
|
+
project: str,
|
|
51
|
+
kind: str = mlrun.common.schemas.model_monitoring.FileTargetKind.PARQUET,
|
|
52
|
+
) -> str:
|
|
53
|
+
"""Get model monitoring parquet target for the current project and kind. The parquet target path is based on the
|
|
54
|
+
project artifact path. If project artifact path is not defined, the parquet target path will be based on MLRun
|
|
55
|
+
artifact path.
|
|
56
|
+
|
|
57
|
+
:param project: Project name.
|
|
58
|
+
:param kind: indicate the kind of the parquet path, can be either stream_parquet or stream_controller_parquet
|
|
59
|
+
|
|
60
|
+
:return: Monitoring parquet target path.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
project_obj = mlrun.get_or_create_project(name=project)
|
|
64
|
+
artifact_path = project_obj.spec.artifact_path
|
|
65
|
+
# Generate monitoring parquet path value
|
|
66
|
+
parquet_path = mlrun.mlconf.get_model_monitoring_file_target_path(
|
|
67
|
+
project=project,
|
|
68
|
+
kind=kind,
|
|
69
|
+
target="offline",
|
|
70
|
+
artifact_path=artifact_path,
|
|
36
71
|
)
|
|
72
|
+
return parquet_path
|
|
37
73
|
|
|
38
74
|
|
|
39
75
|
def get_connection_string(secret_provider: typing.Callable = None) -> str:
|
|
@@ -27,6 +27,12 @@ from mlrun.utils import logger
|
|
|
27
27
|
|
|
28
28
|
from .model_endpoint_store import ModelEndpointStore
|
|
29
29
|
|
|
30
|
+
# Fields to encode before storing in the KV table or to decode after retrieving
|
|
31
|
+
fields_to_encode_decode = [
|
|
32
|
+
mlrun.common.schemas.model_monitoring.EventFieldType.FEATURE_STATS,
|
|
33
|
+
mlrun.common.schemas.model_monitoring.EventFieldType.CURRENT_STATS,
|
|
34
|
+
]
|
|
35
|
+
|
|
30
36
|
|
|
31
37
|
class KVModelEndpointStore(ModelEndpointStore):
|
|
32
38
|
"""
|
|
@@ -51,6 +57,11 @@ class KVModelEndpointStore(ModelEndpointStore):
|
|
|
51
57
|
:param endpoint: model endpoint dictionary that will be written into the DB.
|
|
52
58
|
"""
|
|
53
59
|
|
|
60
|
+
for field in fields_to_encode_decode:
|
|
61
|
+
if field in endpoint:
|
|
62
|
+
# Encode to binary data
|
|
63
|
+
endpoint[field] = self._encode_field(endpoint[field])
|
|
64
|
+
|
|
54
65
|
self.client.kv.put(
|
|
55
66
|
container=self.container,
|
|
56
67
|
table_path=self.path,
|
|
@@ -70,6 +81,11 @@ class KVModelEndpointStore(ModelEndpointStore):
|
|
|
70
81
|
|
|
71
82
|
"""
|
|
72
83
|
|
|
84
|
+
for field in fields_to_encode_decode:
|
|
85
|
+
if field in attributes:
|
|
86
|
+
# Encode to binary data
|
|
87
|
+
attributes[field] = self._encode_field(attributes[field])
|
|
88
|
+
|
|
73
89
|
self.client.kv.update(
|
|
74
90
|
container=self.container,
|
|
75
91
|
table_path=self.path,
|
|
@@ -117,6 +133,11 @@ class KVModelEndpointStore(ModelEndpointStore):
|
|
|
117
133
|
)
|
|
118
134
|
endpoint = endpoint.output.item
|
|
119
135
|
|
|
136
|
+
for field in fields_to_encode_decode:
|
|
137
|
+
if field in endpoint:
|
|
138
|
+
# Decode binary data
|
|
139
|
+
endpoint[field] = self._decode_field(endpoint[field])
|
|
140
|
+
|
|
120
141
|
if not endpoint:
|
|
121
142
|
raise mlrun.errors.MLRunNotFoundError(f"Endpoint {endpoint_id} not found")
|
|
122
143
|
|
|
@@ -512,3 +533,19 @@ class KVModelEndpointStore(ModelEndpointStore):
|
|
|
512
533
|
] = endpoint[
|
|
513
534
|
mlrun.common.schemas.model_monitoring.EventFieldType.ENDPOINT_ID
|
|
514
535
|
]
|
|
536
|
+
|
|
537
|
+
@staticmethod
|
|
538
|
+
def _encode_field(field: typing.Union[str, bytes]) -> bytes:
|
|
539
|
+
"""Encode a provided field. Mainly used when storing data in the KV table."""
|
|
540
|
+
|
|
541
|
+
if isinstance(field, str):
|
|
542
|
+
return field.encode("ascii")
|
|
543
|
+
return field
|
|
544
|
+
|
|
545
|
+
@staticmethod
|
|
546
|
+
def _decode_field(field: typing.Union[str, bytes]) -> str:
|
|
547
|
+
"""Decode a provided field. Mainly used when retrieving data from the KV table."""
|
|
548
|
+
|
|
549
|
+
if isinstance(field, bytes):
|
|
550
|
+
return field.decode()
|
|
551
|
+
return field
|
|
@@ -26,10 +26,7 @@ class TrackingPolicy(mlrun.model.ModelObj):
|
|
|
26
26
|
model monitoring stream.
|
|
27
27
|
"""
|
|
28
28
|
|
|
29
|
-
_dict_fields = [
|
|
30
|
-
"default_batch_image",
|
|
31
|
-
"stream_image",
|
|
32
|
-
]
|
|
29
|
+
_dict_fields = ["default_batch_image", "stream_image", "application_batch"]
|
|
33
30
|
|
|
34
31
|
def __init__(
|
|
35
32
|
self,
|
|
@@ -38,6 +35,7 @@ class TrackingPolicy(mlrun.model.ModelObj):
|
|
|
38
35
|
] = mlrun.common.schemas.schedule.ScheduleCronTrigger(minute="0", hour="*/1"),
|
|
39
36
|
default_batch_image: str = "mlrun/mlrun",
|
|
40
37
|
stream_image: str = "mlrun/mlrun",
|
|
38
|
+
application_batch: bool = False,
|
|
41
39
|
):
|
|
42
40
|
"""
|
|
43
41
|
Initialize TrackingPolicy object.
|
|
@@ -50,6 +48,7 @@ class TrackingPolicy(mlrun.model.ModelObj):
|
|
|
50
48
|
is mlrun/mlrun.
|
|
51
49
|
:param stream_image: The image of the model monitoring stream real-time function. By default,
|
|
52
50
|
the image is mlrun/mlrun.
|
|
51
|
+
:param application_batch
|
|
53
52
|
"""
|
|
54
53
|
if isinstance(default_batch_intervals, str):
|
|
55
54
|
default_batch_intervals = (
|
|
@@ -60,6 +59,7 @@ class TrackingPolicy(mlrun.model.ModelObj):
|
|
|
60
59
|
self.default_batch_intervals = default_batch_intervals
|
|
61
60
|
self.default_batch_image = default_batch_image
|
|
62
61
|
self.stream_image = stream_image
|
|
62
|
+
self.application_batch = application_batch
|
|
63
63
|
|
|
64
64
|
@classmethod
|
|
65
65
|
def from_dict(cls, struct=None, fields=None, deprecated_fields: dict = None):
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Copyright 2023 Iguazio
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
#
|
|
15
|
+
import mlrun.common.schemas
|
|
16
|
+
from mlrun.serving.utils import StepToDict
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ModelMonitoringWriter(StepToDict):
|
|
20
|
+
"""DEMO WRITER TODO"""
|
|
21
|
+
|
|
22
|
+
kind = "monitoring_application_stream_pusher"
|
|
23
|
+
|
|
24
|
+
def __init__(self, name: str = None):
|
|
25
|
+
self.name = name or "king"
|
|
26
|
+
|
|
27
|
+
def do(self, event):
|
|
28
|
+
|
|
29
|
+
print(
|
|
30
|
+
f"endpoint_uid ={event[mlrun.common.schemas.model_monitoring.constants.WriterEvent.ENDPOINT_ID]}, \n"
|
|
31
|
+
f"app_name = {event[mlrun.common.schemas.model_monitoring.constants.WriterEvent.APPLICATION_NAME]}, \n"
|
|
32
|
+
f"schedule_time = {event[mlrun.common.schemas.model_monitoring.constants.WriterEvent.SCHEDULE_TIME]}, \n"
|
|
33
|
+
f"result_name ={event[mlrun.common.schemas.model_monitoring.constants.WriterEvent.RESULT_NAME]}, \n"
|
|
34
|
+
f"result_value ={event[mlrun.common.schemas.model_monitoring.constants.WriterEvent.RESULT_VALUE]}, \n"
|
|
35
|
+
f"my_name = {self.name}."
|
|
36
|
+
)
|
|
37
|
+
return event
|
mlrun/projects/pipelines.py
CHANGED
|
@@ -19,6 +19,7 @@ import tempfile
|
|
|
19
19
|
import traceback
|
|
20
20
|
import typing
|
|
21
21
|
import uuid
|
|
22
|
+
import warnings
|
|
22
23
|
|
|
23
24
|
import kfp.compiler
|
|
24
25
|
from kfp import dsl
|
|
@@ -76,18 +77,28 @@ class WorkflowSpec(mlrun.model.ModelObj):
|
|
|
76
77
|
args=None,
|
|
77
78
|
name=None,
|
|
78
79
|
handler=None,
|
|
80
|
+
# TODO: deprecated, remove in 1.6.0
|
|
81
|
+
ttl=None,
|
|
79
82
|
args_schema: dict = None,
|
|
80
83
|
schedule: typing.Union[str, mlrun.common.schemas.ScheduleCronTrigger] = None,
|
|
81
84
|
cleanup_ttl: int = None,
|
|
82
85
|
image: str = None,
|
|
83
86
|
):
|
|
87
|
+
if ttl:
|
|
88
|
+
warnings.warn(
|
|
89
|
+
"'ttl' is deprecated, use 'cleanup_ttl' instead. "
|
|
90
|
+
"This will be removed in 1.6.0",
|
|
91
|
+
# TODO: Remove this in 1.6.0
|
|
92
|
+
FutureWarning,
|
|
93
|
+
)
|
|
84
94
|
self.engine = engine
|
|
85
95
|
self.code = code
|
|
86
96
|
self.path = path
|
|
87
97
|
self.args = args
|
|
88
98
|
self.name = name
|
|
89
99
|
self.handler = handler
|
|
90
|
-
self.
|
|
100
|
+
self.ttl = cleanup_ttl or ttl
|
|
101
|
+
self.cleanup_ttl = cleanup_ttl or ttl
|
|
91
102
|
self.args_schema = args_schema
|
|
92
103
|
self.run_local = False
|
|
93
104
|
self._tmp_path = None
|
|
@@ -550,7 +561,7 @@ class _KFPRunner(_PipelineRunner):
|
|
|
550
561
|
|
|
551
562
|
conf = new_pipe_metadata(
|
|
552
563
|
artifact_path=artifact_path,
|
|
553
|
-
cleanup_ttl=workflow_spec.cleanup_ttl,
|
|
564
|
+
cleanup_ttl=workflow_spec.cleanup_ttl or workflow_spec.ttl,
|
|
554
565
|
)
|
|
555
566
|
compiler.Compiler().compile(pipeline, target, pipeline_conf=conf)
|
|
556
567
|
workflow_spec.clear_tmp()
|
|
@@ -583,7 +594,7 @@ class _KFPRunner(_PipelineRunner):
|
|
|
583
594
|
experiment=name or workflow_spec.name,
|
|
584
595
|
namespace=namespace,
|
|
585
596
|
artifact_path=artifact_path,
|
|
586
|
-
cleanup_ttl=workflow_spec.cleanup_ttl,
|
|
597
|
+
cleanup_ttl=workflow_spec.cleanup_ttl or workflow_spec.ttl,
|
|
587
598
|
)
|
|
588
599
|
project.notifiers.push_pipeline_start_message(
|
|
589
600
|
project.metadata.name,
|
|
@@ -764,6 +775,13 @@ class _RemoteRunner(_PipelineRunner):
|
|
|
764
775
|
inner_engine = get_workflow_engine(workflow_spec.engine)
|
|
765
776
|
run_db = mlrun.get_run_db()
|
|
766
777
|
try:
|
|
778
|
+
logger.info(
|
|
779
|
+
"Submitting remote workflow",
|
|
780
|
+
workflow_engine=workflow_spec.engine,
|
|
781
|
+
schedule=workflow_spec.schedule,
|
|
782
|
+
project_name=project.name,
|
|
783
|
+
)
|
|
784
|
+
|
|
767
785
|
workflow_response = run_db.submit_workflow(
|
|
768
786
|
project=project.name,
|
|
769
787
|
name=workflow_name,
|
|
@@ -776,6 +794,10 @@ class _RemoteRunner(_PipelineRunner):
|
|
|
776
794
|
namespace=namespace,
|
|
777
795
|
)
|
|
778
796
|
if workflow_spec.schedule:
|
|
797
|
+
logger.info(
|
|
798
|
+
"Workflow scheduled successfully",
|
|
799
|
+
workflow_response=workflow_response,
|
|
800
|
+
)
|
|
779
801
|
return
|
|
780
802
|
|
|
781
803
|
# Getting workflow id from run:
|
|
@@ -883,6 +905,8 @@ def load_and_run(
|
|
|
883
905
|
namespace: str = None,
|
|
884
906
|
sync: bool = False,
|
|
885
907
|
dirty: bool = False,
|
|
908
|
+
# TODO: deprecated, remove in 1.6.0
|
|
909
|
+
ttl: int = None,
|
|
886
910
|
engine: str = None,
|
|
887
911
|
local: bool = None,
|
|
888
912
|
schedule: typing.Union[str, mlrun.common.schemas.ScheduleCronTrigger] = None,
|
|
@@ -910,6 +934,8 @@ def load_and_run(
|
|
|
910
934
|
:param namespace: kubernetes namespace if other than default
|
|
911
935
|
:param sync: force functions sync before run
|
|
912
936
|
:param dirty: allow running the workflow when the git repo is dirty
|
|
937
|
+
:param ttl: pipeline cleanup ttl in secs (time to wait after workflow completion, at which point the
|
|
938
|
+
workflow and all its resources are deleted) (deprecated, use cleanup_ttl instead)
|
|
913
939
|
:param engine: workflow engine running the workflow.
|
|
914
940
|
supported values are 'kfp' (default) or 'local'
|
|
915
941
|
:param local: run local pipeline with local functions (set local=True in function.run())
|
|
@@ -918,6 +944,14 @@ def load_and_run(
|
|
|
918
944
|
workflow and all its resources are deleted)
|
|
919
945
|
:param load_only: for just loading the project, inner use.
|
|
920
946
|
"""
|
|
947
|
+
if ttl:
|
|
948
|
+
warnings.warn(
|
|
949
|
+
"'ttl' is deprecated, use 'cleanup_ttl' instead. "
|
|
950
|
+
"This will be removed in 1.6.0",
|
|
951
|
+
# TODO: Remove this in 1.6.0
|
|
952
|
+
FutureWarning,
|
|
953
|
+
)
|
|
954
|
+
|
|
921
955
|
try:
|
|
922
956
|
project = mlrun.load_project(
|
|
923
957
|
context=f"./{project_name}",
|
|
@@ -969,7 +1003,7 @@ def load_and_run(
|
|
|
969
1003
|
sync=sync,
|
|
970
1004
|
watch=False, # Required for fetching the workflow_id
|
|
971
1005
|
dirty=dirty,
|
|
972
|
-
cleanup_ttl=cleanup_ttl,
|
|
1006
|
+
cleanup_ttl=cleanup_ttl or ttl,
|
|
973
1007
|
engine=engine,
|
|
974
1008
|
local=local,
|
|
975
1009
|
)
|