mlrun 1.6.4rc8__py3-none-any.whl → 1.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mlrun might be problematic. Click here for more details.
- mlrun/__init__.py +11 -1
- mlrun/__main__.py +40 -122
- mlrun/alerts/__init__.py +15 -0
- mlrun/alerts/alert.py +248 -0
- mlrun/api/schemas/__init__.py +5 -4
- mlrun/artifacts/__init__.py +8 -3
- mlrun/artifacts/base.py +47 -257
- mlrun/artifacts/dataset.py +11 -192
- mlrun/artifacts/manager.py +79 -47
- mlrun/artifacts/model.py +31 -159
- mlrun/artifacts/plots.py +23 -380
- mlrun/common/constants.py +74 -1
- mlrun/common/db/sql_session.py +5 -5
- mlrun/common/formatters/__init__.py +21 -0
- mlrun/common/formatters/artifact.py +45 -0
- mlrun/common/formatters/base.py +113 -0
- mlrun/common/formatters/feature_set.py +33 -0
- mlrun/common/formatters/function.py +46 -0
- mlrun/common/formatters/pipeline.py +53 -0
- mlrun/common/formatters/project.py +51 -0
- mlrun/common/formatters/run.py +29 -0
- mlrun/common/helpers.py +12 -3
- mlrun/common/model_monitoring/helpers.py +9 -5
- mlrun/{runtimes → common/runtimes}/constants.py +37 -9
- mlrun/common/schemas/__init__.py +31 -5
- mlrun/common/schemas/alert.py +202 -0
- mlrun/common/schemas/api_gateway.py +196 -0
- mlrun/common/schemas/artifact.py +25 -4
- mlrun/common/schemas/auth.py +16 -5
- mlrun/common/schemas/background_task.py +1 -1
- mlrun/common/schemas/client_spec.py +4 -2
- mlrun/common/schemas/common.py +7 -4
- mlrun/common/schemas/constants.py +3 -0
- mlrun/common/schemas/feature_store.py +74 -44
- mlrun/common/schemas/frontend_spec.py +15 -7
- mlrun/common/schemas/function.py +12 -1
- mlrun/common/schemas/hub.py +11 -18
- mlrun/common/schemas/memory_reports.py +2 -2
- mlrun/common/schemas/model_monitoring/__init__.py +20 -4
- mlrun/common/schemas/model_monitoring/constants.py +123 -42
- mlrun/common/schemas/model_monitoring/grafana.py +13 -9
- mlrun/common/schemas/model_monitoring/model_endpoints.py +101 -54
- mlrun/common/schemas/notification.py +71 -14
- mlrun/common/schemas/object.py +2 -2
- mlrun/{model_monitoring/controller_handler.py → common/schemas/pagination.py} +9 -12
- mlrun/common/schemas/pipeline.py +8 -1
- mlrun/common/schemas/project.py +69 -18
- mlrun/common/schemas/runs.py +7 -1
- mlrun/common/schemas/runtime_resource.py +8 -12
- mlrun/common/schemas/schedule.py +4 -4
- mlrun/common/schemas/tag.py +1 -2
- mlrun/common/schemas/workflow.py +12 -4
- mlrun/common/types.py +14 -1
- mlrun/config.py +154 -69
- mlrun/data_types/data_types.py +6 -1
- mlrun/data_types/spark.py +2 -2
- mlrun/data_types/to_pandas.py +67 -37
- mlrun/datastore/__init__.py +6 -8
- mlrun/datastore/alibaba_oss.py +131 -0
- mlrun/datastore/azure_blob.py +143 -42
- mlrun/datastore/base.py +102 -58
- mlrun/datastore/datastore.py +34 -13
- mlrun/datastore/datastore_profile.py +146 -20
- mlrun/datastore/dbfs_store.py +3 -7
- mlrun/datastore/filestore.py +1 -4
- mlrun/datastore/google_cloud_storage.py +97 -33
- mlrun/datastore/hdfs.py +56 -0
- mlrun/datastore/inmem.py +6 -3
- mlrun/datastore/redis.py +7 -2
- mlrun/datastore/s3.py +34 -12
- mlrun/datastore/snowflake_utils.py +45 -0
- mlrun/datastore/sources.py +303 -111
- mlrun/datastore/spark_utils.py +31 -2
- mlrun/datastore/store_resources.py +9 -7
- mlrun/datastore/storeytargets.py +151 -0
- mlrun/datastore/targets.py +453 -176
- mlrun/datastore/utils.py +72 -58
- mlrun/datastore/v3io.py +6 -1
- mlrun/db/base.py +274 -41
- mlrun/db/factory.py +1 -1
- mlrun/db/httpdb.py +893 -225
- mlrun/db/nopdb.py +291 -33
- mlrun/errors.py +36 -6
- mlrun/execution.py +115 -42
- mlrun/feature_store/__init__.py +0 -2
- mlrun/feature_store/api.py +65 -73
- mlrun/feature_store/common.py +7 -12
- mlrun/feature_store/feature_set.py +76 -55
- mlrun/feature_store/feature_vector.py +39 -31
- mlrun/feature_store/ingestion.py +7 -6
- mlrun/feature_store/retrieval/base.py +16 -11
- mlrun/feature_store/retrieval/dask_merger.py +2 -0
- mlrun/feature_store/retrieval/job.py +13 -4
- mlrun/feature_store/retrieval/local_merger.py +2 -0
- mlrun/feature_store/retrieval/spark_merger.py +24 -32
- mlrun/feature_store/steps.py +45 -34
- mlrun/features.py +11 -21
- mlrun/frameworks/_common/artifacts_library.py +9 -9
- mlrun/frameworks/_common/mlrun_interface.py +5 -5
- mlrun/frameworks/_common/model_handler.py +48 -48
- mlrun/frameworks/_common/plan.py +5 -6
- mlrun/frameworks/_common/producer.py +3 -4
- mlrun/frameworks/_common/utils.py +5 -5
- mlrun/frameworks/_dl_common/loggers/logger.py +6 -7
- mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +9 -9
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +23 -47
- mlrun/frameworks/_ml_common/artifacts_library.py +1 -2
- mlrun/frameworks/_ml_common/loggers/logger.py +3 -4
- mlrun/frameworks/_ml_common/loggers/mlrun_logger.py +4 -5
- mlrun/frameworks/_ml_common/model_handler.py +24 -24
- mlrun/frameworks/_ml_common/pkl_model_server.py +2 -2
- mlrun/frameworks/_ml_common/plan.py +2 -2
- mlrun/frameworks/_ml_common/plans/calibration_curve_plan.py +2 -3
- mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +2 -3
- mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
- mlrun/frameworks/_ml_common/plans/feature_importance_plan.py +3 -3
- mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
- mlrun/frameworks/_ml_common/utils.py +4 -4
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +9 -9
- mlrun/frameworks/huggingface/model_server.py +4 -4
- mlrun/frameworks/lgbm/__init__.py +33 -33
- mlrun/frameworks/lgbm/callbacks/callback.py +2 -4
- mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -5
- mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -5
- mlrun/frameworks/lgbm/mlrun_interfaces/booster_mlrun_interface.py +1 -3
- mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +6 -6
- mlrun/frameworks/lgbm/model_handler.py +10 -10
- mlrun/frameworks/lgbm/model_server.py +6 -6
- mlrun/frameworks/lgbm/utils.py +5 -5
- mlrun/frameworks/onnx/dataset.py +8 -8
- mlrun/frameworks/onnx/mlrun_interface.py +3 -3
- mlrun/frameworks/onnx/model_handler.py +6 -6
- mlrun/frameworks/onnx/model_server.py +7 -7
- mlrun/frameworks/parallel_coordinates.py +6 -6
- mlrun/frameworks/pytorch/__init__.py +18 -18
- mlrun/frameworks/pytorch/callbacks/callback.py +4 -5
- mlrun/frameworks/pytorch/callbacks/logging_callback.py +17 -17
- mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +11 -11
- mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +23 -29
- mlrun/frameworks/pytorch/callbacks_handler.py +38 -38
- mlrun/frameworks/pytorch/mlrun_interface.py +20 -20
- mlrun/frameworks/pytorch/model_handler.py +17 -17
- mlrun/frameworks/pytorch/model_server.py +7 -7
- mlrun/frameworks/sklearn/__init__.py +13 -13
- mlrun/frameworks/sklearn/estimator.py +4 -4
- mlrun/frameworks/sklearn/metrics_library.py +14 -14
- mlrun/frameworks/sklearn/mlrun_interface.py +16 -9
- mlrun/frameworks/sklearn/model_handler.py +2 -2
- mlrun/frameworks/tf_keras/__init__.py +10 -7
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +15 -15
- mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +11 -11
- mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +19 -23
- mlrun/frameworks/tf_keras/mlrun_interface.py +9 -11
- mlrun/frameworks/tf_keras/model_handler.py +14 -14
- mlrun/frameworks/tf_keras/model_server.py +6 -6
- mlrun/frameworks/xgboost/__init__.py +13 -13
- mlrun/frameworks/xgboost/model_handler.py +6 -6
- mlrun/k8s_utils.py +61 -17
- mlrun/launcher/__init__.py +1 -1
- mlrun/launcher/base.py +16 -15
- mlrun/launcher/client.py +13 -11
- mlrun/launcher/factory.py +1 -1
- mlrun/launcher/local.py +23 -13
- mlrun/launcher/remote.py +17 -10
- mlrun/lists.py +7 -6
- mlrun/model.py +478 -103
- mlrun/model_monitoring/__init__.py +1 -1
- mlrun/model_monitoring/api.py +163 -371
- mlrun/{runtimes/mpijob/v1alpha1.py → model_monitoring/applications/__init__.py} +9 -15
- mlrun/model_monitoring/applications/_application_steps.py +188 -0
- mlrun/model_monitoring/applications/base.py +108 -0
- mlrun/model_monitoring/applications/context.py +341 -0
- mlrun/model_monitoring/{evidently_application.py → applications/evidently_base.py} +27 -22
- mlrun/model_monitoring/applications/histogram_data_drift.py +354 -0
- mlrun/model_monitoring/applications/results.py +99 -0
- mlrun/model_monitoring/controller.py +131 -278
- mlrun/model_monitoring/db/__init__.py +18 -0
- mlrun/model_monitoring/db/stores/__init__.py +136 -0
- mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
- mlrun/model_monitoring/db/stores/base/store.py +213 -0
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +190 -0
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +103 -0
- mlrun/model_monitoring/{stores/models/mysql.py → db/stores/sqldb/models/sqlite.py} +19 -13
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +659 -0
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +726 -0
- mlrun/model_monitoring/db/tsdb/__init__.py +105 -0
- mlrun/model_monitoring/db/tsdb/base.py +448 -0
- mlrun/model_monitoring/db/tsdb/helpers.py +30 -0
- mlrun/model_monitoring/db/tsdb/tdengine/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +279 -0
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +42 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +507 -0
- mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +158 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +849 -0
- mlrun/model_monitoring/features_drift_table.py +134 -106
- mlrun/model_monitoring/helpers.py +199 -55
- mlrun/model_monitoring/metrics/__init__.py +13 -0
- mlrun/model_monitoring/metrics/histogram_distance.py +127 -0
- mlrun/model_monitoring/model_endpoint.py +3 -2
- mlrun/model_monitoring/stream_processing.py +134 -398
- mlrun/model_monitoring/tracking_policy.py +9 -2
- mlrun/model_monitoring/writer.py +161 -125
- mlrun/package/__init__.py +6 -6
- mlrun/package/context_handler.py +5 -5
- mlrun/package/packager.py +7 -7
- mlrun/package/packagers/default_packager.py +8 -8
- mlrun/package/packagers/numpy_packagers.py +15 -15
- mlrun/package/packagers/pandas_packagers.py +5 -5
- mlrun/package/packagers/python_standard_library_packagers.py +10 -10
- mlrun/package/packagers_manager.py +19 -23
- mlrun/package/utils/_formatter.py +6 -6
- mlrun/package/utils/_pickler.py +2 -2
- mlrun/package/utils/_supported_format.py +4 -4
- mlrun/package/utils/log_hint_utils.py +2 -2
- mlrun/package/utils/type_hint_utils.py +4 -9
- mlrun/platforms/__init__.py +11 -10
- mlrun/platforms/iguazio.py +24 -203
- mlrun/projects/operations.py +52 -25
- mlrun/projects/pipelines.py +191 -197
- mlrun/projects/project.py +1227 -400
- mlrun/render.py +16 -19
- mlrun/run.py +209 -184
- mlrun/runtimes/__init__.py +83 -15
- mlrun/runtimes/base.py +51 -35
- mlrun/runtimes/daskjob.py +17 -10
- mlrun/runtimes/databricks_job/databricks_cancel_task.py +1 -1
- mlrun/runtimes/databricks_job/databricks_runtime.py +8 -7
- mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
- mlrun/runtimes/funcdoc.py +1 -29
- mlrun/runtimes/function_reference.py +1 -1
- mlrun/runtimes/kubejob.py +34 -128
- mlrun/runtimes/local.py +40 -11
- mlrun/runtimes/mpijob/__init__.py +0 -20
- mlrun/runtimes/mpijob/abstract.py +9 -10
- mlrun/runtimes/mpijob/v1.py +1 -1
- mlrun/{model_monitoring/stores/models/sqlite.py → runtimes/nuclio/__init__.py} +7 -9
- mlrun/runtimes/nuclio/api_gateway.py +769 -0
- mlrun/runtimes/nuclio/application/__init__.py +15 -0
- mlrun/runtimes/nuclio/application/application.py +758 -0
- mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
- mlrun/runtimes/{function.py → nuclio/function.py} +200 -83
- mlrun/runtimes/{nuclio.py → nuclio/nuclio.py} +6 -6
- mlrun/runtimes/{serving.py → nuclio/serving.py} +65 -68
- mlrun/runtimes/pod.py +281 -101
- mlrun/runtimes/remotesparkjob.py +12 -9
- mlrun/runtimes/sparkjob/spark3job.py +67 -51
- mlrun/runtimes/utils.py +41 -75
- mlrun/secrets.py +9 -5
- mlrun/serving/__init__.py +8 -1
- mlrun/serving/remote.py +2 -7
- mlrun/serving/routers.py +85 -69
- mlrun/serving/server.py +69 -44
- mlrun/serving/states.py +209 -36
- mlrun/serving/utils.py +22 -14
- mlrun/serving/v1_serving.py +6 -7
- mlrun/serving/v2_serving.py +133 -54
- mlrun/track/tracker.py +2 -1
- mlrun/track/tracker_manager.py +3 -3
- mlrun/track/trackers/mlflow_tracker.py +6 -2
- mlrun/utils/async_http.py +6 -8
- mlrun/utils/azure_vault.py +1 -1
- mlrun/utils/clones.py +1 -2
- mlrun/utils/condition_evaluator.py +3 -3
- mlrun/utils/db.py +21 -3
- mlrun/utils/helpers.py +405 -225
- mlrun/utils/http.py +3 -6
- mlrun/utils/logger.py +112 -16
- mlrun/utils/notifications/notification/__init__.py +17 -13
- mlrun/utils/notifications/notification/base.py +50 -2
- mlrun/utils/notifications/notification/console.py +2 -0
- mlrun/utils/notifications/notification/git.py +24 -1
- mlrun/utils/notifications/notification/ipython.py +3 -1
- mlrun/utils/notifications/notification/slack.py +96 -21
- mlrun/utils/notifications/notification/webhook.py +59 -2
- mlrun/utils/notifications/notification_pusher.py +149 -30
- mlrun/utils/regex.py +9 -0
- mlrun/utils/retryer.py +208 -0
- mlrun/utils/singleton.py +1 -1
- mlrun/utils/v3io_clients.py +4 -6
- mlrun/utils/version/version.json +2 -2
- mlrun/utils/version/version.py +2 -6
- mlrun-1.7.0.dist-info/METADATA +378 -0
- mlrun-1.7.0.dist-info/RECORD +351 -0
- {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/WHEEL +1 -1
- mlrun/feature_store/retrieval/conversion.py +0 -273
- mlrun/kfpops.py +0 -868
- mlrun/model_monitoring/application.py +0 -310
- mlrun/model_monitoring/batch.py +0 -1095
- mlrun/model_monitoring/prometheus.py +0 -219
- mlrun/model_monitoring/stores/__init__.py +0 -111
- mlrun/model_monitoring/stores/kv_model_endpoint_store.py +0 -576
- mlrun/model_monitoring/stores/model_endpoint_store.py +0 -147
- mlrun/model_monitoring/stores/models/__init__.py +0 -27
- mlrun/model_monitoring/stores/models/base.py +0 -84
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -384
- mlrun/platforms/other.py +0 -306
- mlrun-1.6.4rc8.dist-info/METADATA +0 -272
- mlrun-1.6.4rc8.dist-info/RECORD +0 -314
- {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/LICENSE +0 -0
- {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/entry_points.txt +0 -0
- {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/top_level.txt +0 -0
mlrun/serving/v2_serving.py
CHANGED
|
@@ -15,12 +15,13 @@
|
|
|
15
15
|
import threading
|
|
16
16
|
import time
|
|
17
17
|
import traceback
|
|
18
|
-
from typing import
|
|
18
|
+
from typing import Optional, Union
|
|
19
19
|
|
|
20
|
-
import mlrun.
|
|
20
|
+
import mlrun.artifacts
|
|
21
|
+
import mlrun.common.model_monitoring.helpers
|
|
21
22
|
import mlrun.common.schemas.model_monitoring
|
|
22
|
-
|
|
23
|
-
from mlrun.
|
|
23
|
+
import mlrun.model_monitoring
|
|
24
|
+
from mlrun.errors import err_to_str
|
|
24
25
|
from mlrun.utils import logger, now_date
|
|
25
26
|
|
|
26
27
|
from ..common.helpers import parse_versioned_object_uri
|
|
@@ -29,8 +30,6 @@ from .utils import StepToDict, _extract_input_data, _update_result_body
|
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
class V2ModelServer(StepToDict):
|
|
32
|
-
"""base model serving class (v2), using similar API to KFServing v2 and Triton"""
|
|
33
|
-
|
|
34
33
|
def __init__(
|
|
35
34
|
self,
|
|
36
35
|
context=None,
|
|
@@ -64,11 +63,11 @@ class V2ModelServer(StepToDict):
|
|
|
64
63
|
class MyClass(V2ModelServer):
|
|
65
64
|
def load(self):
|
|
66
65
|
# load and initialize the model and/or other elements
|
|
67
|
-
model_file, extra_data = self.get_model(suffix=
|
|
66
|
+
model_file, extra_data = self.get_model(suffix=".pkl")
|
|
68
67
|
self.model = load(open(model_file, "rb"))
|
|
69
68
|
|
|
70
69
|
def predict(self, request):
|
|
71
|
-
events = np.array(request[
|
|
70
|
+
events = np.array(request["inputs"])
|
|
72
71
|
dmatrix = xgb.DMatrix(events)
|
|
73
72
|
result: xgb.DMatrix = self.model.predict(dmatrix)
|
|
74
73
|
return {"outputs": result.tolist()}
|
|
@@ -103,7 +102,7 @@ class V2ModelServer(StepToDict):
|
|
|
103
102
|
self.error = ""
|
|
104
103
|
self.protocol = protocol or "v2"
|
|
105
104
|
self.model_path = model_path
|
|
106
|
-
self.model_spec: mlrun.artifacts.ModelArtifact = None
|
|
105
|
+
self.model_spec: Optional[mlrun.artifacts.ModelArtifact] = None
|
|
107
106
|
self._input_path = input_path
|
|
108
107
|
self._result_path = result_path
|
|
109
108
|
self._kwargs = kwargs # for to_dict()
|
|
@@ -149,7 +148,7 @@ class V2ModelServer(StepToDict):
|
|
|
149
148
|
logger.warn("GraphServer not initialized for VotingEnsemble instance")
|
|
150
149
|
return
|
|
151
150
|
|
|
152
|
-
if not self.context.is_mock or self.context.
|
|
151
|
+
if not self.context.is_mock or self.context.monitoring_mock:
|
|
153
152
|
self.model_endpoint_uid = _init_endpoint_record(
|
|
154
153
|
graph_server=server, model=self
|
|
155
154
|
)
|
|
@@ -177,9 +176,9 @@ class V2ModelServer(StepToDict):
|
|
|
177
176
|
::
|
|
178
177
|
|
|
179
178
|
def load(self):
|
|
180
|
-
model_file, extra_data = self.get_model(suffix=
|
|
179
|
+
model_file, extra_data = self.get_model(suffix=".pkl")
|
|
181
180
|
self.model = load(open(model_file, "rb"))
|
|
182
|
-
categories = extra_data[
|
|
181
|
+
categories = extra_data["categories"].as_df()
|
|
183
182
|
|
|
184
183
|
Parameters
|
|
185
184
|
----------
|
|
@@ -221,6 +220,8 @@ class V2ModelServer(StepToDict):
|
|
|
221
220
|
|
|
222
221
|
def _pre_event_processing_actions(self, event, event_body, op):
|
|
223
222
|
self._check_readiness(event)
|
|
223
|
+
if "_dict" in op:
|
|
224
|
+
event_body = self._inputs_to_list(event_body)
|
|
224
225
|
request = self.preprocess(event_body, op)
|
|
225
226
|
return self.validate(request, op)
|
|
226
227
|
|
|
@@ -237,7 +238,12 @@ class V2ModelServer(StepToDict):
|
|
|
237
238
|
if not op and event.method != "GET":
|
|
238
239
|
op = "infer"
|
|
239
240
|
|
|
240
|
-
if
|
|
241
|
+
if (
|
|
242
|
+
op == "predict"
|
|
243
|
+
or op == "infer"
|
|
244
|
+
or op == "infer_dict"
|
|
245
|
+
or op == "predict_dict"
|
|
246
|
+
):
|
|
241
247
|
# predict operation
|
|
242
248
|
request = self._pre_event_processing_actions(event, event_body, op)
|
|
243
249
|
try:
|
|
@@ -252,6 +258,7 @@ class V2ModelServer(StepToDict):
|
|
|
252
258
|
"id": event_id,
|
|
253
259
|
"model_name": self.name,
|
|
254
260
|
"outputs": outputs,
|
|
261
|
+
"timestamp": start.isoformat(sep=" ", timespec="microseconds"),
|
|
255
262
|
}
|
|
256
263
|
if self.version:
|
|
257
264
|
response["model_version"] = self.version
|
|
@@ -329,6 +336,7 @@ class V2ModelServer(StepToDict):
|
|
|
329
336
|
else:
|
|
330
337
|
track_request = {"id": event_id, "inputs": inputs or []}
|
|
331
338
|
track_response = {"outputs": outputs or []}
|
|
339
|
+
# TODO : check dict/list
|
|
332
340
|
self._model_logger.push(start, track_request, track_response, op)
|
|
333
341
|
event.body = _update_result_body(self._result_path, original_body, response)
|
|
334
342
|
return event
|
|
@@ -362,22 +370,61 @@ class V2ModelServer(StepToDict):
|
|
|
362
370
|
|
|
363
371
|
return request
|
|
364
372
|
|
|
365
|
-
def preprocess(self, request:
|
|
373
|
+
def preprocess(self, request: dict, operation) -> dict:
|
|
366
374
|
"""preprocess the event body before validate and action"""
|
|
367
375
|
return request
|
|
368
376
|
|
|
369
|
-
def postprocess(self, request:
|
|
377
|
+
def postprocess(self, request: dict) -> dict:
|
|
370
378
|
"""postprocess, before returning response"""
|
|
371
379
|
return request
|
|
372
380
|
|
|
373
|
-
def predict(self, request:
|
|
374
|
-
"""model prediction operation
|
|
381
|
+
def predict(self, request: dict) -> list:
|
|
382
|
+
"""model prediction operation
|
|
383
|
+
:return: list with the model prediction results (can be multi-port) or list of lists for multiple predictions
|
|
384
|
+
"""
|
|
375
385
|
raise NotImplementedError()
|
|
376
386
|
|
|
377
|
-
def explain(self, request:
|
|
387
|
+
def explain(self, request: dict) -> dict:
|
|
378
388
|
"""model explain operation"""
|
|
379
389
|
raise NotImplementedError()
|
|
380
390
|
|
|
391
|
+
def _inputs_to_list(self, request: dict) -> dict:
|
|
392
|
+
"""
|
|
393
|
+
Convert the inputs from list of dictionary / dictionary to list of lists / list
|
|
394
|
+
where the internal list order is according to the ArtifactModel inputs.
|
|
395
|
+
|
|
396
|
+
:param request: event
|
|
397
|
+
:return: evnet body converting the inputs to be list of lists
|
|
398
|
+
"""
|
|
399
|
+
if self.model_spec and self.model_spec.inputs:
|
|
400
|
+
input_order = [feature.name for feature in self.model_spec.inputs]
|
|
401
|
+
else:
|
|
402
|
+
raise mlrun.MLRunInvalidArgumentError(
|
|
403
|
+
"In order to use predict_dict or infer_dict operation you have to provide `model_path` "
|
|
404
|
+
"to the model server and to load it by `load()` function"
|
|
405
|
+
)
|
|
406
|
+
inputs = request.get("inputs")
|
|
407
|
+
try:
|
|
408
|
+
if isinstance(inputs, list) and all(
|
|
409
|
+
isinstance(item, dict) for item in inputs
|
|
410
|
+
):
|
|
411
|
+
new_inputs = [
|
|
412
|
+
[input_dict[key] for key in input_order] for input_dict in inputs
|
|
413
|
+
]
|
|
414
|
+
elif isinstance(inputs, dict):
|
|
415
|
+
new_inputs = [inputs[key] for key in input_order]
|
|
416
|
+
else:
|
|
417
|
+
raise mlrun.MLRunInvalidArgumentError(
|
|
418
|
+
"When using predict_dict or infer_dict operation the inputs must be "
|
|
419
|
+
"of type `list[dict]` or `dict`"
|
|
420
|
+
)
|
|
421
|
+
except KeyError:
|
|
422
|
+
raise mlrun.MLRunInvalidArgumentError(
|
|
423
|
+
f"Input dictionary don't contain all the necessary input keys : {input_order}"
|
|
424
|
+
)
|
|
425
|
+
request["inputs"] = new_inputs
|
|
426
|
+
return request
|
|
427
|
+
|
|
381
428
|
|
|
382
429
|
class _ModelLogPusher:
|
|
383
430
|
def __init__(self, model, context, output_stream=None):
|
|
@@ -481,11 +528,17 @@ def _init_endpoint_record(
|
|
|
481
528
|
graph_server.function_uri
|
|
482
529
|
)
|
|
483
530
|
except Exception as e:
|
|
484
|
-
logger.error("Failed to parse function URI", exc=e)
|
|
531
|
+
logger.error("Failed to parse function URI", exc=err_to_str(e))
|
|
485
532
|
return None
|
|
486
533
|
|
|
487
534
|
# Generating version model value based on the model name and model version
|
|
488
|
-
if model.
|
|
535
|
+
if model.model_path and model.model_path.startswith("store://"):
|
|
536
|
+
# Enrich the model server with the model artifact metadata
|
|
537
|
+
model.get_model()
|
|
538
|
+
if not model.version:
|
|
539
|
+
# Enrich the model version with the model artifact tag
|
|
540
|
+
model.version = model.model_spec.tag
|
|
541
|
+
model.labels = model.model_spec.labels
|
|
489
542
|
versioned_model_name = f"{model.name}:{model.version}"
|
|
490
543
|
else:
|
|
491
544
|
versioned_model_name = f"{model.name}:latest"
|
|
@@ -495,48 +548,74 @@ def _init_endpoint_record(
|
|
|
495
548
|
function_uri=graph_server.function_uri, versioned_model=versioned_model_name
|
|
496
549
|
).uid
|
|
497
550
|
|
|
498
|
-
# If model endpoint object was found in DB, skip the creation process.
|
|
499
551
|
try:
|
|
500
|
-
mlrun.get_run_db().get_model_endpoint(
|
|
501
|
-
|
|
552
|
+
model_ep = mlrun.get_run_db().get_model_endpoint(
|
|
553
|
+
project=project, endpoint_id=uid
|
|
554
|
+
)
|
|
502
555
|
except mlrun.errors.MLRunNotFoundError:
|
|
556
|
+
model_ep = None
|
|
557
|
+
except mlrun.errors.MLRunBadRequestError as err:
|
|
558
|
+
logger.info(
|
|
559
|
+
"Cannot get the model endpoints store", err=mlrun.errors.err_to_str(err)
|
|
560
|
+
)
|
|
561
|
+
return
|
|
562
|
+
|
|
563
|
+
if model.context.server.track_models and not model_ep:
|
|
503
564
|
logger.info("Creating a new model endpoint record", endpoint_id=uid)
|
|
565
|
+
model_endpoint = mlrun.common.schemas.ModelEndpoint(
|
|
566
|
+
metadata=mlrun.common.schemas.ModelEndpointMetadata(
|
|
567
|
+
project=project, labels=model.labels, uid=uid
|
|
568
|
+
),
|
|
569
|
+
spec=mlrun.common.schemas.ModelEndpointSpec(
|
|
570
|
+
function_uri=graph_server.function_uri,
|
|
571
|
+
model=versioned_model_name,
|
|
572
|
+
model_class=model.__class__.__name__,
|
|
573
|
+
model_uri=model.model_path,
|
|
574
|
+
stream_path=model.context.stream.stream_uri,
|
|
575
|
+
active=True,
|
|
576
|
+
monitoring_mode=mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled,
|
|
577
|
+
),
|
|
578
|
+
status=mlrun.common.schemas.ModelEndpointStatus(
|
|
579
|
+
endpoint_type=mlrun.common.schemas.model_monitoring.EndpointType.NODE_EP
|
|
580
|
+
),
|
|
581
|
+
)
|
|
504
582
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
function_uri=graph_server.function_uri,
|
|
512
|
-
model=versioned_model_name,
|
|
513
|
-
model_class=model.__class__.__name__,
|
|
514
|
-
model_uri=model.model_path,
|
|
515
|
-
stream_path=config.model_endpoint_monitoring.store_prefixes.default.format(
|
|
516
|
-
project=project, kind="stream"
|
|
517
|
-
),
|
|
518
|
-
active=True,
|
|
519
|
-
monitoring_mode=mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled
|
|
520
|
-
if model.context.server.track_models
|
|
521
|
-
else mlrun.common.schemas.model_monitoring.ModelMonitoringMode.disabled,
|
|
522
|
-
),
|
|
523
|
-
status=mlrun.common.schemas.ModelEndpointStatus(
|
|
524
|
-
endpoint_type=mlrun.common.schemas.model_monitoring.EndpointType.NODE_EP
|
|
525
|
-
),
|
|
526
|
-
)
|
|
583
|
+
db = mlrun.get_run_db()
|
|
584
|
+
db.create_model_endpoint(
|
|
585
|
+
project=project,
|
|
586
|
+
endpoint_id=uid,
|
|
587
|
+
model_endpoint=model_endpoint.dict(),
|
|
588
|
+
)
|
|
527
589
|
|
|
590
|
+
elif model_ep:
|
|
591
|
+
attributes = {}
|
|
592
|
+
old_model_uri = model_ep.spec.model_uri
|
|
593
|
+
mlrun.model_monitoring.helpers.enrich_model_endpoint_with_model_uri(
|
|
594
|
+
model_endpoint=model_ep,
|
|
595
|
+
model_obj=model.model_spec,
|
|
596
|
+
)
|
|
597
|
+
if model_ep.spec.model_uri != old_model_uri:
|
|
598
|
+
attributes["model_uri"] = model_ep.spec.model_uri
|
|
599
|
+
if (
|
|
600
|
+
model_ep.spec.monitoring_mode
|
|
601
|
+
== mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled
|
|
602
|
+
) != model.context.server.track_models:
|
|
603
|
+
attributes["monitoring_mode"] = (
|
|
604
|
+
mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled
|
|
605
|
+
if model.context.server.track_models
|
|
606
|
+
else mlrun.common.schemas.model_monitoring.ModelMonitoringMode.disabled
|
|
607
|
+
)
|
|
608
|
+
if attributes:
|
|
528
609
|
db = mlrun.get_run_db()
|
|
529
|
-
|
|
530
|
-
db.create_model_endpoint(
|
|
610
|
+
db.patch_model_endpoint(
|
|
531
611
|
project=project,
|
|
532
612
|
endpoint_id=uid,
|
|
533
|
-
|
|
613
|
+
attributes=attributes,
|
|
614
|
+
)
|
|
615
|
+
logger.info(
|
|
616
|
+
"Updating model endpoint attributes",
|
|
617
|
+
attributes=attributes,
|
|
618
|
+
endpoint_id=uid,
|
|
534
619
|
)
|
|
535
|
-
|
|
536
|
-
except Exception as e:
|
|
537
|
-
logger.error("Failed to create endpoint record", exc=e)
|
|
538
|
-
|
|
539
|
-
except Exception as e:
|
|
540
|
-
logger.error("Failed to retrieve model endpoint object", exc=e)
|
|
541
620
|
|
|
542
621
|
return uid
|
mlrun/track/tracker.py
CHANGED
|
@@ -31,8 +31,9 @@ class Tracker(ABC):
|
|
|
31
31
|
* Offline: Manually importing models and artifacts into an MLRun project using the `import_x` methods.
|
|
32
32
|
"""
|
|
33
33
|
|
|
34
|
+
@staticmethod
|
|
34
35
|
@abstractmethod
|
|
35
|
-
def is_enabled(
|
|
36
|
+
def is_enabled() -> bool:
|
|
36
37
|
"""
|
|
37
38
|
Checks if tracker is enabled.
|
|
38
39
|
|
mlrun/track/tracker_manager.py
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import importlib
|
|
16
16
|
import inspect
|
|
17
|
-
from typing import
|
|
17
|
+
from typing import Union
|
|
18
18
|
|
|
19
19
|
import mlrun.errors
|
|
20
20
|
from mlrun.config import config as mlconf
|
|
@@ -28,7 +28,7 @@ _TRACKERS = ["mlflow"]
|
|
|
28
28
|
|
|
29
29
|
# A list for the available trackers during runtime. It will be setup at the beginning of the run by the function
|
|
30
30
|
# `_collect_available_trackers`:
|
|
31
|
-
_AVAILABLE_TRACKERS:
|
|
31
|
+
_AVAILABLE_TRACKERS: list[Tracker] = None
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
class TrackerManager(metaclass=Singleton):
|
|
@@ -41,7 +41,7 @@ class TrackerManager(metaclass=Singleton):
|
|
|
41
41
|
"""
|
|
42
42
|
Initialize a new empty tracker manager.
|
|
43
43
|
"""
|
|
44
|
-
self._trackers:
|
|
44
|
+
self._trackers: list[Tracker] = []
|
|
45
45
|
|
|
46
46
|
# Check general config for tracking usage, if false we return an empty manager
|
|
47
47
|
if mlconf.external_platform_tracking.enabled:
|
|
@@ -15,7 +15,6 @@ import os
|
|
|
15
15
|
import pathlib
|
|
16
16
|
import tempfile
|
|
17
17
|
import zipfile
|
|
18
|
-
from typing import List
|
|
19
18
|
|
|
20
19
|
import mlflow
|
|
21
20
|
import mlflow.entities
|
|
@@ -443,6 +442,11 @@ class MLFlowTracker(Tracker):
|
|
|
443
442
|
# Prepare the archive path:
|
|
444
443
|
model_uri = pathlib.Path(model_uri)
|
|
445
444
|
archive_path = pathlib.Path(tmp_path) / f"{model_uri.stem}.zip"
|
|
445
|
+
if not os.path.exists(model_uri):
|
|
446
|
+
local_path = mlflow.artifacts.download_artifacts(
|
|
447
|
+
artifact_uri=str(model_uri)
|
|
448
|
+
)
|
|
449
|
+
model_uri = pathlib.Path(local_path)
|
|
446
450
|
|
|
447
451
|
# TODO add progress bar for the case of large files
|
|
448
452
|
# Zip the artifact:
|
|
@@ -526,7 +530,7 @@ class MLFlowTracker(Tracker):
|
|
|
526
530
|
)
|
|
527
531
|
|
|
528
532
|
@staticmethod
|
|
529
|
-
def _schema_to_feature(schema: mlflow.types.Schema) ->
|
|
533
|
+
def _schema_to_feature(schema: mlflow.types.Schema) -> list[Feature]:
|
|
530
534
|
"""
|
|
531
535
|
Cast MLFlow schema to MLRun features.
|
|
532
536
|
|
mlrun/utils/async_http.py
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import asyncio
|
|
17
17
|
import logging
|
|
18
18
|
import typing
|
|
19
|
-
from typing import
|
|
19
|
+
from typing import Optional
|
|
20
20
|
|
|
21
21
|
import aiohttp
|
|
22
22
|
import aiohttp.http_exceptions
|
|
@@ -38,12 +38,10 @@ class AsyncClientWithRetry(RetryClient):
|
|
|
38
38
|
self,
|
|
39
39
|
max_retries: int = config.http_retry_defaults.max_retries,
|
|
40
40
|
retry_backoff_factor: float = config.http_retry_defaults.backoff_factor,
|
|
41
|
-
retry_on_status_codes:
|
|
42
|
-
int
|
|
43
|
-
] = config.http_retry_defaults.status_codes,
|
|
41
|
+
retry_on_status_codes: list[int] = config.http_retry_defaults.status_codes,
|
|
44
42
|
retry_on_exception: bool = True,
|
|
45
43
|
raise_for_status: bool = True,
|
|
46
|
-
blacklisted_methods: typing.Optional[
|
|
44
|
+
blacklisted_methods: typing.Optional[list[str]] = None,
|
|
47
45
|
logger: logging.Logger = None,
|
|
48
46
|
*args,
|
|
49
47
|
**kwargs,
|
|
@@ -82,7 +80,7 @@ class AsyncClientWithRetry(RetryClient):
|
|
|
82
80
|
|
|
83
81
|
def _make_requests(
|
|
84
82
|
self,
|
|
85
|
-
params_list:
|
|
83
|
+
params_list: list[RequestParams],
|
|
86
84
|
retry_options: Optional[RetryOptionsBase] = None,
|
|
87
85
|
raise_for_status: Optional[bool] = None,
|
|
88
86
|
) -> "_CustomRequestContext":
|
|
@@ -117,7 +115,7 @@ class ExponentialRetryOverride(ExponentialRetry):
|
|
|
117
115
|
def __init__(
|
|
118
116
|
self,
|
|
119
117
|
retry_on_exception: bool,
|
|
120
|
-
blacklisted_methods:
|
|
118
|
+
blacklisted_methods: list[str],
|
|
121
119
|
*args,
|
|
122
120
|
**kwargs,
|
|
123
121
|
):
|
|
@@ -239,7 +237,7 @@ class _CustomRequestContext(_RequestContext):
|
|
|
239
237
|
retry_wait = self._retry_options.get_timeout(
|
|
240
238
|
attempt=current_attempt, response=None
|
|
241
239
|
)
|
|
242
|
-
self._logger.
|
|
240
|
+
self._logger.warning(
|
|
243
241
|
"Request failed on retryable exception, retrying",
|
|
244
242
|
retry_wait_secs=retry_wait,
|
|
245
243
|
method=params.method,
|
mlrun/utils/azure_vault.py
CHANGED
|
@@ -63,7 +63,7 @@ class AzureVaultStore:
|
|
|
63
63
|
mlconf.secret_stores.azure_vault.secret_path + "/" + file_name
|
|
64
64
|
)
|
|
65
65
|
if os.path.isfile(full_path):
|
|
66
|
-
with open(full_path
|
|
66
|
+
with open(full_path) as secret_file:
|
|
67
67
|
contents = secret_file.read()
|
|
68
68
|
return contents
|
|
69
69
|
return None
|
mlrun/utils/clones.py
CHANGED
|
@@ -18,7 +18,6 @@ import tarfile
|
|
|
18
18
|
import tempfile
|
|
19
19
|
import zipfile
|
|
20
20
|
from os import path, remove
|
|
21
|
-
from typing import Tuple
|
|
22
21
|
from urllib.parse import urlparse
|
|
23
22
|
|
|
24
23
|
from git import Repo
|
|
@@ -91,7 +90,7 @@ def get_repo_url(repo):
|
|
|
91
90
|
return url
|
|
92
91
|
|
|
93
92
|
|
|
94
|
-
def add_credentials_git_remote_url(url: str, secrets=None) ->
|
|
93
|
+
def add_credentials_git_remote_url(url: str, secrets=None) -> tuple[str, bool]:
|
|
95
94
|
"""Enrich a Git remote URL with credential related secrets, if any are available
|
|
96
95
|
If no secrets are supplied, or if the secrets are insufficient, the original URL is returned
|
|
97
96
|
Besides the URL, this function also returns a bool indicating if any enrichment was done
|
|
@@ -19,7 +19,7 @@ from mlrun.utils import logger
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
def evaluate_condition_in_separate_process(
|
|
22
|
-
condition: str, context:
|
|
22
|
+
condition: str, context: dict[str, typing.Any], timeout: int = 5
|
|
23
23
|
):
|
|
24
24
|
if not condition:
|
|
25
25
|
return True
|
|
@@ -44,13 +44,13 @@ def evaluate_condition_in_separate_process(
|
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
def _evaluate_condition_wrapper(
|
|
47
|
-
connection, condition: str, context:
|
|
47
|
+
connection, condition: str, context: dict[str, typing.Any]
|
|
48
48
|
):
|
|
49
49
|
connection.send(_evaluate_condition(condition, context))
|
|
50
50
|
return connection.close()
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
def _evaluate_condition(condition: str, context:
|
|
53
|
+
def _evaluate_condition(condition: str, context: dict[str, typing.Any]):
|
|
54
54
|
import jinja2.sandbox
|
|
55
55
|
|
|
56
56
|
jinja_env = jinja2.sandbox.SandboxedEnvironment()
|
mlrun/utils/db.py
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
#
|
|
15
|
+
import abc
|
|
15
16
|
import pickle
|
|
16
17
|
from datetime import datetime
|
|
17
18
|
|
|
@@ -19,7 +20,7 @@ from sqlalchemy.orm import class_mapper
|
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
class BaseModel:
|
|
22
|
-
def to_dict(self, exclude=None):
|
|
23
|
+
def to_dict(self, exclude=None, strip: bool = False):
|
|
23
24
|
"""
|
|
24
25
|
NOTE - this function (currently) does not handle serializing relationships
|
|
25
26
|
"""
|
|
@@ -28,12 +29,22 @@ class BaseModel:
|
|
|
28
29
|
columns = [column.key for column in mapper.columns if column.key not in exclude]
|
|
29
30
|
|
|
30
31
|
def get_key_value(c):
|
|
32
|
+
# all (never say never) DB classes have "object" defined as "full_object"
|
|
33
|
+
if c == "object":
|
|
34
|
+
c = "full_object"
|
|
31
35
|
if isinstance(getattr(self, c), datetime):
|
|
32
36
|
return c, getattr(self, c).isoformat()
|
|
33
37
|
return c, getattr(self, c)
|
|
34
38
|
|
|
35
39
|
return dict(map(get_key_value, columns))
|
|
36
40
|
|
|
41
|
+
@abc.abstractmethod
|
|
42
|
+
def get_identifier_string(self):
|
|
43
|
+
"""
|
|
44
|
+
This method must be implemented by any subclass.
|
|
45
|
+
"""
|
|
46
|
+
pass
|
|
47
|
+
|
|
37
48
|
|
|
38
49
|
class HasStruct(BaseModel):
|
|
39
50
|
@property
|
|
@@ -44,10 +55,17 @@ class HasStruct(BaseModel):
|
|
|
44
55
|
def struct(self, value):
|
|
45
56
|
self.body = pickle.dumps(value)
|
|
46
57
|
|
|
47
|
-
def to_dict(self, exclude=None):
|
|
58
|
+
def to_dict(self, exclude=None, strip: bool = False):
|
|
48
59
|
"""
|
|
49
60
|
NOTE - this function (currently) does not handle serializing relationships
|
|
50
61
|
"""
|
|
51
62
|
exclude = exclude or []
|
|
52
63
|
exclude.append("body")
|
|
53
|
-
return super().to_dict(exclude)
|
|
64
|
+
return super().to_dict(exclude, strip=strip)
|
|
65
|
+
|
|
66
|
+
@abc.abstractmethod
|
|
67
|
+
def get_identifier_string(self):
|
|
68
|
+
"""
|
|
69
|
+
This method must be implemented by any subclass.
|
|
70
|
+
"""
|
|
71
|
+
pass
|