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.

Files changed (200) hide show
  1. mlrun/__init__.py +11 -1
  2. mlrun/__main__.py +25 -111
  3. mlrun/{datastore/helpers.py → alerts/__init__.py} +2 -5
  4. mlrun/alerts/alert.py +144 -0
  5. mlrun/api/schemas/__init__.py +4 -3
  6. mlrun/artifacts/__init__.py +8 -3
  7. mlrun/artifacts/base.py +38 -254
  8. mlrun/artifacts/dataset.py +9 -190
  9. mlrun/artifacts/manager.py +41 -47
  10. mlrun/artifacts/model.py +30 -158
  11. mlrun/artifacts/plots.py +23 -380
  12. mlrun/common/constants.py +68 -0
  13. mlrun/common/formatters/__init__.py +19 -0
  14. mlrun/{model_monitoring/stores/models/sqlite.py → common/formatters/artifact.py} +6 -8
  15. mlrun/common/formatters/base.py +78 -0
  16. mlrun/common/formatters/function.py +41 -0
  17. mlrun/common/formatters/pipeline.py +53 -0
  18. mlrun/common/formatters/project.py +51 -0
  19. mlrun/{runtimes → common/runtimes}/constants.py +32 -4
  20. mlrun/common/schemas/__init__.py +25 -4
  21. mlrun/common/schemas/alert.py +203 -0
  22. mlrun/common/schemas/api_gateway.py +148 -0
  23. mlrun/common/schemas/artifact.py +15 -5
  24. mlrun/common/schemas/auth.py +8 -2
  25. mlrun/common/schemas/client_spec.py +2 -0
  26. mlrun/common/schemas/frontend_spec.py +1 -0
  27. mlrun/common/schemas/function.py +4 -0
  28. mlrun/common/schemas/hub.py +7 -9
  29. mlrun/common/schemas/model_monitoring/__init__.py +19 -3
  30. mlrun/common/schemas/model_monitoring/constants.py +96 -26
  31. mlrun/common/schemas/model_monitoring/grafana.py +9 -5
  32. mlrun/common/schemas/model_monitoring/model_endpoints.py +86 -2
  33. mlrun/{runtimes/mpijob/v1alpha1.py → common/schemas/pagination.py} +10 -13
  34. mlrun/common/schemas/pipeline.py +0 -9
  35. mlrun/common/schemas/project.py +22 -21
  36. mlrun/common/types.py +7 -1
  37. mlrun/config.py +87 -19
  38. mlrun/data_types/data_types.py +4 -0
  39. mlrun/data_types/to_pandas.py +9 -9
  40. mlrun/datastore/__init__.py +5 -8
  41. mlrun/datastore/alibaba_oss.py +130 -0
  42. mlrun/datastore/azure_blob.py +4 -5
  43. mlrun/datastore/base.py +69 -30
  44. mlrun/datastore/datastore.py +10 -2
  45. mlrun/datastore/datastore_profile.py +90 -6
  46. mlrun/datastore/google_cloud_storage.py +1 -1
  47. mlrun/datastore/hdfs.py +5 -0
  48. mlrun/datastore/inmem.py +2 -2
  49. mlrun/datastore/redis.py +2 -2
  50. mlrun/datastore/s3.py +5 -0
  51. mlrun/datastore/snowflake_utils.py +43 -0
  52. mlrun/datastore/sources.py +172 -44
  53. mlrun/datastore/store_resources.py +7 -7
  54. mlrun/datastore/targets.py +285 -41
  55. mlrun/datastore/utils.py +68 -5
  56. mlrun/datastore/v3io.py +27 -50
  57. mlrun/db/auth_utils.py +152 -0
  58. mlrun/db/base.py +149 -14
  59. mlrun/db/factory.py +1 -1
  60. mlrun/db/httpdb.py +608 -178
  61. mlrun/db/nopdb.py +191 -7
  62. mlrun/errors.py +11 -0
  63. mlrun/execution.py +37 -20
  64. mlrun/feature_store/__init__.py +0 -2
  65. mlrun/feature_store/api.py +21 -52
  66. mlrun/feature_store/feature_set.py +48 -23
  67. mlrun/feature_store/feature_vector.py +2 -1
  68. mlrun/feature_store/ingestion.py +7 -6
  69. mlrun/feature_store/retrieval/base.py +9 -4
  70. mlrun/feature_store/retrieval/conversion.py +9 -9
  71. mlrun/feature_store/retrieval/dask_merger.py +2 -0
  72. mlrun/feature_store/retrieval/job.py +9 -3
  73. mlrun/feature_store/retrieval/local_merger.py +2 -0
  74. mlrun/feature_store/retrieval/spark_merger.py +34 -24
  75. mlrun/feature_store/steps.py +30 -19
  76. mlrun/features.py +4 -13
  77. mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +7 -12
  78. mlrun/frameworks/auto_mlrun/auto_mlrun.py +2 -2
  79. mlrun/frameworks/lgbm/__init__.py +1 -1
  80. mlrun/frameworks/lgbm/callbacks/callback.py +2 -4
  81. mlrun/frameworks/lgbm/model_handler.py +1 -1
  82. mlrun/frameworks/parallel_coordinates.py +2 -1
  83. mlrun/frameworks/pytorch/__init__.py +2 -2
  84. mlrun/frameworks/sklearn/__init__.py +1 -1
  85. mlrun/frameworks/tf_keras/__init__.py +5 -2
  86. mlrun/frameworks/tf_keras/callbacks/logging_callback.py +1 -1
  87. mlrun/frameworks/tf_keras/mlrun_interface.py +2 -2
  88. mlrun/frameworks/xgboost/__init__.py +1 -1
  89. mlrun/k8s_utils.py +10 -11
  90. mlrun/launcher/__init__.py +1 -1
  91. mlrun/launcher/base.py +6 -5
  92. mlrun/launcher/client.py +8 -6
  93. mlrun/launcher/factory.py +1 -1
  94. mlrun/launcher/local.py +9 -3
  95. mlrun/launcher/remote.py +9 -3
  96. mlrun/lists.py +6 -2
  97. mlrun/model.py +58 -19
  98. mlrun/model_monitoring/__init__.py +1 -1
  99. mlrun/model_monitoring/api.py +127 -301
  100. mlrun/model_monitoring/application.py +5 -296
  101. mlrun/model_monitoring/applications/__init__.py +11 -0
  102. mlrun/model_monitoring/applications/_application_steps.py +157 -0
  103. mlrun/model_monitoring/applications/base.py +282 -0
  104. mlrun/model_monitoring/applications/context.py +214 -0
  105. mlrun/model_monitoring/applications/evidently_base.py +211 -0
  106. mlrun/model_monitoring/applications/histogram_data_drift.py +224 -93
  107. mlrun/model_monitoring/applications/results.py +99 -0
  108. mlrun/model_monitoring/controller.py +30 -36
  109. mlrun/model_monitoring/db/__init__.py +18 -0
  110. mlrun/model_monitoring/{stores → db/stores}/__init__.py +43 -36
  111. mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
  112. mlrun/model_monitoring/{stores/model_endpoint_store.py → db/stores/base/store.py} +58 -32
  113. mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
  114. mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
  115. mlrun/model_monitoring/{stores → db/stores/sqldb}/models/base.py +109 -5
  116. mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +88 -0
  117. mlrun/model_monitoring/{stores/models/mysql.py → db/stores/sqldb/models/sqlite.py} +19 -13
  118. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +684 -0
  119. mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
  120. mlrun/model_monitoring/{stores/kv_model_endpoint_store.py → db/stores/v3io_kv/kv_store.py} +302 -155
  121. mlrun/model_monitoring/db/tsdb/__init__.py +100 -0
  122. mlrun/model_monitoring/db/tsdb/base.py +329 -0
  123. mlrun/model_monitoring/db/tsdb/helpers.py +30 -0
  124. mlrun/model_monitoring/db/tsdb/tdengine/__init__.py +15 -0
  125. mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +240 -0
  126. mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +45 -0
  127. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +397 -0
  128. mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
  129. mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +117 -0
  130. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +630 -0
  131. mlrun/model_monitoring/evidently_application.py +6 -118
  132. mlrun/model_monitoring/features_drift_table.py +34 -22
  133. mlrun/model_monitoring/helpers.py +100 -7
  134. mlrun/model_monitoring/model_endpoint.py +3 -2
  135. mlrun/model_monitoring/stream_processing.py +93 -228
  136. mlrun/model_monitoring/tracking_policy.py +7 -1
  137. mlrun/model_monitoring/writer.py +152 -124
  138. mlrun/package/packagers_manager.py +1 -0
  139. mlrun/package/utils/_formatter.py +2 -2
  140. mlrun/platforms/__init__.py +11 -10
  141. mlrun/platforms/iguazio.py +21 -202
  142. mlrun/projects/operations.py +30 -16
  143. mlrun/projects/pipelines.py +92 -99
  144. mlrun/projects/project.py +757 -268
  145. mlrun/render.py +15 -14
  146. mlrun/run.py +160 -162
  147. mlrun/runtimes/__init__.py +55 -3
  148. mlrun/runtimes/base.py +33 -19
  149. mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
  150. mlrun/runtimes/funcdoc.py +0 -28
  151. mlrun/runtimes/kubejob.py +28 -122
  152. mlrun/runtimes/local.py +5 -2
  153. mlrun/runtimes/mpijob/__init__.py +0 -20
  154. mlrun/runtimes/mpijob/abstract.py +8 -8
  155. mlrun/runtimes/mpijob/v1.py +1 -1
  156. mlrun/runtimes/nuclio/__init__.py +1 -0
  157. mlrun/runtimes/nuclio/api_gateway.py +709 -0
  158. mlrun/runtimes/nuclio/application/__init__.py +15 -0
  159. mlrun/runtimes/nuclio/application/application.py +523 -0
  160. mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
  161. mlrun/runtimes/nuclio/function.py +98 -58
  162. mlrun/runtimes/nuclio/serving.py +36 -42
  163. mlrun/runtimes/pod.py +196 -45
  164. mlrun/runtimes/remotesparkjob.py +1 -1
  165. mlrun/runtimes/sparkjob/spark3job.py +1 -1
  166. mlrun/runtimes/utils.py +6 -73
  167. mlrun/secrets.py +6 -2
  168. mlrun/serving/remote.py +2 -3
  169. mlrun/serving/routers.py +7 -4
  170. mlrun/serving/server.py +7 -8
  171. mlrun/serving/states.py +73 -43
  172. mlrun/serving/v2_serving.py +8 -7
  173. mlrun/track/tracker.py +2 -1
  174. mlrun/utils/async_http.py +25 -5
  175. mlrun/utils/helpers.py +141 -75
  176. mlrun/utils/http.py +1 -1
  177. mlrun/utils/logger.py +39 -7
  178. mlrun/utils/notifications/notification/__init__.py +14 -9
  179. mlrun/utils/notifications/notification/base.py +12 -0
  180. mlrun/utils/notifications/notification/console.py +2 -0
  181. mlrun/utils/notifications/notification/git.py +3 -1
  182. mlrun/utils/notifications/notification/ipython.py +2 -0
  183. mlrun/utils/notifications/notification/slack.py +101 -21
  184. mlrun/utils/notifications/notification/webhook.py +11 -1
  185. mlrun/utils/notifications/notification_pusher.py +147 -16
  186. mlrun/utils/retryer.py +3 -2
  187. mlrun/utils/v3io_clients.py +0 -1
  188. mlrun/utils/version/version.json +2 -2
  189. {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/METADATA +33 -18
  190. mlrun-1.7.0rc20.dist-info/RECORD +353 -0
  191. {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/WHEEL +1 -1
  192. mlrun/kfpops.py +0 -868
  193. mlrun/model_monitoring/batch.py +0 -974
  194. mlrun/model_monitoring/stores/models/__init__.py +0 -27
  195. mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -382
  196. mlrun/platforms/other.py +0 -305
  197. mlrun-1.7.0rc4.dist-info/RECORD +0 -321
  198. {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/LICENSE +0 -0
  199. {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/entry_points.txt +0 -0
  200. {mlrun-1.7.0rc4.dist-info → mlrun-1.7.0rc20.dist-info}/top_level.txt +0 -0
@@ -13,8 +13,8 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import hashlib
16
- import json
17
16
  import typing
17
+ import warnings
18
18
  from datetime import datetime
19
19
 
20
20
  import numpy as np
@@ -22,13 +22,14 @@ import pandas as pd
22
22
 
23
23
  import mlrun.artifacts
24
24
  import mlrun.common.helpers
25
+ import mlrun.common.schemas.model_monitoring.constants as mm_constants
25
26
  import mlrun.feature_store
26
- from mlrun.common.schemas.model_monitoring import EventFieldType, ModelMonitoringMode
27
+ import mlrun.model_monitoring.application
28
+ import mlrun.model_monitoring.applications as mm_app
29
+ import mlrun.serving
27
30
  from mlrun.data_types.infer import InferOptions, get_df_stats
28
31
  from mlrun.utils import datetime_now, logger
29
32
 
30
- from .batch import VirtualDrift
31
- from .features_drift_table import FeaturesDriftTablePlot
32
33
  from .helpers import update_model_endpoint_last_request
33
34
  from .model_endpoint import ModelEndpoint
34
35
 
@@ -48,7 +49,7 @@ def get_or_create_model_endpoint(
48
49
  sample_set_statistics: dict[str, typing.Any] = None,
49
50
  drift_threshold: float = None,
50
51
  possible_drift_threshold: float = None,
51
- monitoring_mode: ModelMonitoringMode = ModelMonitoringMode.disabled,
52
+ monitoring_mode: mm_constants.ModelMonitoringMode = mm_constants.ModelMonitoringMode.disabled,
52
53
  db_session=None,
53
54
  ) -> ModelEndpoint:
54
55
  """
@@ -128,20 +129,19 @@ def record_results(
128
129
  context: typing.Optional[mlrun.MLClientCtx] = None,
129
130
  infer_results_df: typing.Optional[pd.DataFrame] = None,
130
131
  sample_set_statistics: typing.Optional[dict[str, typing.Any]] = None,
131
- monitoring_mode: ModelMonitoringMode = ModelMonitoringMode.enabled,
132
+ monitoring_mode: mm_constants.ModelMonitoringMode = mm_constants.ModelMonitoringMode.enabled,
133
+ # Deprecated arguments:
132
134
  drift_threshold: typing.Optional[float] = None,
133
135
  possible_drift_threshold: typing.Optional[float] = None,
134
136
  trigger_monitoring_job: bool = False,
135
137
  artifacts_tag: str = "",
136
- default_batch_image="mlrun/mlrun",
138
+ default_batch_image: str = "mlrun/mlrun",
137
139
  ) -> ModelEndpoint:
138
140
  """
139
141
  Write a provided inference dataset to model endpoint parquet target. If not exist, generate a new model endpoint
140
142
  record and use the provided sample set statistics as feature stats that will be used later for the drift analysis.
141
- To manually trigger the monitoring batch job, set `trigger_monitoring_job=True` and then the batch
142
- job will immediately perform drift analysis between the sample set statistics stored in the model and the new
143
- input data (along with the outputs). The drift rule is the value per-feature mean of the TVD and Hellinger scores
144
- according to the provided thresholds.
143
+ To activate model monitoring, run `project.enable_model_monitoring()`. The model monitoring applications will be
144
+ triggered with the recorded data according to a periodic schedule.
145
145
 
146
146
  :param project: Project name.
147
147
  :param model_path: The model Store path.
@@ -160,17 +160,47 @@ def record_results(
160
160
  the current model endpoint.
161
161
  :param monitoring_mode: If enabled, apply model monitoring features on the provided endpoint id. Enabled
162
162
  by default.
163
- :param drift_threshold: The threshold of which to mark drifts.
164
- :param possible_drift_threshold: The threshold of which to mark possible drifts.
165
- :param trigger_monitoring_job: If true, run the batch drift job. If not exists, the monitoring batch function
166
- will be registered through MLRun API with the provided image.
167
- :param artifacts_tag: Tag to use for all the artifacts resulted from the function. Will be relevant
168
- only if the monitoring batch job has been triggered.
169
-
170
- :param default_batch_image: The image that will be used when registering the model monitoring batch job.
163
+ :param drift_threshold: (deprecated) The threshold of which to mark drifts.
164
+ :param possible_drift_threshold: (deprecated) The threshold of which to mark possible drifts.
165
+ :param trigger_monitoring_job: (deprecated) If true, run the batch drift job. If not exists, the monitoring
166
+ batch function will be registered through MLRun API with the provided image.
167
+ :param artifacts_tag: (deprecated) Tag to use for all the artifacts resulted from the function.
168
+ Will be relevant only if the monitoring batch job has been triggered.
169
+ :param default_batch_image: (deprecated) The image that will be used when registering the model monitoring
170
+ batch job.
171
171
 
172
172
  :return: A ModelEndpoint object
173
173
  """
174
+
175
+ if drift_threshold is not None or possible_drift_threshold is not None:
176
+ warnings.warn(
177
+ "Custom drift threshold arguments are deprecated since version "
178
+ "1.7.0 and have no effect. They will be removed in version 1.9.0.\n"
179
+ "To enable the default histogram data drift application, run:\n"
180
+ "`project.enable_model_monitoring()`.",
181
+ FutureWarning,
182
+ )
183
+ if trigger_monitoring_job is not False:
184
+ warnings.warn(
185
+ "`trigger_monitoring_job` argument is deprecated since version "
186
+ "1.7.0 and has no effect. It will be removed in version 1.9.0.\n"
187
+ "To enable the default histogram data drift application, run:\n"
188
+ "`project.enable_model_monitoring()`.",
189
+ FutureWarning,
190
+ )
191
+ if artifacts_tag != "":
192
+ warnings.warn(
193
+ "`artifacts_tag` argument is deprecated since version "
194
+ "1.7.0 and has no effect. It will be removed in version 1.9.0.",
195
+ FutureWarning,
196
+ )
197
+ if default_batch_image != "mlrun/mlrun":
198
+ warnings.warn(
199
+ "`default_batch_image` argument is deprecated since version "
200
+ "1.7.0 and has no effect. It will be removed in version 1.9.0.",
201
+ FutureWarning,
202
+ )
203
+
174
204
  db = mlrun.get_run_db()
175
205
 
176
206
  model_endpoint = get_or_create_model_endpoint(
@@ -181,8 +211,6 @@ def record_results(
181
211
  function_name=function_name,
182
212
  context=context,
183
213
  sample_set_statistics=sample_set_statistics,
184
- drift_threshold=drift_threshold,
185
- possible_drift_threshold=possible_drift_threshold,
186
214
  monitoring_mode=monitoring_mode,
187
215
  db_session=db,
188
216
  )
@@ -206,33 +234,6 @@ def record_results(
206
234
  db=db,
207
235
  )
208
236
 
209
- if trigger_monitoring_job:
210
- # Run the monitoring batch drift job
211
- trigger_drift_batch_job(
212
- project=project,
213
- default_batch_image=default_batch_image,
214
- model_endpoints_ids=[model_endpoint.metadata.uid],
215
- db_session=db,
216
- )
217
-
218
- # Getting drift thresholds if not provided
219
- drift_threshold, possible_drift_threshold = get_drift_thresholds_if_not_none(
220
- model_endpoint=model_endpoint,
221
- drift_threshold=drift_threshold,
222
- possible_drift_threshold=possible_drift_threshold,
223
- )
224
-
225
- perform_drift_analysis(
226
- project=project,
227
- context=context,
228
- sample_set_statistics=model_endpoint.status.feature_stats,
229
- drift_threshold=drift_threshold,
230
- possible_drift_threshold=possible_drift_threshold,
231
- artifacts_tag=artifacts_tag,
232
- endpoint_id=model_endpoint.metadata.uid,
233
- db_session=db,
234
- )
235
-
236
237
  return model_endpoint
237
238
 
238
239
 
@@ -282,7 +283,7 @@ def _model_endpoint_validations(
282
283
  # drift and possible drift thresholds
283
284
  if drift_threshold:
284
285
  current_drift_threshold = model_endpoint.spec.monitor_configuration.get(
285
- EventFieldType.DRIFT_DETECTED_THRESHOLD,
286
+ mm_constants.EventFieldType.DRIFT_DETECTED_THRESHOLD,
286
287
  mlrun.mlconf.model_endpoint_monitoring.drift_thresholds.default.drift_detected,
287
288
  )
288
289
  if current_drift_threshold != drift_threshold:
@@ -293,7 +294,7 @@ def _model_endpoint_validations(
293
294
 
294
295
  if possible_drift_threshold:
295
296
  current_possible_drift_threshold = model_endpoint.spec.monitor_configuration.get(
296
- EventFieldType.POSSIBLE_DRIFT_THRESHOLD,
297
+ mm_constants.EventFieldType.POSSIBLE_DRIFT_THRESHOLD,
297
298
  mlrun.mlconf.model_endpoint_monitoring.drift_thresholds.default.possible_drift,
298
299
  )
299
300
  if current_possible_drift_threshold != possible_drift_threshold:
@@ -303,40 +304,6 @@ def _model_endpoint_validations(
303
304
  )
304
305
 
305
306
 
306
- def get_drift_thresholds_if_not_none(
307
- model_endpoint: ModelEndpoint,
308
- drift_threshold: float = None,
309
- possible_drift_threshold: float = None,
310
- ) -> tuple[float, float]:
311
- """
312
- Get drift and possible drift thresholds. If one of the thresholds is missing, will try to retrieve
313
- it from the `ModelEndpoint` object. If not defined under the `ModelEndpoint` as well, will retrieve it from
314
- the default mlrun configuration.
315
-
316
- :param model_endpoint: `ModelEndpoint` object.
317
- :param drift_threshold: The threshold of which to mark drifts.
318
- :param possible_drift_threshold: The threshold of which to mark possible drifts.
319
-
320
- :return: A Tuple of:
321
- [0] drift threshold as a float
322
- [1] possible drift threshold as a float
323
- """
324
- if not drift_threshold:
325
- # Getting drift threshold value from either model endpoint or monitoring default configurations
326
- drift_threshold = model_endpoint.spec.monitor_configuration.get(
327
- EventFieldType.DRIFT_DETECTED_THRESHOLD,
328
- mlrun.mlconf.model_endpoint_monitoring.drift_thresholds.default.drift_detected,
329
- )
330
- if not possible_drift_threshold:
331
- # Getting possible drift threshold value from either model endpoint or monitoring default configurations
332
- possible_drift_threshold = model_endpoint.spec.monitor_configuration.get(
333
- EventFieldType.POSSIBLE_DRIFT_THRESHOLD,
334
- mlrun.mlconf.model_endpoint_monitoring.drift_thresholds.default.possible_drift,
335
- )
336
-
337
- return drift_threshold, possible_drift_threshold
338
-
339
-
340
307
  def write_monitoring_df(
341
308
  endpoint_id: str,
342
309
  infer_results_df: pd.DataFrame,
@@ -366,14 +333,14 @@ def write_monitoring_df(
366
333
  )
367
334
 
368
335
  # Modify the DataFrame to the required structure that will be used later by the monitoring batch job
369
- if EventFieldType.TIMESTAMP not in infer_results_df.columns:
336
+ if mm_constants.EventFieldType.TIMESTAMP not in infer_results_df.columns:
370
337
  # Initialize timestamp column with the current time
371
- infer_results_df[EventFieldType.TIMESTAMP] = infer_datetime
338
+ infer_results_df[mm_constants.EventFieldType.TIMESTAMP] = infer_datetime
372
339
 
373
340
  # `endpoint_id` is the monitoring feature set entity and therefore it should be defined as the df index before
374
341
  # the ingest process
375
- infer_results_df[EventFieldType.ENDPOINT_ID] = endpoint_id
376
- infer_results_df.set_index(EventFieldType.ENDPOINT_ID, inplace=True)
342
+ infer_results_df[mm_constants.EventFieldType.ENDPOINT_ID] = endpoint_id
343
+ infer_results_df.set_index(mm_constants.EventFieldType.ENDPOINT_ID, inplace=True)
377
344
 
378
345
  monitoring_feature_set.ingest(source=infer_results_df, overwrite=False)
379
346
 
@@ -389,7 +356,7 @@ def _generate_model_endpoint(
389
356
  sample_set_statistics: dict[str, typing.Any],
390
357
  drift_threshold: float,
391
358
  possible_drift_threshold: float,
392
- monitoring_mode: ModelMonitoringMode = ModelMonitoringMode.disabled,
359
+ monitoring_mode: mm_constants.ModelMonitoringMode = mm_constants.ModelMonitoringMode.disabled,
393
360
  ) -> ModelEndpoint:
394
361
  """
395
362
  Write a new model endpoint record.
@@ -428,11 +395,11 @@ def _generate_model_endpoint(
428
395
  model_endpoint.spec.model_class = "drift-analysis"
429
396
  if drift_threshold:
430
397
  model_endpoint.spec.monitor_configuration[
431
- EventFieldType.DRIFT_DETECTED_THRESHOLD
398
+ mm_constants.EventFieldType.DRIFT_DETECTED_THRESHOLD
432
399
  ] = drift_threshold
433
400
  if possible_drift_threshold:
434
401
  model_endpoint.spec.monitor_configuration[
435
- EventFieldType.POSSIBLE_DRIFT_THRESHOLD
402
+ mm_constants.EventFieldType.POSSIBLE_DRIFT_THRESHOLD
436
403
  ] = possible_drift_threshold
437
404
 
438
405
  model_endpoint.spec.monitoring_mode = monitoring_mode
@@ -449,71 +416,6 @@ def _generate_model_endpoint(
449
416
  return db_session.get_model_endpoint(project=project, endpoint_id=endpoint_id)
450
417
 
451
418
 
452
- def trigger_drift_batch_job(
453
- project: str,
454
- default_batch_image="mlrun/mlrun",
455
- model_endpoints_ids: list[str] = None,
456
- batch_intervals_dict: dict[str, float] = None,
457
- db_session=None,
458
- ):
459
- """
460
- Run model monitoring drift analysis job. If not exists, the monitoring batch function will be registered through
461
- MLRun API with the provided image.
462
-
463
- :param project: Project name.
464
- :param default_batch_image: The image that will be used when registering the model monitoring batch job.
465
- :param model_endpoints_ids: List of model endpoints to include in the current run.
466
- :param batch_intervals_dict: Batch interval range (days, hours, minutes). By default, the batch interval is
467
- configured to run through the last hour.
468
- :param db_session: A runtime session that manages the current dialog with the database.
469
-
470
- """
471
- if not model_endpoints_ids:
472
- raise mlrun.errors.MLRunNotFoundError(
473
- "No model endpoints provided",
474
- )
475
- if not db_session:
476
- db_session = mlrun.get_run_db()
477
-
478
- # Register the monitoring batch job (do nothing if already exist) and get the job function as a dictionary
479
- batch_function_dict: dict[str, typing.Any] = db_session.deploy_monitoring_batch_job(
480
- project=project,
481
- default_batch_image=default_batch_image,
482
- )
483
-
484
- # Prepare current run params
485
- job_params = _generate_job_params(
486
- model_endpoints_ids=model_endpoints_ids,
487
- batch_intervals_dict=batch_intervals_dict,
488
- )
489
-
490
- # Generate runtime and trigger the job function
491
- batch_function = mlrun.new_function(runtime=batch_function_dict)
492
- batch_function.run(name="model-monitoring-batch", params=job_params, watch=True)
493
-
494
-
495
- def _generate_job_params(
496
- model_endpoints_ids: list[str],
497
- batch_intervals_dict: dict[str, float] = None,
498
- ):
499
- """
500
- Generate the required params for the model monitoring batch job function.
501
-
502
- :param model_endpoints_ids: List of model endpoints to include in the current run.
503
- :param batch_intervals_dict: Batch interval range (days, hours, minutes). By default, the batch interval is
504
- configured to run through the last hour.
505
-
506
- """
507
- if not batch_intervals_dict:
508
- # Generate default batch intervals dict
509
- batch_intervals_dict = {"minutes": 0, "hours": 1, "days": 0}
510
-
511
- return {
512
- "model_endpoints": model_endpoints_ids,
513
- "batch_intervals_dict": batch_intervals_dict,
514
- }
515
-
516
-
517
419
  def get_sample_set_statistics(
518
420
  sample_set: DatasetType = None,
519
421
  model_artifact_feature_stats: dict = None,
@@ -659,151 +561,6 @@ def read_dataset_as_dataframe(
659
561
  return dataset, label_columns
660
562
 
661
563
 
662
- def perform_drift_analysis(
663
- project: str,
664
- endpoint_id: str,
665
- context: mlrun.MLClientCtx,
666
- sample_set_statistics: dict,
667
- drift_threshold: float,
668
- possible_drift_threshold: float,
669
- artifacts_tag: str = "",
670
- db_session=None,
671
- ) -> None:
672
- """
673
- Calculate drift per feature and produce the drift table artifact for logging post prediction. Note that most of
674
- the calculations were already made through the monitoring batch job.
675
-
676
- :param project: Project name.
677
- :param endpoint_id: Model endpoint unique ID.
678
- :param context: MLRun context. Will log the artifacts.
679
- :param sample_set_statistics: The statistics of the sample set logged along a model.
680
- :param drift_threshold: The threshold of which to mark drifts.
681
- :param possible_drift_threshold: The threshold of which to mark possible drifts.
682
- :param artifacts_tag: Tag to use for all the artifacts resulted from the function.
683
- :param db_session: A runtime session that manages the current dialog with the database.
684
-
685
- """
686
- if not db_session:
687
- db_session = mlrun.get_run_db()
688
-
689
- model_endpoint = db_session.get_model_endpoint(
690
- project=project, endpoint_id=endpoint_id
691
- )
692
-
693
- # Get the drift metrics results along with the feature statistics from the latest batch
694
- metrics = model_endpoint.status.drift_measures
695
- inputs_statistics = model_endpoint.status.current_stats
696
-
697
- inputs_statistics.pop(EventFieldType.TIMESTAMP, None)
698
-
699
- # Calculate drift for each feature
700
- virtual_drift = VirtualDrift()
701
- drift_results = virtual_drift.check_for_drift_per_feature(
702
- metrics_results_dictionary=metrics,
703
- possible_drift_threshold=possible_drift_threshold,
704
- drift_detected_threshold=drift_threshold,
705
- )
706
-
707
- # Drift table plot
708
- html_plot = FeaturesDriftTablePlot().produce(
709
- sample_set_statistics=sample_set_statistics,
710
- inputs_statistics=inputs_statistics,
711
- metrics=metrics,
712
- drift_results=drift_results,
713
- )
714
-
715
- # Prepare drift result per feature dictionary
716
- metrics_per_feature = {
717
- feature: _get_drift_result(
718
- tvd=metric_dictionary["tvd"],
719
- hellinger=metric_dictionary["hellinger"],
720
- threshold=drift_threshold,
721
- )[1]
722
- for feature, metric_dictionary in metrics.items()
723
- if isinstance(metric_dictionary, dict)
724
- }
725
-
726
- # Calculate the final analysis result as well
727
- drift_status, drift_metric = _get_drift_result(
728
- tvd=metrics["tvd_mean"],
729
- hellinger=metrics["hellinger_mean"],
730
- threshold=drift_threshold,
731
- )
732
- # Log the different artifacts
733
- _log_drift_artifacts(
734
- context=context,
735
- html_plot=html_plot,
736
- metrics_per_feature=metrics_per_feature,
737
- drift_status=drift_status,
738
- drift_metric=drift_metric,
739
- artifacts_tag=artifacts_tag,
740
- )
741
-
742
-
743
- def _log_drift_artifacts(
744
- context: mlrun.MLClientCtx,
745
- html_plot: str,
746
- metrics_per_feature: dict[str, float],
747
- drift_status: bool,
748
- drift_metric: float,
749
- artifacts_tag: str,
750
- ):
751
- """
752
- Log the following artifacts/results:
753
- 1 - Drift table plot which includes a detailed drift analysis per feature
754
- 2 - Drift result per feature in a JSON format
755
- 3 - Results of the total drift analysis
756
-
757
- :param context: MLRun context. Will log the artifacts.
758
- :param html_plot: Body of the html file of the plot.
759
- :param metrics_per_feature: Dictionary in which the key is a feature name and the value is the drift numerical
760
- result.
761
- :param drift_status: Boolean value that represents the final drift analysis result.
762
- :param drift_metric: The final drift numerical result.
763
- :param artifacts_tag: Tag to use for all the artifacts resulted from the function.
764
-
765
- """
766
- context.log_artifact(
767
- mlrun.artifacts.Artifact(
768
- body=html_plot.encode("utf-8"), format="html", key="drift_table_plot"
769
- ),
770
- tag=artifacts_tag,
771
- )
772
- context.log_artifact(
773
- mlrun.artifacts.Artifact(
774
- body=json.dumps(metrics_per_feature),
775
- format="json",
776
- key="features_drift_results",
777
- ),
778
- tag=artifacts_tag,
779
- )
780
- context.log_results(
781
- results={"drift_status": drift_status, "drift_metric": drift_metric}
782
- )
783
-
784
-
785
- def _get_drift_result(
786
- tvd: float,
787
- hellinger: float,
788
- threshold: float,
789
- ) -> tuple[bool, float]:
790
- """
791
- Calculate the drift result by the following equation: (tvd + hellinger) / 2
792
-
793
- :param tvd: The feature's TVD value.
794
- :param hellinger: The feature's Hellinger value.
795
- :param threshold: The threshold from which the value is considered a drift.
796
-
797
- :returns: A tuple of:
798
- [0] = Boolean value as the drift status.
799
- [1] = The result.
800
- """
801
- result = (tvd + hellinger) / 2
802
- if result >= threshold:
803
- return True, result
804
- return False, result
805
-
806
-
807
564
  def log_result(
808
565
  context: mlrun.MLClientCtx,
809
566
  result_set_name: str,
@@ -826,3 +583,72 @@ def log_result(
826
583
  key="batch_id",
827
584
  value=batch_id,
828
585
  )
586
+
587
+
588
+ def _create_model_monitoring_function_base(
589
+ *,
590
+ project: str,
591
+ func: typing.Union[str, None] = None,
592
+ application_class: typing.Union[
593
+ str,
594
+ mlrun.model_monitoring.application.ModelMonitoringApplicationBase,
595
+ mm_app.ModelMonitoringApplicationBaseV2,
596
+ None,
597
+ ] = None,
598
+ name: typing.Optional[str] = None,
599
+ image: typing.Optional[str] = None,
600
+ tag: typing.Optional[str] = None,
601
+ requirements: typing.Union[str, list[str], None] = None,
602
+ requirements_file: str = "",
603
+ **application_kwargs,
604
+ ) -> mlrun.runtimes.ServingRuntime:
605
+ """
606
+ Note: this is an internal API only.
607
+ This function does not set the labels or mounts v3io.
608
+ """
609
+ if isinstance(
610
+ application_class,
611
+ mlrun.model_monitoring.application.ModelMonitoringApplicationBase,
612
+ ):
613
+ warnings.warn(
614
+ "The `ModelMonitoringApplicationBase` class is deprecated from version 1.7.0, "
615
+ "please use `ModelMonitoringApplicationBaseV2`. It will be removed in 1.9.0.",
616
+ FutureWarning,
617
+ )
618
+ if name in mm_constants.MonitoringFunctionNames.list():
619
+ raise mlrun.errors.MLRunInvalidArgumentError(
620
+ f"An application cannot have the following names: "
621
+ f"{mm_constants.MonitoringFunctionNames.list()}"
622
+ )
623
+ if func is None:
624
+ func = ""
625
+ func_obj = typing.cast(
626
+ mlrun.runtimes.ServingRuntime,
627
+ mlrun.code_to_function(
628
+ filename=func,
629
+ name=name,
630
+ project=project,
631
+ tag=tag,
632
+ kind=mlrun.run.RuntimeKinds.serving,
633
+ image=image,
634
+ requirements=requirements,
635
+ requirements_file=requirements_file,
636
+ ),
637
+ )
638
+ graph = func_obj.set_topology(mlrun.serving.states.StepKinds.flow)
639
+ prepare_step = graph.to(
640
+ class_name="mlrun.model_monitoring.applications._application_steps._PrepareMonitoringEvent",
641
+ name="PrepareMonitoringEvent",
642
+ application_name=name,
643
+ )
644
+ if isinstance(application_class, str):
645
+ app_step = prepare_step.to(class_name=application_class, **application_kwargs)
646
+ else:
647
+ app_step = prepare_step.to(class_name=application_class)
648
+ app_step.to(
649
+ class_name="mlrun.model_monitoring.applications._application_steps._PushToMonitoringWriter",
650
+ name="PushToMonitoringWriter",
651
+ project=project,
652
+ writer_application_name=mm_constants.MonitoringFunctionNames.WRITER,
653
+ ).respond()
654
+ return func_obj