mlrun 1.7.0rc4__py3-none-any.whl → 1.7.0rc20__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mlrun might be problematic. Click here for more details.
- mlrun/__init__.py +11 -1
- mlrun/__main__.py +25 -111
- mlrun/{datastore/helpers.py → alerts/__init__.py} +2 -5
- mlrun/alerts/alert.py +144 -0
- mlrun/api/schemas/__init__.py +4 -3
- mlrun/artifacts/__init__.py +8 -3
- mlrun/artifacts/base.py +38 -254
- mlrun/artifacts/dataset.py +9 -190
- mlrun/artifacts/manager.py +41 -47
- mlrun/artifacts/model.py +30 -158
- mlrun/artifacts/plots.py +23 -380
- mlrun/common/constants.py +68 -0
- mlrun/common/formatters/__init__.py +19 -0
- mlrun/{model_monitoring/stores/models/sqlite.py → common/formatters/artifact.py} +6 -8
- mlrun/common/formatters/base.py +78 -0
- mlrun/common/formatters/function.py +41 -0
- mlrun/common/formatters/pipeline.py +53 -0
- mlrun/common/formatters/project.py +51 -0
- mlrun/{runtimes → common/runtimes}/constants.py +32 -4
- mlrun/common/schemas/__init__.py +25 -4
- mlrun/common/schemas/alert.py +203 -0
- mlrun/common/schemas/api_gateway.py +148 -0
- mlrun/common/schemas/artifact.py +15 -5
- mlrun/common/schemas/auth.py +8 -2
- mlrun/common/schemas/client_spec.py +2 -0
- mlrun/common/schemas/frontend_spec.py +1 -0
- mlrun/common/schemas/function.py +4 -0
- mlrun/common/schemas/hub.py +7 -9
- mlrun/common/schemas/model_monitoring/__init__.py +19 -3
- mlrun/common/schemas/model_monitoring/constants.py +96 -26
- mlrun/common/schemas/model_monitoring/grafana.py +9 -5
- mlrun/common/schemas/model_monitoring/model_endpoints.py +86 -2
- mlrun/{runtimes/mpijob/v1alpha1.py → common/schemas/pagination.py} +10 -13
- mlrun/common/schemas/pipeline.py +0 -9
- mlrun/common/schemas/project.py +22 -21
- mlrun/common/types.py +7 -1
- mlrun/config.py +87 -19
- mlrun/data_types/data_types.py +4 -0
- mlrun/data_types/to_pandas.py +9 -9
- mlrun/datastore/__init__.py +5 -8
- mlrun/datastore/alibaba_oss.py +130 -0
- mlrun/datastore/azure_blob.py +4 -5
- mlrun/datastore/base.py +69 -30
- mlrun/datastore/datastore.py +10 -2
- mlrun/datastore/datastore_profile.py +90 -6
- mlrun/datastore/google_cloud_storage.py +1 -1
- mlrun/datastore/hdfs.py +5 -0
- mlrun/datastore/inmem.py +2 -2
- mlrun/datastore/redis.py +2 -2
- mlrun/datastore/s3.py +5 -0
- mlrun/datastore/snowflake_utils.py +43 -0
- mlrun/datastore/sources.py +172 -44
- mlrun/datastore/store_resources.py +7 -7
- mlrun/datastore/targets.py +285 -41
- mlrun/datastore/utils.py +68 -5
- mlrun/datastore/v3io.py +27 -50
- mlrun/db/auth_utils.py +152 -0
- mlrun/db/base.py +149 -14
- mlrun/db/factory.py +1 -1
- mlrun/db/httpdb.py +608 -178
- mlrun/db/nopdb.py +191 -7
- mlrun/errors.py +11 -0
- mlrun/execution.py +37 -20
- mlrun/feature_store/__init__.py +0 -2
- mlrun/feature_store/api.py +21 -52
- mlrun/feature_store/feature_set.py +48 -23
- mlrun/feature_store/feature_vector.py +2 -1
- mlrun/feature_store/ingestion.py +7 -6
- mlrun/feature_store/retrieval/base.py +9 -4
- mlrun/feature_store/retrieval/conversion.py +9 -9
- mlrun/feature_store/retrieval/dask_merger.py +2 -0
- mlrun/feature_store/retrieval/job.py +9 -3
- mlrun/feature_store/retrieval/local_merger.py +2 -0
- mlrun/feature_store/retrieval/spark_merger.py +34 -24
- mlrun/feature_store/steps.py +30 -19
- mlrun/features.py +4 -13
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +7 -12
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +2 -2
- mlrun/frameworks/lgbm/__init__.py +1 -1
- mlrun/frameworks/lgbm/callbacks/callback.py +2 -4
- mlrun/frameworks/lgbm/model_handler.py +1 -1
- mlrun/frameworks/parallel_coordinates.py +2 -1
- mlrun/frameworks/pytorch/__init__.py +2 -2
- mlrun/frameworks/sklearn/__init__.py +1 -1
- mlrun/frameworks/tf_keras/__init__.py +5 -2
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +1 -1
- mlrun/frameworks/tf_keras/mlrun_interface.py +2 -2
- mlrun/frameworks/xgboost/__init__.py +1 -1
- mlrun/k8s_utils.py +10 -11
- mlrun/launcher/__init__.py +1 -1
- mlrun/launcher/base.py +6 -5
- mlrun/launcher/client.py +8 -6
- mlrun/launcher/factory.py +1 -1
- mlrun/launcher/local.py +9 -3
- mlrun/launcher/remote.py +9 -3
- mlrun/lists.py +6 -2
- mlrun/model.py +58 -19
- mlrun/model_monitoring/__init__.py +1 -1
- mlrun/model_monitoring/api.py +127 -301
- mlrun/model_monitoring/application.py +5 -296
- mlrun/model_monitoring/applications/__init__.py +11 -0
- mlrun/model_monitoring/applications/_application_steps.py +157 -0
- mlrun/model_monitoring/applications/base.py +282 -0
- mlrun/model_monitoring/applications/context.py +214 -0
- mlrun/model_monitoring/applications/evidently_base.py +211 -0
- mlrun/model_monitoring/applications/histogram_data_drift.py +224 -93
- mlrun/model_monitoring/applications/results.py +99 -0
- mlrun/model_monitoring/controller.py +30 -36
- mlrun/model_monitoring/db/__init__.py +18 -0
- mlrun/model_monitoring/{stores → db/stores}/__init__.py +43 -36
- mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
- mlrun/model_monitoring/{stores/model_endpoint_store.py → db/stores/base/store.py} +58 -32
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
- mlrun/model_monitoring/{stores → db/stores/sqldb}/models/base.py +109 -5
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +88 -0
- mlrun/model_monitoring/{stores/models/mysql.py → db/stores/sqldb/models/sqlite.py} +19 -13
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +684 -0
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
- mlrun/model_monitoring/{stores/kv_model_endpoint_store.py → db/stores/v3io_kv/kv_store.py} +302 -155
- mlrun/model_monitoring/db/tsdb/__init__.py +100 -0
- mlrun/model_monitoring/db/tsdb/base.py +329 -0
- mlrun/model_monitoring/db/tsdb/helpers.py +30 -0
- mlrun/model_monitoring/db/tsdb/tdengine/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +240 -0
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +45 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +397 -0
- mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +117 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +630 -0
- mlrun/model_monitoring/evidently_application.py +6 -118
- mlrun/model_monitoring/features_drift_table.py +34 -22
- mlrun/model_monitoring/helpers.py +100 -7
- mlrun/model_monitoring/model_endpoint.py +3 -2
- mlrun/model_monitoring/stream_processing.py +93 -228
- mlrun/model_monitoring/tracking_policy.py +7 -1
- mlrun/model_monitoring/writer.py +152 -124
- mlrun/package/packagers_manager.py +1 -0
- mlrun/package/utils/_formatter.py +2 -2
- mlrun/platforms/__init__.py +11 -10
- mlrun/platforms/iguazio.py +21 -202
- mlrun/projects/operations.py +30 -16
- mlrun/projects/pipelines.py +92 -99
- mlrun/projects/project.py +757 -268
- mlrun/render.py +15 -14
- mlrun/run.py +160 -162
- mlrun/runtimes/__init__.py +55 -3
- mlrun/runtimes/base.py +33 -19
- mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
- mlrun/runtimes/funcdoc.py +0 -28
- mlrun/runtimes/kubejob.py +28 -122
- mlrun/runtimes/local.py +5 -2
- mlrun/runtimes/mpijob/__init__.py +0 -20
- mlrun/runtimes/mpijob/abstract.py +8 -8
- mlrun/runtimes/mpijob/v1.py +1 -1
- mlrun/runtimes/nuclio/__init__.py +1 -0
- mlrun/runtimes/nuclio/api_gateway.py +709 -0
- mlrun/runtimes/nuclio/application/__init__.py +15 -0
- mlrun/runtimes/nuclio/application/application.py +523 -0
- mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
- mlrun/runtimes/nuclio/function.py +98 -58
- mlrun/runtimes/nuclio/serving.py +36 -42
- mlrun/runtimes/pod.py +196 -45
- mlrun/runtimes/remotesparkjob.py +1 -1
- mlrun/runtimes/sparkjob/spark3job.py +1 -1
- mlrun/runtimes/utils.py +6 -73
- mlrun/secrets.py +6 -2
- mlrun/serving/remote.py +2 -3
- mlrun/serving/routers.py +7 -4
- mlrun/serving/server.py +7 -8
- mlrun/serving/states.py +73 -43
- mlrun/serving/v2_serving.py +8 -7
- mlrun/track/tracker.py +2 -1
- mlrun/utils/async_http.py +25 -5
- mlrun/utils/helpers.py +141 -75
- mlrun/utils/http.py +1 -1
- mlrun/utils/logger.py +39 -7
- mlrun/utils/notifications/notification/__init__.py +14 -9
- mlrun/utils/notifications/notification/base.py +12 -0
- mlrun/utils/notifications/notification/console.py +2 -0
- mlrun/utils/notifications/notification/git.py +3 -1
- mlrun/utils/notifications/notification/ipython.py +2 -0
- mlrun/utils/notifications/notification/slack.py +101 -21
- mlrun/utils/notifications/notification/webhook.py +11 -1
- mlrun/utils/notifications/notification_pusher.py +147 -16
- mlrun/utils/retryer.py +3 -2
- mlrun/utils/v3io_clients.py +0 -1
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/METADATA +33 -18
- mlrun-1.7.0rc20.dist-info/RECORD +353 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/WHEEL +1 -1
- mlrun/kfpops.py +0 -868
- mlrun/model_monitoring/batch.py +0 -974
- mlrun/model_monitoring/stores/models/__init__.py +0 -27
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -382
- mlrun/platforms/other.py +0 -305
- mlrun-1.7.0rc4.dist-info/RECORD +0 -321
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/top_level.txt +0 -0
mlrun/artifacts/manager.py
CHANGED
|
@@ -16,6 +16,7 @@ import typing
|
|
|
16
16
|
from os.path import exists, isdir
|
|
17
17
|
from urllib.parse import urlparse
|
|
18
18
|
|
|
19
|
+
import mlrun.common.schemas.artifact
|
|
19
20
|
import mlrun.config
|
|
20
21
|
from mlrun.utils.helpers import (
|
|
21
22
|
get_local_file_schema,
|
|
@@ -24,7 +25,6 @@ from mlrun.utils.helpers import (
|
|
|
24
25
|
)
|
|
25
26
|
|
|
26
27
|
from ..utils import (
|
|
27
|
-
is_legacy_artifact,
|
|
28
28
|
is_relative_path,
|
|
29
29
|
logger,
|
|
30
30
|
validate_artifact_key_name,
|
|
@@ -33,56 +33,28 @@ from ..utils import (
|
|
|
33
33
|
from .base import (
|
|
34
34
|
Artifact,
|
|
35
35
|
DirArtifact,
|
|
36
|
-
LegacyArtifact,
|
|
37
|
-
LegacyDirArtifact,
|
|
38
|
-
LegacyLinkArtifact,
|
|
39
36
|
LinkArtifact,
|
|
40
37
|
)
|
|
41
38
|
from .dataset import (
|
|
42
39
|
DatasetArtifact,
|
|
43
|
-
LegacyDatasetArtifact,
|
|
44
|
-
LegacyTableArtifact,
|
|
45
40
|
TableArtifact,
|
|
46
41
|
)
|
|
47
|
-
from .model import
|
|
42
|
+
from .model import ModelArtifact
|
|
48
43
|
from .plots import (
|
|
49
|
-
BokehArtifact,
|
|
50
|
-
ChartArtifact,
|
|
51
|
-
LegacyBokehArtifact,
|
|
52
|
-
LegacyChartArtifact,
|
|
53
|
-
LegacyPlotArtifact,
|
|
54
|
-
LegacyPlotlyArtifact,
|
|
55
44
|
PlotArtifact,
|
|
56
45
|
PlotlyArtifact,
|
|
57
46
|
)
|
|
58
47
|
|
|
59
|
-
# TODO - Remove deprecated types when deleted in 1.7.0
|
|
60
48
|
artifact_types = {
|
|
61
49
|
"": Artifact,
|
|
62
50
|
"artifact": Artifact,
|
|
63
51
|
"dir": DirArtifact,
|
|
64
52
|
"link": LinkArtifact,
|
|
65
53
|
"plot": PlotArtifact,
|
|
66
|
-
"chart": ChartArtifact,
|
|
67
54
|
"table": TableArtifact,
|
|
68
55
|
"model": ModelArtifact,
|
|
69
56
|
"dataset": DatasetArtifact,
|
|
70
57
|
"plotly": PlotlyArtifact,
|
|
71
|
-
"bokeh": BokehArtifact,
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
# TODO - Remove this when legacy types are deleted in 1.7.0
|
|
75
|
-
legacy_artifact_types = {
|
|
76
|
-
"": LegacyArtifact,
|
|
77
|
-
"dir": LegacyDirArtifact,
|
|
78
|
-
"link": LegacyLinkArtifact,
|
|
79
|
-
"plot": LegacyPlotArtifact,
|
|
80
|
-
"chart": LegacyChartArtifact,
|
|
81
|
-
"table": LegacyTableArtifact,
|
|
82
|
-
"model": LegacyModelArtifact,
|
|
83
|
-
"dataset": LegacyDatasetArtifact,
|
|
84
|
-
"plotly": LegacyPlotlyArtifact,
|
|
85
|
-
"bokeh": LegacyBokehArtifact,
|
|
86
58
|
}
|
|
87
59
|
|
|
88
60
|
|
|
@@ -100,17 +72,14 @@ class ArtifactProducer:
|
|
|
100
72
|
def get_meta(self) -> dict:
|
|
101
73
|
return {"kind": self.kind, "name": self.name, "tag": self.tag}
|
|
102
74
|
|
|
75
|
+
@property
|
|
76
|
+
def uid(self):
|
|
77
|
+
return None
|
|
78
|
+
|
|
103
79
|
|
|
104
80
|
def dict_to_artifact(struct: dict) -> Artifact:
|
|
105
|
-
# Need to distinguish between LegacyArtifact classes and Artifact classes. Use existence of the "metadata"
|
|
106
|
-
# property to make this distinction
|
|
107
81
|
kind = struct.get("kind", "")
|
|
108
|
-
|
|
109
|
-
if is_legacy_artifact(struct):
|
|
110
|
-
return mlrun.artifacts.base.convert_legacy_artifact_to_new_format(struct)
|
|
111
|
-
|
|
112
82
|
artifact_class = artifact_types[kind]
|
|
113
|
-
|
|
114
83
|
return artifact_class.from_dict(struct)
|
|
115
84
|
|
|
116
85
|
|
|
@@ -180,11 +149,13 @@ class ArtifactManager:
|
|
|
180
149
|
upload=None,
|
|
181
150
|
labels=None,
|
|
182
151
|
db_key=None,
|
|
152
|
+
project=None,
|
|
153
|
+
is_retained_producer=None,
|
|
183
154
|
**kwargs,
|
|
184
155
|
) -> Artifact:
|
|
185
156
|
"""
|
|
186
157
|
Log an artifact to the DB and upload it to the artifact store.
|
|
187
|
-
:param producer: The producer of the artifact, the producer depends
|
|
158
|
+
:param producer: The producer of the artifact, the producer depends on where the artifact is being logged.
|
|
188
159
|
:param item: The artifact to log.
|
|
189
160
|
:param body: The body of the artifact.
|
|
190
161
|
:param target_path: The target path of the artifact. (cannot be a relative path)
|
|
@@ -202,6 +173,9 @@ class ArtifactManager:
|
|
|
202
173
|
:param labels: Labels to add to the artifact.
|
|
203
174
|
:param db_key: The key to use when logging the artifact to the DB.
|
|
204
175
|
If not provided, will generate a key based on the producer name and the artifact key.
|
|
176
|
+
:param project: The project to log the artifact to. If not provided, will use the producer's project.
|
|
177
|
+
:param is_retained_producer: Whether the producer is retained or not. Relevant to register artifacts flow
|
|
178
|
+
where a project may log artifacts which were produced by another producer.
|
|
205
179
|
:param kwargs: Arguments to pass to the artifact class.
|
|
206
180
|
:return: The logged artifact.
|
|
207
181
|
"""
|
|
@@ -226,7 +200,7 @@ class ArtifactManager:
|
|
|
226
200
|
|
|
227
201
|
if db_key is None:
|
|
228
202
|
# set the default artifact db key
|
|
229
|
-
if producer.kind == "run":
|
|
203
|
+
if producer.kind == "run" and not is_retained_producer:
|
|
230
204
|
# When the producer's type is "run,"
|
|
231
205
|
# we generate a different db_key than the one we obtained in the request.
|
|
232
206
|
# As a result, a new artifact for the requested key will be created,
|
|
@@ -251,8 +225,11 @@ class ArtifactManager:
|
|
|
251
225
|
item.labels.update({"workflow-id": item.producer.get("workflow")})
|
|
252
226
|
|
|
253
227
|
item.iter = producer.iteration
|
|
254
|
-
project = producer.project
|
|
228
|
+
project = project or producer.project
|
|
255
229
|
item.project = project
|
|
230
|
+
if is_retained_producer:
|
|
231
|
+
# if the producer is retained, we want to use the original target path
|
|
232
|
+
target_path = target_path or item.target_path
|
|
256
233
|
|
|
257
234
|
# if target_path is provided and not relative, then no need to upload the artifact as it already exists
|
|
258
235
|
if target_path:
|
|
@@ -260,7 +237,8 @@ class ArtifactManager:
|
|
|
260
237
|
raise ValueError(
|
|
261
238
|
f"target_path ({target_path}) param cannot be relative"
|
|
262
239
|
)
|
|
263
|
-
upload
|
|
240
|
+
if upload is None:
|
|
241
|
+
upload = False
|
|
264
242
|
|
|
265
243
|
# if target_path wasn't provided, but src_path is not relative, then no need to upload the artifact as it
|
|
266
244
|
# already exists. In this case set the target_path to the src_path and set upload to False
|
|
@@ -287,7 +265,9 @@ class ArtifactManager:
|
|
|
287
265
|
|
|
288
266
|
if target_path and item.is_dir and not target_path.endswith("/"):
|
|
289
267
|
target_path += "/"
|
|
290
|
-
target_path = template_artifact_path(
|
|
268
|
+
target_path = template_artifact_path(
|
|
269
|
+
artifact_path=target_path, project=producer.project, run_uid=producer.uid
|
|
270
|
+
)
|
|
291
271
|
item.target_path = target_path
|
|
292
272
|
|
|
293
273
|
item.before_log()
|
|
@@ -297,13 +277,10 @@ class ArtifactManager:
|
|
|
297
277
|
# before uploading the item, we want to ensure that its tags are valid,
|
|
298
278
|
# so that we don't upload something that won't be stored later
|
|
299
279
|
validate_tag_name(item.metadata.tag, "artifact.metadata.tag")
|
|
300
|
-
|
|
301
|
-
item.upload()
|
|
302
|
-
else:
|
|
303
|
-
item.upload(artifact_path=artifact_path)
|
|
280
|
+
item.upload(artifact_path=artifact_path)
|
|
304
281
|
|
|
305
282
|
if db_key:
|
|
306
|
-
self._log_to_db(db_key,
|
|
283
|
+
self._log_to_db(db_key, project, producer.inputs, item)
|
|
307
284
|
size = str(item.size) or "?"
|
|
308
285
|
db_str = "Y" if (self.artifact_db and db_key) else "N"
|
|
309
286
|
logger.debug(
|
|
@@ -371,6 +348,23 @@ class ArtifactManager:
|
|
|
371
348
|
project=project,
|
|
372
349
|
)
|
|
373
350
|
|
|
351
|
+
def delete_artifact(
|
|
352
|
+
self,
|
|
353
|
+
item: Artifact,
|
|
354
|
+
deletion_strategy: mlrun.common.schemas.artifact.ArtifactsDeletionStrategies = (
|
|
355
|
+
mlrun.common.schemas.artifact.ArtifactsDeletionStrategies.metadata_only
|
|
356
|
+
),
|
|
357
|
+
secrets: dict = None,
|
|
358
|
+
):
|
|
359
|
+
self.artifact_db.del_artifact(
|
|
360
|
+
key=item.db_key,
|
|
361
|
+
project=item.project,
|
|
362
|
+
tag=item.tag,
|
|
363
|
+
tree=item.tree,
|
|
364
|
+
deletion_strategy=deletion_strategy,
|
|
365
|
+
secrets=secrets,
|
|
366
|
+
)
|
|
367
|
+
|
|
374
368
|
|
|
375
369
|
def extend_artifact_path(artifact_path: str, default_artifact_path: str):
|
|
376
370
|
artifact_path = str(artifact_path or "")
|
mlrun/artifacts/model.py
CHANGED
|
@@ -11,13 +11,14 @@
|
|
|
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
|
+
|
|
14
15
|
import tempfile
|
|
16
|
+
import warnings
|
|
15
17
|
from os import path
|
|
16
|
-
from typing import Any
|
|
18
|
+
from typing import Any, Optional
|
|
17
19
|
|
|
18
20
|
import pandas as pd
|
|
19
21
|
import yaml
|
|
20
|
-
from deprecated import deprecated
|
|
21
22
|
|
|
22
23
|
import mlrun
|
|
23
24
|
import mlrun.datastore
|
|
@@ -26,7 +27,7 @@ from ..data_types import InferOptions, get_infer_interface
|
|
|
26
27
|
from ..features import Feature
|
|
27
28
|
from ..model import ObjectList
|
|
28
29
|
from ..utils import StorePrefix, is_relative_path
|
|
29
|
-
from .base import Artifact, ArtifactSpec,
|
|
30
|
+
from .base import Artifact, ArtifactSpec, upload_extra_data
|
|
30
31
|
|
|
31
32
|
model_spec_filename = "model_spec.yaml"
|
|
32
33
|
|
|
@@ -69,8 +70,8 @@ class ModelArtifactSpec(ArtifactSpec):
|
|
|
69
70
|
model_file=None,
|
|
70
71
|
metrics=None,
|
|
71
72
|
paraemeters=None,
|
|
72
|
-
inputs: list[Feature] = None,
|
|
73
|
-
outputs: list[Feature] = None,
|
|
73
|
+
inputs: Optional[list[Feature]] = None,
|
|
74
|
+
outputs: Optional[list[Feature]] = None,
|
|
74
75
|
framework=None,
|
|
75
76
|
algorithm=None,
|
|
76
77
|
feature_vector=None,
|
|
@@ -92,8 +93,8 @@ class ModelArtifactSpec(ArtifactSpec):
|
|
|
92
93
|
self.model_file = model_file
|
|
93
94
|
self.metrics = metrics or {}
|
|
94
95
|
self.parameters = paraemeters or {}
|
|
95
|
-
self.inputs
|
|
96
|
-
self.outputs
|
|
96
|
+
self.inputs = inputs or []
|
|
97
|
+
self.outputs = outputs or []
|
|
97
98
|
self.framework = framework
|
|
98
99
|
self.algorithm = algorithm
|
|
99
100
|
self.feature_vector = feature_vector
|
|
@@ -102,21 +103,21 @@ class ModelArtifactSpec(ArtifactSpec):
|
|
|
102
103
|
self.model_target_file = model_target_file
|
|
103
104
|
|
|
104
105
|
@property
|
|
105
|
-
def inputs(self) ->
|
|
106
|
+
def inputs(self) -> ObjectList:
|
|
106
107
|
"""input feature list"""
|
|
107
108
|
return self._inputs
|
|
108
109
|
|
|
109
110
|
@inputs.setter
|
|
110
|
-
def inputs(self, inputs: list[Feature]):
|
|
111
|
+
def inputs(self, inputs: list[Feature]) -> None:
|
|
111
112
|
self._inputs = ObjectList.from_list(Feature, inputs)
|
|
112
113
|
|
|
113
114
|
@property
|
|
114
|
-
def outputs(self) ->
|
|
115
|
+
def outputs(self) -> ObjectList:
|
|
115
116
|
"""output feature list"""
|
|
116
117
|
return self._outputs
|
|
117
118
|
|
|
118
119
|
@outputs.setter
|
|
119
|
-
def outputs(self, outputs: list[Feature]):
|
|
120
|
+
def outputs(self, outputs: list[Feature]) -> None:
|
|
120
121
|
self._outputs = ObjectList.from_list(Feature, outputs)
|
|
121
122
|
|
|
122
123
|
|
|
@@ -148,6 +149,12 @@ class ModelArtifact(Artifact):
|
|
|
148
149
|
model_dir=None,
|
|
149
150
|
**kwargs,
|
|
150
151
|
):
|
|
152
|
+
if key or body or format or target_path:
|
|
153
|
+
warnings.warn(
|
|
154
|
+
"Artifact constructor parameters are deprecated and will be removed in 1.9.0. "
|
|
155
|
+
"Use the metadata and spec parameters instead.",
|
|
156
|
+
DeprecationWarning,
|
|
157
|
+
)
|
|
151
158
|
super().__init__(key, body, format=format, target_path=target_path, **kwargs)
|
|
152
159
|
model_file = str(model_file or "")
|
|
153
160
|
if model_file and "/" in model_file:
|
|
@@ -176,22 +183,22 @@ class ModelArtifact(Artifact):
|
|
|
176
183
|
self._spec = self._verify_dict(spec, "spec", ModelArtifactSpec)
|
|
177
184
|
|
|
178
185
|
@property
|
|
179
|
-
def inputs(self) ->
|
|
186
|
+
def inputs(self) -> ObjectList:
|
|
180
187
|
"""input feature list"""
|
|
181
188
|
return self.spec.inputs
|
|
182
189
|
|
|
183
190
|
@inputs.setter
|
|
184
|
-
def inputs(self, inputs: list[Feature]):
|
|
191
|
+
def inputs(self, inputs: list[Feature]) -> None:
|
|
185
192
|
"""input feature list"""
|
|
186
193
|
self.spec.inputs = inputs
|
|
187
194
|
|
|
188
195
|
@property
|
|
189
|
-
def outputs(self) ->
|
|
196
|
+
def outputs(self) -> ObjectList:
|
|
190
197
|
"""input feature list"""
|
|
191
198
|
return self.spec.outputs
|
|
192
199
|
|
|
193
200
|
@outputs.setter
|
|
194
|
-
def outputs(self, outputs: list[Feature]):
|
|
201
|
+
def outputs(self, outputs: list[Feature]) -> None:
|
|
195
202
|
"""input feature list"""
|
|
196
203
|
self.spec.outputs = outputs
|
|
197
204
|
|
|
@@ -396,144 +403,6 @@ class ModelArtifact(Artifact):
|
|
|
396
403
|
return mlrun.get_dataitem(target_model_path).get()
|
|
397
404
|
|
|
398
405
|
|
|
399
|
-
# TODO: remove in 1.7.0
|
|
400
|
-
@deprecated(
|
|
401
|
-
version="1.3.0",
|
|
402
|
-
reason="'LegacyModelArtifact' will be removed in 1.7.0, use 'ModelArtifact' instead",
|
|
403
|
-
category=FutureWarning,
|
|
404
|
-
)
|
|
405
|
-
class LegacyModelArtifact(LegacyArtifact):
|
|
406
|
-
"""ML Model artifact
|
|
407
|
-
|
|
408
|
-
Store link to ML model file(s) along with the model metrics, parameters, schema, and stats
|
|
409
|
-
"""
|
|
410
|
-
|
|
411
|
-
_dict_fields = LegacyArtifact._dict_fields + [
|
|
412
|
-
"model_file",
|
|
413
|
-
"metrics",
|
|
414
|
-
"parameters",
|
|
415
|
-
"inputs",
|
|
416
|
-
"outputs",
|
|
417
|
-
"framework",
|
|
418
|
-
"algorithm",
|
|
419
|
-
"extra_data",
|
|
420
|
-
"feature_vector",
|
|
421
|
-
"feature_weights",
|
|
422
|
-
"feature_stats",
|
|
423
|
-
"model_target_file",
|
|
424
|
-
]
|
|
425
|
-
kind = "model"
|
|
426
|
-
_store_prefix = StorePrefix.Model
|
|
427
|
-
|
|
428
|
-
def __init__(
|
|
429
|
-
self,
|
|
430
|
-
key=None,
|
|
431
|
-
body=None,
|
|
432
|
-
format=None,
|
|
433
|
-
model_file=None,
|
|
434
|
-
metrics=None,
|
|
435
|
-
target_path=None,
|
|
436
|
-
parameters=None,
|
|
437
|
-
inputs=None,
|
|
438
|
-
outputs=None,
|
|
439
|
-
framework=None,
|
|
440
|
-
algorithm=None,
|
|
441
|
-
feature_vector=None,
|
|
442
|
-
feature_weights=None,
|
|
443
|
-
extra_data=None,
|
|
444
|
-
model_target_file=None,
|
|
445
|
-
**kwargs,
|
|
446
|
-
):
|
|
447
|
-
super().__init__(key, body, format=format, target_path=target_path, **kwargs)
|
|
448
|
-
self._inputs: ObjectList = None
|
|
449
|
-
self._outputs: ObjectList = None
|
|
450
|
-
|
|
451
|
-
self.model_file = model_file
|
|
452
|
-
self.parameters = parameters or {}
|
|
453
|
-
self.metrics = metrics or {}
|
|
454
|
-
self.inputs: list[Feature] = inputs or []
|
|
455
|
-
self.outputs: list[Feature] = outputs or []
|
|
456
|
-
self.extra_data = extra_data or {}
|
|
457
|
-
self.framework = framework
|
|
458
|
-
self.algorithm = algorithm
|
|
459
|
-
self.feature_vector = feature_vector
|
|
460
|
-
self.feature_weights = feature_weights
|
|
461
|
-
self.feature_stats = None
|
|
462
|
-
self.model_target_file = model_target_file
|
|
463
|
-
|
|
464
|
-
@property
|
|
465
|
-
def inputs(self) -> list[Feature]:
|
|
466
|
-
"""input feature list"""
|
|
467
|
-
return self._inputs
|
|
468
|
-
|
|
469
|
-
@inputs.setter
|
|
470
|
-
def inputs(self, inputs: list[Feature]):
|
|
471
|
-
self._inputs = ObjectList.from_list(Feature, inputs)
|
|
472
|
-
|
|
473
|
-
@property
|
|
474
|
-
def outputs(self) -> list[Feature]:
|
|
475
|
-
"""output feature list"""
|
|
476
|
-
return self._outputs
|
|
477
|
-
|
|
478
|
-
@outputs.setter
|
|
479
|
-
def outputs(self, outputs: list[Feature]):
|
|
480
|
-
self._outputs = ObjectList.from_list(Feature, outputs)
|
|
481
|
-
|
|
482
|
-
def infer_from_df(self, df, label_columns=None, with_stats=True, num_bins=None):
|
|
483
|
-
"""infer inputs, outputs, and stats from provided df (training set)
|
|
484
|
-
|
|
485
|
-
:param df: dataframe to infer from
|
|
486
|
-
:param label_columns: name of the label (target) column
|
|
487
|
-
:param with_stats: infer statistics (min, max, .. histogram)
|
|
488
|
-
:param num_bins: number of bins for histogram
|
|
489
|
-
"""
|
|
490
|
-
subset = df
|
|
491
|
-
inferer = get_infer_interface(subset)
|
|
492
|
-
if label_columns:
|
|
493
|
-
if not isinstance(label_columns, list):
|
|
494
|
-
label_columns = [label_columns]
|
|
495
|
-
subset = df.drop(columns=label_columns)
|
|
496
|
-
inferer.infer_schema(subset, self.inputs, {}, options=InferOptions.Features)
|
|
497
|
-
if label_columns:
|
|
498
|
-
inferer.infer_schema(
|
|
499
|
-
df[label_columns], self.outputs, {}, options=InferOptions.Features
|
|
500
|
-
)
|
|
501
|
-
if with_stats:
|
|
502
|
-
self.feature_stats = inferer.get_stats(
|
|
503
|
-
df, options=InferOptions.Histogram, num_bins=num_bins
|
|
504
|
-
)
|
|
505
|
-
|
|
506
|
-
@property
|
|
507
|
-
def is_dir(self):
|
|
508
|
-
return True
|
|
509
|
-
|
|
510
|
-
def before_log(self):
|
|
511
|
-
if not self.model_file:
|
|
512
|
-
raise ValueError("model_file attr must be specified")
|
|
513
|
-
|
|
514
|
-
super().before_log()
|
|
515
|
-
|
|
516
|
-
if self.framework:
|
|
517
|
-
self.labels = self.labels or {}
|
|
518
|
-
self.labels["framework"] = self.framework
|
|
519
|
-
|
|
520
|
-
def upload(self):
|
|
521
|
-
target_model_path = path.join(self.target_path, self.model_file)
|
|
522
|
-
body = self.get_body()
|
|
523
|
-
if body:
|
|
524
|
-
self._upload_body(body, target=target_model_path)
|
|
525
|
-
else:
|
|
526
|
-
src_model_path = _get_src_path(self, self.model_file)
|
|
527
|
-
if not path.isfile(src_model_path):
|
|
528
|
-
raise ValueError(f"model file {src_model_path} not found")
|
|
529
|
-
self._upload_file(src_model_path, target=target_model_path)
|
|
530
|
-
|
|
531
|
-
upload_extra_data(self, self.extra_data)
|
|
532
|
-
|
|
533
|
-
spec_path = path.join(self.target_path, model_spec_filename)
|
|
534
|
-
mlrun.datastore.store_manager.object(url=spec_path).put(self.to_yaml())
|
|
535
|
-
|
|
536
|
-
|
|
537
406
|
def _get_src_path(model_spec: ModelArtifact, filename):
|
|
538
407
|
if model_spec.src_path:
|
|
539
408
|
return path.join(model_spec.src_path, filename)
|
|
@@ -552,9 +421,9 @@ def get_model(model_dir, suffix=""):
|
|
|
552
421
|
|
|
553
422
|
example::
|
|
554
423
|
|
|
555
|
-
model_file, model_artifact, extra_data = get_model(models_path, suffix=
|
|
424
|
+
model_file, model_artifact, extra_data = get_model(models_path, suffix=".pkl")
|
|
556
425
|
model = load(open(model_file, "rb"))
|
|
557
|
-
categories = extra_data[
|
|
426
|
+
categories = extra_data["categories"].as_df()
|
|
558
427
|
|
|
559
428
|
:param model_dir: model dir or artifact path (store://..) or DataItem
|
|
560
429
|
:param suffix: model filename suffix (when using a dir)
|
|
@@ -640,7 +509,7 @@ def _get_extra(target, extra_data, is_dir=False):
|
|
|
640
509
|
def _remove_tag_from_spec_yaml(model_spec):
|
|
641
510
|
spec_dict = model_spec.to_dict()
|
|
642
511
|
spec_dict["metadata"].pop("tag", None)
|
|
643
|
-
return yaml.
|
|
512
|
+
return yaml.safe_dump(spec_dict)
|
|
644
513
|
|
|
645
514
|
|
|
646
515
|
def update_model(
|
|
@@ -663,8 +532,11 @@ def update_model(
|
|
|
663
532
|
|
|
664
533
|
example::
|
|
665
534
|
|
|
666
|
-
update_model(
|
|
667
|
-
|
|
535
|
+
update_model(
|
|
536
|
+
model_path,
|
|
537
|
+
metrics={"speed": 100},
|
|
538
|
+
extra_data={"my_data": b"some text", "file": "s3://mybucket/.."},
|
|
539
|
+
)
|
|
668
540
|
|
|
669
541
|
:param model_artifact: model artifact object or path (store://..) or DataItem
|
|
670
542
|
:param parameters: parameters dict
|