\n"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data",
+ "jetTransient": {
+ "display_id": null
+ }
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ],
+ "text/html": [
+ " > to track results use the .show() or .logs() methods or click here to open in UI"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data",
+ "jetTransient": {
+ "display_id": null
+ }
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "> 2026-02-10 16:15:03,414 [info] Run execution finished: {\"name\":\"onnx-utils-optimize\",\"status\":\"completed\"}\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "execution_count": 6
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "2.2.2. And now our model was optimized. Let us verify:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "pycharm": {
+ "name": "#%%\n"
+ },
+ "ExecuteTime": {
+ "end_time": "2026-02-10T14:15:05.748413Z",
+ "start_time": "2026-02-10T14:15:05.745309Z"
+ }
+ },
+ "source": [
+ "optimized_model_file = os.path.join(ARTIFACT_PATH, \"onnx-utils-optimize\", \"0\", \"model\", \"optimized_onnx_mobilenetv2.onnx\")\n",
+ "assert os.path.isfile(optimized_model_file), f\"Optimized ONNX model not found at {optimized_model_file}\"\n",
+ "print(f\"Optimized ONNX model created at: {optimized_model_file}\")"
+ ],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Optimized ONNX model created at: /var/folders/rn/q8gs952n26982d36y50w_2rw0000gp/T/tmpvs5qvbxr/onnx-utils-optimize/0/model/optimized_onnx_mobilenetv2.onnx\n"
+ ]
+ }
+ ],
+ "execution_count": 7
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "pycharm": {
+ "name": "#%% md\n"
+ }
+ },
+ "source": [
+ "Lastly, run this code to clean up all generated files and directories:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "metadata": {
+ "pycharm": {
+ "name": "#%%\n"
+ },
+ "ExecuteTime": {
+ "end_time": "2026-02-10T14:00:28.409998Z",
+ "start_time": "2026-02-10T13:57:21.679146Z"
+ }
+ },
+ "source": "import shutil\n\n# Clean up the temporary artifact directory:\nif os.path.exists(ARTIFACT_PATH):\n shutil.rmtree(ARTIFACT_PATH)",
+ "outputs": [],
+ "execution_count": null
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "mlrun_functions",
+ "language": "python",
+ "name": "mlrun_functions"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.22"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/functions/development/onnx_utils/1.4.0/src/onnx_utils.py b/functions/development/onnx_utils/1.4.0/src/onnx_utils.py
new file mode 100644
index 00000000..c26e011b
--- /dev/null
+++ b/functions/development/onnx_utils/1.4.0/src/onnx_utils.py
@@ -0,0 +1,271 @@
+# Copyright 2019 Iguazio
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+from typing import Any, Callable, Dict, List, Tuple
+
+import mlrun
+
+
+class _ToONNXConversions:
+ """
+ An ONNX conversion functions library class.
+ """
+
+ @staticmethod
+ def tf_keras_to_onnx(
+ model_handler,
+ onnx_model_name: str = None,
+ optimize_model: bool = True,
+ input_signature: List[Tuple[Tuple[int], str]] = None,
+ ):
+ """
+ Convert a TF.Keras model to an ONNX model and log it back to MLRun as a new model object.
+
+ :param model_handler: An initialized TFKerasModelHandler with a loaded model to convert to ONNX.
+ :param onnx_model_name: The name to use to log the converted ONNX model. If not given, the given `model_name`
+ will be used with an additional suffix `_onnx`. Defaulted to None.
+ :param optimize_model: Whether or not to optimize the ONNX model using 'onnxoptimizer' before saving the model.
+ Defaulted to True.
+ :param input_signature: A list of the input layers shape and data type properties. Expected to receive a list
+ where each element is an input layer tuple. An input layer tuple is a tuple of:
+ [0] = Layer's shape, a tuple of integers.
+ [1] = Layer's data type, a mlrun.data_types.ValueType string.
+ If None, the input signature will be tried to be read from the model artifact. Defaulted
+ to None.
+ """
+ # Import the framework and handler:
+ import tensorflow as tf
+ from mlrun.frameworks.tf_keras import TFKerasUtils
+
+ # Check the given 'input_signature' parameter:
+ if input_signature is None:
+ # Read the inputs from the model:
+ try:
+ model_handler.read_inputs_from_model()
+ except Exception as error:
+ raise mlrun.errors.MLRunRuntimeError(
+ f"Please provide the 'input_signature' parameter. The function tried reading the input layers "
+ f"information automatically but failed with the following error: {error}"
+ )
+ else:
+ # Parse the 'input_signature' parameter:
+ input_signature = [
+ tf.TensorSpec(
+ shape=shape,
+ dtype=TFKerasUtils.convert_value_type_to_tf_dtype(
+ value_type=value_type
+ ),
+ )
+ for (shape, value_type) in input_signature
+ ]
+
+ # Convert to ONNX:
+ model_handler.to_onnx(
+ model_name=onnx_model_name,
+ input_signature=input_signature,
+ optimize=optimize_model,
+ )
+
+ @staticmethod
+ def pytorch_to_onnx(
+ model_handler,
+ onnx_model_name: str = None,
+ optimize_model: bool = True,
+ input_signature: List[Tuple[Tuple[int, ...], str]] = None,
+ input_layers_names: List[str] = None,
+ output_layers_names: List[str] = None,
+ dynamic_axes: Dict[str, Dict[int, str]] = None,
+ is_batched: bool = True,
+ ):
+ """
+ Convert a PyTorch model to an ONNX model and log it back to MLRun as a new model object.
+
+ :param model_handler: An initialized PyTorchModelHandler with a loaded model to convert to ONNX.
+ :param onnx_model_name: The name to use to log the converted ONNX model. If not given, the given
+ `model_name` will be used with an additional suffix `_onnx`. Defaulted to None.
+ :param optimize_model: Whether or not to optimize the ONNX model using 'onnxoptimizer' before saving the
+ model. Defaulted to True.
+ :param input_signature: A list of the input layers shape and data type properties. Expected to receive a
+ list where each element is an input layer tuple. An input layer tuple is a tuple of:
+ [0] = Layer's shape, a tuple of integers.
+ [1] = Layer's data type, a mlrun.data_types.ValueType string.
+ If None, the input signature will be tried to be read from the model artifact.
+ Defaulted to None.
+ :param input_layers_names: List of names to assign to the input nodes of the graph in order. All of the other
+ parameters (inner layers) can be set as well by passing additional names in the
+ list. The order is by the order of the parameters in the model. If None, the inputs
+ will be read from the handler's inputs. If its also None, it is defaulted to:
+ "input_0", "input_1", ...
+ :param output_layers_names: List of names to assign to the output nodes of the graph in order. If None, the
+ outputs will be read from the handler's outputs. If its also None, it is defaulted
+ to: "output_0" (for multiple outputs, this parameter must be provided).
+ :param dynamic_axes: If part of the input / output shape is dynamic, like (batch_size, 3, 32, 32) you can
+ specify it by giving a dynamic axis to the input / output layer by its name as
+ follows: {
+ "input layer name": {0: "batch_size"},
+ "output layer name": {0: "batch_size"},
+ }
+ If provided, the 'is_batched' flag will be ignored. Defaulted to None.
+ :param is_batched: Whether to include a batch size as the first axis in every input and output layer.
+ Defaulted to True. Will be ignored if 'dynamic_axes' is provided.
+ """
+ # Import the framework and handler:
+ import torch
+ from mlrun.frameworks.pytorch import PyTorchUtils
+
+ # Parse the 'input_signature' parameter:
+ if input_signature is not None:
+ input_signature = tuple(
+ [
+ torch.zeros(
+ size=shape,
+ dtype=PyTorchUtils.convert_value_type_to_torch_dtype(
+ value_type=value_type
+ ),
+ )
+ for (shape, value_type) in input_signature
+ ]
+ )
+
+ # Convert to ONNX:
+ model_handler.to_onnx(
+ model_name=onnx_model_name,
+ input_sample=input_signature,
+ optimize=optimize_model,
+ input_layers_names=input_layers_names,
+ output_layers_names=output_layers_names,
+ dynamic_axes=dynamic_axes,
+ is_batched=is_batched,
+ )
+
+
+# Map for getting the conversion function according to the provided framework:
+_CONVERSION_MAP = {
+ "tensorflow.keras": _ToONNXConversions.tf_keras_to_onnx,
+ "torch": _ToONNXConversions.pytorch_to_onnx,
+} # type: Dict[str, Callable]
+
+
+def to_onnx(
+ context: mlrun.MLClientCtx,
+ model_path: str,
+ load_model_kwargs: dict = None,
+ onnx_model_name: str = None,
+ optimize_model: bool = True,
+ framework_kwargs: Dict[str, Any] = None,
+):
+ """
+ Convert the given model to an ONNX model.
+
+ :param context: The MLRun function execution context
+ :param model_path: The model path store object.
+ :param load_model_kwargs: Keyword arguments to pass to the `AutoMLRun.load_model` method.
+ :param onnx_model_name: The name to use to log the converted ONNX model. If not given, the given `model_name` will
+ be used with an additional suffix `_onnx`. Defaulted to None.
+ :param optimize_model: Whether to optimize the ONNX model using 'onnxoptimizer' before saving the model.
+ Defaulted to True.
+ :param framework_kwargs: Additional arguments each framework may require to convert to ONNX. To get the doc string
+ of the desired framework onnx conversion function, pass "help".
+ """
+ from mlrun.frameworks.auto_mlrun.auto_mlrun import AutoMLRun
+
+ # Get a model handler of the required framework:
+ load_model_kwargs = load_model_kwargs or {}
+ model_handler = AutoMLRun.load_model(
+ model_path=model_path, context=context, **load_model_kwargs
+ )
+
+ # Get the model's framework:
+ framework = model_handler.FRAMEWORK_NAME
+
+ # Use the conversion map to get the specific framework to onnx conversion:
+ if framework not in _CONVERSION_MAP:
+ raise mlrun.errors.MLRunInvalidArgumentError(
+ f"The following framework: '{framework}', has no ONNX conversion."
+ )
+ conversion_function = _CONVERSION_MAP[framework]
+
+ # Check if needed to print the function's doc string ("help" is passed):
+ if framework_kwargs == "help":
+ print(conversion_function.__doc__)
+ return
+
+ # Set the default empty framework kwargs if needed:
+ if framework_kwargs is None:
+ framework_kwargs = {}
+
+ # Run the conversion:
+ try:
+ conversion_function(
+ model_handler=model_handler,
+ onnx_model_name=onnx_model_name,
+ optimize_model=optimize_model,
+ **framework_kwargs,
+ )
+ except TypeError as exception:
+ raise mlrun.errors.MLRunInvalidArgumentError(
+ f"ERROR: A TypeError exception was raised during the conversion:\n{exception}. "
+ f"Please read the {framework} framework conversion function doc string by passing 'help' in the "
+ f"'framework_kwargs' dictionary parameter."
+ )
+
+
+def optimize(
+ context: mlrun.MLClientCtx,
+ model_path: str,
+ handler_init_kwargs: dict = None,
+ optimizations: List[str] = None,
+ fixed_point: bool = False,
+ optimized_model_name: str = None,
+):
+ """
+ Optimize the given ONNX model.
+
+ :param context: The MLRun function execution context.
+ :param model_path: Path to the ONNX model object.
+ :param handler_init_kwargs: Keyword arguments to pass to the `ONNXModelHandler` init method preloading.
+ :param optimizations: List of possible optimizations. To see what optimizations are available, pass "help".
+ If None, all the optimizations will be used. Defaulted to None.
+ :param fixed_point: Optimize the weights using fixed point. Defaulted to False.
+ :param optimized_model_name: The name of the optimized model. If None, the original model will be overridden.
+ Defaulted to None.
+ """
+ # Import the model handler:
+ import onnxoptimizer
+ from mlrun.frameworks.onnx import ONNXModelHandler
+
+ # Check if needed to print the available optimizations ("help" is passed):
+ if optimizations == "help":
+ available_passes = "\n* ".join(onnxoptimizer.get_available_passes())
+ print(f"The available optimizations are:\n* {available_passes}")
+ return
+
+ # Create the model handler:
+ handler_init_kwargs = handler_init_kwargs or {}
+ model_handler = ONNXModelHandler(
+ model_path=model_path, context=context, **handler_init_kwargs
+ )
+
+ # Load the ONNX model:
+ model_handler.load()
+
+ # Optimize the model using the given configurations:
+ model_handler.optimize(optimizations=optimizations, fixed_point=fixed_point)
+
+ # Rename if needed:
+ if optimized_model_name is not None:
+ model_handler.set_model_name(model_name=optimized_model_name)
+
+ # Log the optimized model:
+ model_handler.log()
diff --git a/functions/development/onnx_utils/1.4.0/src/requirements.txt b/functions/development/onnx_utils/1.4.0/src/requirements.txt
new file mode 100644
index 00000000..912b3d7e
--- /dev/null
+++ b/functions/development/onnx_utils/1.4.0/src/requirements.txt
@@ -0,0 +1,10 @@
+tqdm~=4.67.1
+tensorflow~=2.19.0
+tf_keras~=2.19.0
+torch~=2.8
+torchvision~=0.23.0
+onnx~=1.17.0
+onnxruntime~=1.19.2
+onnxoptimizer~=0.3.13
+onnxmltools~=1.13.0
+plotly~=5.23
\ No newline at end of file
diff --git a/functions/development/onnx_utils/1.4.0/src/test_onnx_utils.py b/functions/development/onnx_utils/1.4.0/src/test_onnx_utils.py
new file mode 100644
index 00000000..59c6c2b3
--- /dev/null
+++ b/functions/development/onnx_utils/1.4.0/src/test_onnx_utils.py
@@ -0,0 +1,432 @@
+# Copyright 2019 Iguazio
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+import os
+import shutil
+import tempfile
+
+import mlrun
+import pytest
+
+PROJECT_NAME = "onnx-utils"
+
+# Choose our model's name:
+MODEL_NAME = "model"
+
+# Choose our ONNX version model's name:
+ONNX_MODEL_NAME = f"onnx_{MODEL_NAME}"
+
+# Choose our optimized ONNX version model's name:
+OPTIMIZED_ONNX_MODEL_NAME = f"optimized_{ONNX_MODEL_NAME}"
+
+REQUIRED_ENV_VARS = [
+ "MLRUN_DBPATH",
+ "MLRUN_ARTIFACT_PATH",
+ "V3IO_USERNAME",
+ "V3IO_ACCESS_KEY",
+]
+
+
+def _validate_environment_variables() -> bool:
+ """
+ Checks that all required Environment variables are set.
+ """
+ environment_keys = os.environ.keys()
+ return all(key in environment_keys for key in REQUIRED_ENV_VARS)
+
+
+def _is_tf2onnx_available() -> bool:
+ """
+ Check if tf2onnx is installed (required for TensorFlow/Keras ONNX conversion).
+ """
+ try:
+ import tf2onnx
+ return True
+ except ImportError:
+ return False
+
+
+@pytest.fixture(scope="session")
+def onnx_project():
+ """Create/get the MLRun project once per test session."""
+ return mlrun.get_or_create_project(PROJECT_NAME, context="./")
+
+
+@pytest.fixture(autouse=True)
+def test_environment(onnx_project):
+ """Setup and cleanup test artifacts for each test."""
+ artifact_path = tempfile.mkdtemp()
+ yield artifact_path
+ # Cleanup - only remove files/dirs from the directory containing this test file,
+ # never from an arbitrary CWD (which could be the project root).
+ test_dir = os.path.dirname(os.path.abspath(__file__))
+ for test_output in [
+ "schedules",
+ "runs",
+ "artifacts",
+ "functions",
+ "model.pt",
+ "model.zip",
+ "model_modules_map.json",
+ "model_modules_map.json.json",
+ "onnx_model.onnx",
+ "optimized_onnx_model.onnx",
+ ]:
+ test_output_path = os.path.join(test_dir, test_output)
+ if os.path.exists(test_output_path):
+ if os.path.isdir(test_output_path):
+ shutil.rmtree(test_output_path)
+ else:
+ os.remove(test_output_path)
+ if os.path.exists(artifact_path):
+ shutil.rmtree(artifact_path)
+
+
+def _log_tf_keras_model(context: mlrun.MLClientCtx, model_name: str):
+ """
+ Create and log a tf.keras model - MobileNetV2.
+
+ :param context: The context to log to.
+ :param model_name: The model name to use.
+ """
+ # To use `tf_keras` instead of `tensorflow.keras`
+ os.environ["TF_USE_LEGACY_KERAS"] = "true"
+ from mlrun.frameworks.tf_keras import TFKerasModelHandler
+ from tensorflow import keras
+
+ # Download the MobileNetV2 model:
+ model = keras.applications.mobilenet_v2.MobileNetV2()
+
+ # Initialize a model handler for logging the model:
+ model_handler = TFKerasModelHandler(
+ model_name=model_name, model=model, context=context
+ )
+
+ # Log the model:
+ model_handler.log()
+
+
+def _log_pytorch_model(context: mlrun.MLClientCtx, model_name: str):
+ """
+ Create and log a pytorch model - MobileNetV2.
+
+ :param context: The context to log to.
+ :param model_name: The model name to use.
+ """
+ import torchvision
+ from mlrun.frameworks.pytorch import PyTorchModelHandler
+
+ # Download the MobileNetV2 model:
+ model = torchvision.models.mobilenet_v2()
+
+ # Initialize a model handler for logging the model:
+ model_handler = PyTorchModelHandler(
+ model_name=model_name,
+ model=model,
+ model_class="mobilenet_v2",
+ modules_map={"torchvision.models": "mobilenet_v2"},
+ context=context,
+ )
+
+ # Log the model:
+ model_handler.log()
+
+
+@pytest.mark.skipif(
+ condition=not _validate_environment_variables(),
+ reason="Project's environment variables are not set",
+)
+def test_to_onnx_help(test_environment):
+ """
+ Test the 'to_onnx' handler, passing "help" in the 'framework_kwargs'.
+ """
+ artifact_path = test_environment
+
+ # Create the function:
+ log_model_function = mlrun.code_to_function(
+ filename="test_onnx_utils.py",
+ name="log_model",
+ project=PROJECT_NAME,
+ kind="job",
+ image="mlrun/ml-models",
+ )
+
+ # Run the function to log the model:
+ log_model_function.run(
+ handler="_log_pytorch_model",
+ output_path=artifact_path,
+ params={"model_name": MODEL_NAME},
+ local=True,
+ )
+
+ # Get artifact paths - construct from artifact_path and run structure
+ run_artifact_dir = os.path.join(artifact_path, "log-model--log-pytorch-model", "0")
+ model_path = os.path.join(run_artifact_dir, "model")
+ modules_map_path = os.path.join(run_artifact_dir, "model_modules_map.json.json")
+
+ # Import the ONNX Utils function:
+ onnx_function = mlrun.import_function("function.yaml", project=PROJECT_NAME)
+
+ # Run the function, passing "help" in 'framework_kwargs' and see that no exception was raised:
+ is_test_passed = True
+ try:
+ onnx_function.run(
+ handler="to_onnx",
+ output_path=artifact_path,
+ params={
+ # Take the logged model from the previous function.
+ "model_path": model_path,
+ "load_model_kwargs": {
+ "model_name": MODEL_NAME,
+ "model_class": "mobilenet_v2",
+ "modules_map": modules_map_path,
+ },
+ "framework_kwargs": "help",
+ },
+ local=True,
+ )
+ except TypeError as exception:
+ print(
+ f"The test failed, the help was not handled properly and raised the following error: {exception}"
+ )
+ is_test_passed = False
+
+ assert is_test_passed
+
+
+@pytest.mark.skipif(
+ condition=not _validate_environment_variables(),
+ reason="Project's environment variables are not set",
+)
+@pytest.mark.skipif(
+ condition=not _is_tf2onnx_available(),
+ reason="tf2onnx is not installed",
+)
+def test_tf_keras_to_onnx(test_environment):
+ """
+ Test the 'to_onnx' handler, giving it a tf.keras model.
+ """
+ artifact_path = test_environment
+
+ # Create the function:
+ log_model_function = mlrun.code_to_function(
+ filename="test_onnx_utils.py",
+ name="log_model",
+ project=PROJECT_NAME,
+ kind="job",
+ image="mlrun/ml-models",
+ )
+
+ # Run the function to log the model:
+ log_model_run = log_model_function.run(
+ handler="_log_tf_keras_model",
+ output_path=artifact_path,
+ params={"model_name": MODEL_NAME},
+ local=True,
+ )
+
+ # Import the ONNX Utils function:
+ onnx_function = mlrun.import_function("function.yaml", project=PROJECT_NAME)
+
+ # Run the function to convert our model to ONNX:
+ onnx_function_run = onnx_function.run(
+ handler="to_onnx",
+ output_path=artifact_path,
+ params={
+ # Take the logged model from the previous function.
+ "model_path": log_model_run.status.artifacts[0]["spec"]["target_path"],
+ "load_model_kwargs": {"model_name": MODEL_NAME},
+ "onnx_model_name": ONNX_MODEL_NAME,
+ },
+ local=True,
+ )
+
+ # Print the outputs list:
+ print(f"Produced outputs: {onnx_function_run.outputs}")
+
+ # Verify the '.onnx' model was created:
+ assert "model" in onnx_function_run.outputs
+
+
+@pytest.mark.skipif(
+ condition=not _validate_environment_variables(),
+ reason="Project's environment variables are not set",
+)
+def test_pytorch_to_onnx(test_environment):
+ """
+ Test the 'to_onnx' handler, giving it a pytorch model.
+ """
+ artifact_path = test_environment
+
+ # Create the function:
+ log_model_function = mlrun.code_to_function(
+ filename="test_onnx_utils.py",
+ name="log_model",
+ project=PROJECT_NAME,
+ kind="job",
+ image="mlrun/ml-models",
+ )
+
+ # Run the function to log the model:
+ log_model_run = log_model_function.run(
+ handler="_log_pytorch_model",
+ output_path=artifact_path,
+ params={"model_name": MODEL_NAME},
+ local=True,
+ )
+
+ # Import the ONNX Utils function:
+ onnx_function = mlrun.import_function("function.yaml", project=PROJECT_NAME)
+
+ # Get artifact paths - construct from artifact_path and run structure
+ run_artifact_dir = os.path.join(artifact_path, "log-model--log-pytorch-model", "0")
+ model_path = os.path.join(run_artifact_dir, "model")
+ modules_map_path = os.path.join(run_artifact_dir, "model_modules_map.json.json")
+
+ # Run the function to convert our model to ONNX:
+ onnx_function_run = onnx_function.run(
+ handler="to_onnx",
+ output_path=artifact_path,
+ params={
+ # Take the logged model from the previous function.
+ "model_path": model_path,
+ "load_model_kwargs": {
+ "model_name": MODEL_NAME,
+ "model_class": "mobilenet_v2",
+ "modules_map": modules_map_path,
+ },
+ "onnx_model_name": ONNX_MODEL_NAME,
+ "framework_kwargs": {"input_signature": [((32, 3, 224, 224), "float32")]},
+ },
+ local=True,
+ )
+
+ # Print the outputs list:
+ print(f"Produced outputs: {onnx_function_run.outputs}")
+
+ # Verify the '.onnx' model was created:
+ assert "model" in onnx_function_run.outputs
+
+
+@pytest.mark.skipif(
+ condition=not _validate_environment_variables(),
+ reason="Project's environment variables are not set",
+)
+def test_optimize_help(test_environment):
+ """
+ Test the 'optimize' handler, passing "help" in the 'optimizations'.
+ """
+ artifact_path = test_environment
+
+ # Import the ONNX Utils function:
+ onnx_function = mlrun.import_function("function.yaml", project=PROJECT_NAME)
+
+ # Run the function, passing "help" in 'optimizations' and see that no exception was raised:
+ is_test_passed = True
+ try:
+ onnx_function.run(
+ handler="optimize",
+ output_path=artifact_path,
+ params={
+ "model_path": "",
+ "optimizations": "help",
+ },
+ local=True,
+ )
+ except TypeError as exception:
+ print(
+ f"The test failed, the help was not handled properly and raised the following error: {exception}"
+ )
+ is_test_passed = False
+
+ assert is_test_passed
+
+
+@pytest.mark.skipif(
+ condition=not _validate_environment_variables(),
+ reason="Project's environment variables are not set",
+)
+def test_optimize(test_environment):
+ """
+ Test the 'optimize' handler, giving it a pytorch model converted to ONNX.
+ """
+ artifact_path = test_environment
+
+ # Create the function:
+ log_model_function = mlrun.code_to_function(
+ filename="test_onnx_utils.py",
+ name="log_model",
+ project=PROJECT_NAME,
+ kind="job",
+ image="mlrun/ml-models",
+ )
+
+ # Run the function to log the model:
+ log_model_function.run(
+ handler="_log_pytorch_model",
+ output_path=artifact_path,
+ params={"model_name": MODEL_NAME},
+ local=True,
+ )
+
+ # Get artifact paths - construct from artifact_path and run structure
+ run_artifact_dir = os.path.join(artifact_path, "log-model--log-pytorch-model", "0")
+ model_path = os.path.join(run_artifact_dir, "model")
+ modules_map_path = os.path.join(run_artifact_dir, "model_modules_map.json.json")
+
+ # Import the ONNX Utils function:
+ onnx_function = mlrun.import_function("function.yaml", project=PROJECT_NAME)
+
+ # Run the function to convert our model to ONNX:
+ onnx_function.run(
+ handler="to_onnx",
+ output_path=artifact_path,
+ params={
+ # Take the logged model from the previous function.
+ "model_path": model_path,
+ "load_model_kwargs": {
+ "model_name": MODEL_NAME,
+ "model_class": "mobilenet_v2",
+ "modules_map": modules_map_path,
+ },
+ "onnx_model_name": ONNX_MODEL_NAME,
+ "framework_kwargs": {"input_signature": [((32, 3, 224, 224), "float32")]},
+ },
+ local=True,
+ )
+
+ # Get the ONNX model path from the to_onnx run output
+ onnx_run_artifact_dir = os.path.join(
+ artifact_path, "onnx-utils-to-onnx", "0"
+ )
+ onnx_model_path = os.path.join(onnx_run_artifact_dir, "model")
+
+ # Run the function to optimize our model:
+ optimize_function_run = onnx_function.run(
+ handler="optimize",
+ output_path=artifact_path,
+ params={
+ # Take the logged model from the previous function.
+ "model_path": onnx_model_path,
+ "handler_init_kwargs": {"model_name": ONNX_MODEL_NAME},
+ "optimized_model_name": OPTIMIZED_ONNX_MODEL_NAME,
+ },
+ local=True,
+ )
+
+ # Print the outputs list:
+ print(f"Produced outputs: {optimize_function_run.outputs}")
+
+ # Verify the '.onnx' model was created:
+ assert "model" in optimize_function_run.outputs
diff --git a/functions/development/onnx_utils/1.4.0/static/documentation.html b/functions/development/onnx_utils/1.4.0/static/documentation.html
new file mode 100644
index 00000000..3faa1b78
--- /dev/null
+++ b/functions/development/onnx_utils/1.4.0/static/documentation.html
@@ -0,0 +1,277 @@
+
+
+
+
+
+
+
+onnx_utils package
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
handler_init_kwargs – Keyword arguments to pass to the ONNXModelHandler init method preloading.
+
optimizations – List of possible optimizations. To see what optimizations are available, pass “help”.
+If None, all the optimizations will be used. Defaulted to None.
+
fixed_point – Optimize the weights using fixed point. Defaulted to False.
+
optimized_model_name – The name of the optimized model. If None, the original model will be overridden.
+Defaulted to None.
load_model_kwargs – Keyword arguments to pass to the AutoMLRun.load_model method.
+
onnx_model_name – The name to use to log the converted ONNX model. If not given, the given model_name will
+be used with an additional suffix _onnx. Defaulted to None.
+
optimize_model – Whether to optimize the ONNX model using ‘onnxoptimizer’ before saving the model.
+Defaulted to True.
+
framework_kwargs – Additional arguments each framework may require to convert to ONNX. To get the doc string
+of the desired framework onnx conversion function, pass “help”.
context: mlrun.MLClientCtx - The MLRun function execution context
+
model_path: str - The model path store object.
+
onnx_model_name: str=None - The name to use to log the converted ONNX model. If not given, the given model_name will be used with an additional suffix _onnx. Defaulted to None.
+
optimize_model: bool=True - Whether to optimize the ONNX model using ‘onnxoptimizer’ before saving the model. Defaulted to True.
+
framework: str=None - The model’s framework. If None, it will be read from the ‘framework’ label of the model artifact provided. Defaulted to None.
+
framework_kwargs: Dict[str,Any]=None - Additional arguments each framework may require in order to convert to ONNX. To get the doc string of the desired framework onnx conversion function, pass “help”.
+
+
+
+
Supported keyword arguments (framework_kwargs) per framework:#
+
tensorflow.keras:
+
+
input_signature: List[Tuple[Tuple[int],str]]=None - A list of the input layers shape and data type properties. Expected to receive a list where each element is an input layer tuple. An input layer tuple is a tuple of:
+
+
[0] = Layer’s shape, a tuple of integers.
+
[1] = Layer’s data type, a mlrun.data_types.ValueType string.
+
+
If None, the input signature will be tried to be read automatically before converting to ONNX or from the model artifact if available. Defaulted to None.
+
+
+
torch:
+
+
input_signature: List[Tuple[Tuple[int],str]]=None - A list of the input layers shape and data type properties. Expected to receive a list where each element is an input layer tuple. An input layer tuple is a tuple of:
+
+
[0] = Layer’s shape, a tuple of integers.
+
[1] = Layer’s data type, a mlrun.data_types.ValueType string.
+
+
If None, the input signature will be read from the model artifact if available. Defaulted to None.
+
+
input_layers_names: List[str]=None - List of names to assign to the input nodes of the graph in order. All of the other parameters (inner layers) can be set as well by passing additional names in the list. The order is by the order of the parameters in the model. If None, the inputs will be read from the handler’s inputs. If its also None, it is defaulted to: “input_0”, “input_1”, …
+
output_layers_names: List[str]=None - List of names to assign to the output nodes of the graph in order. If None, the outputs will be read from the handler’s outputs. If its also None, it is defaulted to: “output_0” (for multiple outputs, this parameter must be provided).
+
paramdynamic_axes: Dict[str,Dict[int,str]]=None - If part of the input / output shape is dynamic, like (batch_size, 3, 32, 32) you can specify it by giving a dynamic axis to the input / output layer by its name as follows:
If provided, the ‘is_batched’ flag will be ignored. Defaulted to None.
+
+
is_batched: bool=True - Whether to include a batch size as the first axis in every input and output layer. Defaulted to True. Will be ignored if ‘dynamic_axes’ is provided.
We will use the PyTorch framework, a MobileNetV2 as our model and we will convert it to ONNX using the to_onnx handler.
+
1.2.1. First we will set the artifact path for our model to be saved in and choose the models names:
+
+
+
importos
+importtempfile
+# Use a temporary directory for model artifacts (safe cleanup):
+ARTIFACT_PATH=tempfile.mkdtemp()
+os.environ["MLRUN_ARTIFACT_PATH"]=ARTIFACT_PATH
+
+# Project name:
+PROJECT_NAME="onnx-utils"
+
+# Choose our model's name:
+MODEL_NAME="mobilenetv2"
+
+# Choose our ONNX version model's name:
+ONNX_MODEL_NAME="onnx_mobilenetv2"
+
+# Choose our optimized ONNX version model's name:
+OPTIMIZED_ONNX_MODEL_NAME="optimized_onnx_mobilenetv2"
+
+
+
+
+
1.2.2. Download the model from torchvision.models and log it with MLRun’s PyTorchModelHandler:
+
+
+
# mlrun: start-code
+
+
+
+
+
+
+
importtorchvision
+
+importmlrun
+frommlrun.frameworks.pytorchimportPyTorchModelHandler
+
+
+defget_model(context:mlrun.MLClientCtx,model_name:str):
+ # Download the MobileNetV2 model:
+ model=torchvision.models.mobilenet_v2()
+
+ # Initialize a model handler for logging the model:
+ model_handler=PyTorchModelHandler(
+ model_name=model_name,
+ model=model,
+ model_class="mobilenet_v2",
+ modules_map={"torchvision.models":"mobilenet_v2"},
+ context=context,
+ )
+
+ # Log the model:
+ model_handler.log()
+
+
+
+
+
+
+
# mlrun: end-code
+
+
+
+
+
+
+
importmlrun
+
+# Create or get the MLRun project:
+project=mlrun.get_or_create_project(PROJECT_NAME,context="./")
+
+# Create the function parsing this notebook's code using 'code_to_function':
+get_model_function=mlrun.code_to_function(
+ name="get_mobilenetv2",
+ project=PROJECT_NAME,
+ kind="job",
+ image="mlrun/ml-models"
+)
+
+# Run the function to log the model:
+get_model_run=get_model_function.run(
+ handler="get_model",
+ output_path=ARTIFACT_PATH,
+ params={
+ "model_name":MODEL_NAME
+ },
+ local=True
+)
+
+
+
+
+
> 2026-02-10 16:14:24,932 [info] Created and saved project: {"context":"./","from_template":null,"name":"onnx-utils","overwrite":false,"save":true}
+> 2026-02-10 16:14:24,933 [info] Project created successfully: {"project_name":"onnx-utils","stored_in_db":true}
+> 2026-02-10 16:14:31,659 [info] Storing function: {"db":null,"name":"get-mobilenetv2-get-model","uid":"7b9d1b54375b44e191d73685a382c910"}
+
> to track results use the .show() or .logs() methods or click here to open in UI
> 2026-02-10 16:14:34,427 [info] Run execution finished: {"name":"get-mobilenetv2-get-model","status":"completed"}
+
+
+
+
+
1.2.4. Import the onnx_utils MLRun function and run it:
+
+
+
# Import the ONNX function from the marketplace:
+onnx_utils_function=mlrun.import_function("hub://onnx_utils",project=PROJECT_NAME)
+
+# Construct the model path from the run directory structure:
+model_path=os.path.join(ARTIFACT_PATH,"get-mobilenetv2-get-model","0","model")
+modules_map_path=os.path.join(ARTIFACT_PATH,"get-mobilenetv2-get-model","0","mobilenetv2_modules_map.json.json")
+
+# Run the function to convert our model to ONNX:
+to_onnx_run=onnx_utils_function.run(
+ handler="to_onnx",
+ output_path=ARTIFACT_PATH,
+ params={
+ "model_name":MODEL_NAME,
+ "model_path":model_path,
+ "load_model_kwargs":{
+ "model_name":MODEL_NAME,
+ "model_class":"mobilenet_v2",
+ "modules_map":modules_map_path,
+ },
+ "onnx_model_name":ONNX_MODEL_NAME,
+ "optimize_model":False,# <- For optimizing it later in the demo, we mark the flag as False
+ "framework_kwargs":{"input_signature":[((32,3,224,224),"float32")]},
+ },
+ local=True
+)
+
> to track results use the .show() or .logs() methods or click here to open in UI
> 2026-02-10 16:14:53,862 [info] Run execution finished: {"name":"onnx-utils-to-onnx","status":"completed"}
+
+
+
+
+
1.2.5. Now we verify the ONNX model was created:
+
+
+
importos
+
+onnx_model_file=os.path.join(ARTIFACT_PATH,"onnx-utils-to-onnx","0","model","onnx_mobilenetv2.onnx")
+assertos.path.isfile(onnx_model_file),f"ONNX model not found at {onnx_model_file}"
+print(f"ONNX model created at: {onnx_model_file}")
+
+
+
+
+
ONNX model created at: /var/folders/rn/q8gs952n26982d36y50w_2rw0000gp/T/tmpvs5qvbxr/onnx-utils-to-onnx/0/model/onnx_mobilenetv2.onnx
+
context: mlrun.MLClientCtx - The MLRun function execution context
+
model_path: str - The model path store object.
+
optimizations: List[str]=None - List of possible optimizations. To see what optimizations are available, pass “help”. If None, all of the optimizations will be used. Defaulted to None.
+
fixed_point: bool=False - Optimize the weights using fixed point. Defaulted to False.
+
optimized_model_name: str=None - The name of the optimized model. If None, the original model will be overridden. Defaulted to None.
> to track results use the .show() or .logs() methods or click here to open in UI
> 2026-02-10 16:15:03,414 [info] Run execution finished: {"name":"onnx-utils-optimize","status":"completed"}
+
+
+
<mlrun.model.RunObject at 0x106148190>
+
+
+
+
+
2.2.2. And now our model was optimized. Let us verify:
+
+
+
optimized_model_file=os.path.join(ARTIFACT_PATH,"onnx-utils-optimize","0","model","optimized_onnx_mobilenetv2.onnx")
+assertos.path.isfile(optimized_model_file),f"Optimized ONNX model not found at {optimized_model_file}"
+print(f"Optimized ONNX model created at: {optimized_model_file}")
+
+
+
+
+
Optimized ONNX model created at: /var/folders/rn/q8gs952n26982d36y50w_2rw0000gp/T/tmpvs5qvbxr/onnx-utils-optimize/0/model/optimized_onnx_mobilenetv2.onnx
+
+
+
+
+
Lastly, run this code to clean up all generated files and directories:
+
+
+
importshutil
+
+# Clean up the temporary artifact directory:
+ifos.path.exists(ARTIFACT_PATH):
+ shutil.rmtree(ARTIFACT_PATH)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Contents
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/functions/development/onnx_utils/1.4.0/static/function.html b/functions/development/onnx_utils/1.4.0/static/function.html
new file mode 100644
index 00000000..d1b5444b
--- /dev/null
+++ b/functions/development/onnx_utils/1.4.0/static/function.html
@@ -0,0 +1,224 @@
+
+
+
+
+
+
+
+
+
+
+ Source
+
+
+
+
+
+
+metadata:
+ name: onnx-utils
+ tag: ''
+ categories:
+ - utilities
+ - deep-learning
+kind: job
+spec:
+ entry_points:
+ tf_keras_to_onnx:
+ name: tf_keras_to_onnx
+ parameters:
+ - name: model_handler
+ doc: An initialized TFKerasModelHandler with a loaded model to convert to
+ ONNX.
+ - name: onnx_model_name
+ type: str
+ doc: The name to use to log the converted ONNX model. If not given, the given
+ `model_name` will be used with an additional suffix `_onnx`. Defaulted to
+ None.
+ default: null
+ - name: optimize_model
+ type: bool
+ doc: Whether or not to optimize the ONNX model using 'onnxoptimizer' before
+ saving the model. Defaulted to True.
+ default: true
+ - name: input_signature
+ type: List[Tuple[Tuple[int], str]]
+ doc: 'A list of the input layers shape and data type properties. Expected
+ to receive a list where each element is an input layer tuple. An input layer
+ tuple is a tuple of: [0] = Layer''s shape, a tuple of integers. [1] = Layer''s
+ data type, a mlrun.data_types.ValueType string. If None, the input signature
+ will be tried to be read from the model artifact. Defaulted to None.'
+ default: null
+ doc: Convert a TF.Keras model to an ONNX model and log it back to MLRun as a
+ new model object.
+ lineno: 26
+ has_varargs: false
+ has_kwargs: false
+ pytorch_to_onnx:
+ name: pytorch_to_onnx
+ parameters:
+ - name: model_handler
+ doc: An initialized PyTorchModelHandler with a loaded model to convert to
+ ONNX.
+ - name: onnx_model_name
+ type: str
+ doc: The name to use to log the converted ONNX model. If not given, the given
+ `model_name` will be used with an additional suffix `_onnx`. Defaulted to
+ None.
+ default: null
+ - name: optimize_model
+ type: bool
+ doc: Whether or not to optimize the ONNX model using 'onnxoptimizer' before
+ saving the model. Defaulted to True.
+ default: true
+ - name: input_signature
+ type: List[Tuple[Tuple[int, ], str]]
+ doc: 'A list of the input layers shape and data type properties. Expected
+ to receive a list where each element is an input layer tuple. An input layer
+ tuple is a tuple of: [0] = Layer''s shape, a tuple of integers. [1] = Layer''s
+ data type, a mlrun.data_types.ValueType string. If None, the input signature
+ will be tried to be read from the model artifact. Defaulted to None.'
+ default: null
+ - name: input_layers_names
+ type: List[str]
+ doc: 'List of names to assign to the input nodes of the graph in order. All
+ of the other parameters (inner layers) can be set as well by passing additional
+ names in the list. The order is by the order of the parameters in the model.
+ If None, the inputs will be read from the handler''s inputs. If its also
+ None, it is defaulted to: "input_0", "input_1", ...'
+ default: null
+ - name: output_layers_names
+ type: List[str]
+ doc: 'List of names to assign to the output nodes of the graph in order. If
+ None, the outputs will be read from the handler''s outputs. If its also
+ None, it is defaulted to: "output_0" (for multiple outputs, this parameter
+ must be provided).'
+ default: null
+ - name: dynamic_axes
+ type: Dict[str, Dict[int, str]]
+ doc: 'If part of the input / output shape is dynamic, like (batch_size, 3,
+ 32, 32) you can specify it by giving a dynamic axis to the input / output
+ layer by its name as follows: { "input layer name": {0: "batch_size"}, "output
+ layer name": {0: "batch_size"}, } If provided, the ''is_batched'' flag will
+ be ignored. Defaulted to None.'
+ default: null
+ - name: is_batched
+ type: bool
+ doc: Whether to include a batch size as the first axis in every input and
+ output layer. Defaulted to True. Will be ignored if 'dynamic_axes' is provided.
+ default: true
+ doc: Convert a PyTorch model to an ONNX model and log it back to MLRun as a
+ new model object.
+ lineno: 81
+ has_varargs: false
+ has_kwargs: false
+ to_onnx:
+ name: to_onnx
+ parameters:
+ - name: context
+ type: MLClientCtx
+ doc: The MLRun function execution context
+ - name: model_path
+ type: str
+ doc: The model path store object.
+ - name: load_model_kwargs
+ type: dict
+ doc: Keyword arguments to pass to the `AutoMLRun.load_model` method.
+ default: null
+ - name: onnx_model_name
+ type: str
+ doc: The name to use to log the converted ONNX model. If not given, the given
+ `model_name` will be used with an additional suffix `_onnx`. Defaulted to
+ None.
+ default: null
+ - name: optimize_model
+ type: bool
+ doc: Whether to optimize the ONNX model using 'onnxoptimizer' before saving
+ the model. Defaulted to True.
+ default: true
+ - name: framework_kwargs
+ type: Dict[str, Any]
+ doc: Additional arguments each framework may require to convert to ONNX. To
+ get the doc string of the desired framework onnx conversion function, pass
+ "help".
+ default: null
+ doc: Convert the given model to an ONNX model.
+ lineno: 160
+ has_varargs: false
+ has_kwargs: false
+ optimize:
+ name: optimize
+ parameters:
+ - name: context
+ type: MLClientCtx
+ doc: The MLRun function execution context.
+ - name: model_path
+ type: str
+ doc: Path to the ONNX model object.
+ - name: handler_init_kwargs
+ type: dict
+ doc: Keyword arguments to pass to the `ONNXModelHandler` init method preloading.
+ default: null
+ - name: optimizations
+ type: List[str]
+ doc: List of possible optimizations. To see what optimizations are available,
+ pass "help". If None, all the optimizations will be used. Defaulted to None.
+ default: null
+ - name: fixed_point
+ type: bool
+ doc: Optimize the weights using fixed point. Defaulted to False.
+ default: false
+ - name: optimized_model_name
+ type: str
+ doc: The name of the optimized model. If None, the original model will be
+ overridden. Defaulted to None.
+ default: null
+ doc: Optimize the given ONNX model.
+ lineno: 224
+ has_varargs: false
+ has_kwargs: false
+ image: ''
+ default_handler: to_onnx
+ allow_empty_resources: true
+ command: ''
+ disable_auto_mount: false
+ description: ONNX intigration in MLRun, some utils functions for the ONNX framework,
+ optimizing and converting models from different framework to ONNX using MLRun.
+ build:
+ functionSourceCode: IyBDb3B5cmlnaHQgMjAxOSBJZ3VhemlvCiMKIyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiMgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiMKIyAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiMKIyBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiMgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KIyBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiMgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiMKZnJvbSB0eXBpbmcgaW1wb3J0IEFueSwgQ2FsbGFibGUsIERpY3QsIExpc3QsIFR1cGxlCgppbXBvcnQgbWxydW4KCgpjbGFzcyBfVG9PTk5YQ29udmVyc2lvbnM6CiAgICAiIiIKICAgIEFuIE9OTlggY29udmVyc2lvbiBmdW5jdGlvbnMgbGlicmFyeSBjbGFzcy4KICAgICIiIgoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiB0Zl9rZXJhc190b19vbm54KAogICAgICAgIG1vZGVsX2hhbmRsZXIsCiAgICAgICAgb25ueF9tb2RlbF9uYW1lOiBzdHIgPSBOb25lLAogICAgICAgIG9wdGltaXplX21vZGVsOiBib29sID0gVHJ1ZSwKICAgICAgICBpbnB1dF9zaWduYXR1cmU6IExpc3RbVHVwbGVbVHVwbGVbaW50XSwgc3RyXV0gPSBOb25lLAogICAgKToKICAgICAgICAiIiIKICAgICAgICBDb252ZXJ0IGEgVEYuS2VyYXMgbW9kZWwgdG8gYW4gT05OWCBtb2RlbCBhbmQgbG9nIGl0IGJhY2sgdG8gTUxSdW4gYXMgYSBuZXcgbW9kZWwgb2JqZWN0LgoKICAgICAgICA6cGFyYW0gbW9kZWxfaGFuZGxlcjogICBBbiBpbml0aWFsaXplZCBURktlcmFzTW9kZWxIYW5kbGVyIHdpdGggYSBsb2FkZWQgbW9kZWwgdG8gY29udmVydCB0byBPTk5YLgogICAgICAgIDpwYXJhbSBvbm54X21vZGVsX25hbWU6IFRoZSBuYW1lIHRvIHVzZSB0byBsb2cgdGhlIGNvbnZlcnRlZCBPTk5YIG1vZGVsLiBJZiBub3QgZ2l2ZW4sIHRoZSBnaXZlbiBgbW9kZWxfbmFtZWAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aWxsIGJlIHVzZWQgd2l0aCBhbiBhZGRpdGlvbmFsIHN1ZmZpeCBgX29ubnhgLiBEZWZhdWx0ZWQgdG8gTm9uZS4KICAgICAgICA6cGFyYW0gb3B0aW1pemVfbW9kZWw6ICBXaGV0aGVyIG9yIG5vdCB0byBvcHRpbWl6ZSB0aGUgT05OWCBtb2RlbCB1c2luZyAnb25ueG9wdGltaXplcicgYmVmb3JlIHNhdmluZyB0aGUgbW9kZWwuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVmYXVsdGVkIHRvIFRydWUuCiAgICAgICAgOnBhcmFtIGlucHV0X3NpZ25hdHVyZTogQSBsaXN0IG9mIHRoZSBpbnB1dCBsYXllcnMgc2hhcGUgYW5kIGRhdGEgdHlwZSBwcm9wZXJ0aWVzLiBFeHBlY3RlZCB0byByZWNlaXZlIGEgbGlzdAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoZXJlIGVhY2ggZWxlbWVudCBpcyBhbiBpbnB1dCBsYXllciB0dXBsZS4gQW4gaW5wdXQgbGF5ZXIgdHVwbGUgaXMgYSB0dXBsZSBvZjoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbMF0gPSBMYXllcidzIHNoYXBlLCBhIHR1cGxlIG9mIGludGVnZXJzLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFsxXSA9IExheWVyJ3MgZGF0YSB0eXBlLCBhIG1scnVuLmRhdGFfdHlwZXMuVmFsdWVUeXBlIHN0cmluZy4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJZiBOb25lLCB0aGUgaW5wdXQgc2lnbmF0dXJlIHdpbGwgYmUgdHJpZWQgdG8gYmUgcmVhZCBmcm9tIHRoZSBtb2RlbCBhcnRpZmFjdC4gRGVmYXVsdGVkCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG8gTm9uZS4KICAgICAgICAiIiIKICAgICAgICAjIEltcG9ydCB0aGUgZnJhbWV3b3JrIGFuZCBoYW5kbGVyOgogICAgICAgIGltcG9ydCB0ZW5zb3JmbG93IGFzIHRmCiAgICAgICAgZnJvbSBtbHJ1bi5mcmFtZXdvcmtzLnRmX2tlcmFzIGltcG9ydCBURktlcmFzVXRpbHMKCiAgICAgICAgIyBDaGVjayB0aGUgZ2l2ZW4gJ2lucHV0X3NpZ25hdHVyZScgcGFyYW1ldGVyOgogICAgICAgIGlmIGlucHV0X3NpZ25hdHVyZSBpcyBOb25lOgogICAgICAgICAgICAjIFJlYWQgdGhlIGlucHV0cyBmcm9tIHRoZSBtb2RlbDoKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgbW9kZWxfaGFuZGxlci5yZWFkX2lucHV0c19mcm9tX21vZGVsKCkKICAgICAgICAgICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlcnJvcjoKICAgICAgICAgICAgICAgIHJhaXNlIG1scnVuLmVycm9ycy5NTFJ1blJ1bnRpbWVFcnJvcigKICAgICAgICAgICAgICAgICAgICBmIlBsZWFzZSBwcm92aWRlIHRoZSAnaW5wdXRfc2lnbmF0dXJlJyBwYXJhbWV0ZXIuIFRoZSBmdW5jdGlvbiB0cmllZCByZWFkaW5nIHRoZSBpbnB1dCBsYXllcnMgIgogICAgICAgICAgICAgICAgICAgIGYiaW5mb3JtYXRpb24gYXV0b21hdGljYWxseSBidXQgZmFpbGVkIHdpdGggdGhlIGZvbGxvd2luZyBlcnJvcjoge2Vycm9yfSIKICAgICAgICAgICAgICAgICkKICAgICAgICBlbHNlOgogICAgICAgICAgICAjIFBhcnNlIHRoZSAnaW5wdXRfc2lnbmF0dXJlJyBwYXJhbWV0ZXI6CiAgICAgICAgICAgIGlucHV0X3NpZ25hdHVyZSA9IFsKICAgICAgICAgICAgICAgIHRmLlRlbnNvclNwZWMoCiAgICAgICAgICAgICAgICAgICAgc2hhcGU9c2hhcGUsCiAgICAgICAgICAgICAgICAgICAgZHR5cGU9VEZLZXJhc1V0aWxzLmNvbnZlcnRfdmFsdWVfdHlwZV90b190Zl9kdHlwZSgKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVfdHlwZT12YWx1ZV90eXBlCiAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIGZvciAoc2hhcGUsIHZhbHVlX3R5cGUpIGluIGlucHV0X3NpZ25hdHVyZQogICAgICAgICAgICBdCgogICAgICAgICMgQ29udmVydCB0byBPTk5YOgogICAgICAgIG1vZGVsX2hhbmRsZXIudG9fb25ueCgKICAgICAgICAgICAgbW9kZWxfbmFtZT1vbm54X21vZGVsX25hbWUsCiAgICAgICAgICAgIGlucHV0X3NpZ25hdHVyZT1pbnB1dF9zaWduYXR1cmUsCiAgICAgICAgICAgIG9wdGltaXplPW9wdGltaXplX21vZGVsLAogICAgICAgICkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgcHl0b3JjaF90b19vbm54KAogICAgICAgIG1vZGVsX2hhbmRsZXIsCiAgICAgICAgb25ueF9tb2RlbF9uYW1lOiBzdHIgPSBOb25lLAogICAgICAgIG9wdGltaXplX21vZGVsOiBib29sID0gVHJ1ZSwKICAgICAgICBpbnB1dF9zaWduYXR1cmU6IExpc3RbVHVwbGVbVHVwbGVbaW50LCAuLi5dLCBzdHJdXSA9IE5vbmUsCiAgICAgICAgaW5wdXRfbGF5ZXJzX25hbWVzOiBMaXN0W3N0cl0gPSBOb25lLAogICAgICAgIG91dHB1dF9sYXllcnNfbmFtZXM6IExpc3Rbc3RyXSA9IE5vbmUsCiAgICAgICAgZHluYW1pY19heGVzOiBEaWN0W3N0ciwgRGljdFtpbnQsIHN0cl1dID0gTm9uZSwKICAgICAgICBpc19iYXRjaGVkOiBib29sID0gVHJ1ZSwKICAgICk6CiAgICAgICAgIiIiCiAgICAgICAgQ29udmVydCBhIFB5VG9yY2ggbW9kZWwgdG8gYW4gT05OWCBtb2RlbCBhbmQgbG9nIGl0IGJhY2sgdG8gTUxSdW4gYXMgYSBuZXcgbW9kZWwgb2JqZWN0LgoKICAgICAgICA6cGFyYW0gbW9kZWxfaGFuZGxlcjogICAgICAgQW4gaW5pdGlhbGl6ZWQgUHlUb3JjaE1vZGVsSGFuZGxlciB3aXRoIGEgbG9hZGVkIG1vZGVsIHRvIGNvbnZlcnQgdG8gT05OWC4KICAgICAgICA6cGFyYW0gb25ueF9tb2RlbF9uYW1lOiAgICAgVGhlIG5hbWUgdG8gdXNlIHRvIGxvZyB0aGUgY29udmVydGVkIE9OTlggbW9kZWwuIElmIG5vdCBnaXZlbiwgdGhlIGdpdmVuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBtb2RlbF9uYW1lYCB3aWxsIGJlIHVzZWQgd2l0aCBhbiBhZGRpdGlvbmFsIHN1ZmZpeCBgX29ubnhgLiBEZWZhdWx0ZWQgdG8gTm9uZS4KICAgICAgICA6cGFyYW0gb3B0aW1pemVfbW9kZWw6ICAgICAgV2hldGhlciBvciBub3QgdG8gb3B0aW1pemUgdGhlIE9OTlggbW9kZWwgdXNpbmcgJ29ubnhvcHRpbWl6ZXInIGJlZm9yZSBzYXZpbmcgdGhlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLiBEZWZhdWx0ZWQgdG8gVHJ1ZS4KICAgICAgICA6cGFyYW0gaW5wdXRfc2lnbmF0dXJlOiAgICAgQSBsaXN0IG9mIHRoZSBpbnB1dCBsYXllcnMgc2hhcGUgYW5kIGRhdGEgdHlwZSBwcm9wZXJ0aWVzLiBFeHBlY3RlZCB0byByZWNlaXZlIGEKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdCB3aGVyZSBlYWNoIGVsZW1lbnQgaXMgYW4gaW5wdXQgbGF5ZXIgdHVwbGUuIEFuIGlucHV0IGxheWVyIHR1cGxlIGlzIGEgdHVwbGUgb2Y6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFswXSA9IExheWVyJ3Mgc2hhcGUsIGEgdHVwbGUgb2YgaW50ZWdlcnMuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFsxXSA9IExheWVyJ3MgZGF0YSB0eXBlLCBhIG1scnVuLmRhdGFfdHlwZXMuVmFsdWVUeXBlIHN0cmluZy4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSWYgTm9uZSwgdGhlIGlucHV0IHNpZ25hdHVyZSB3aWxsIGJlIHRyaWVkIHRvIGJlIHJlYWQgZnJvbSB0aGUgbW9kZWwgYXJ0aWZhY3QuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlZmF1bHRlZCB0byBOb25lLgogICAgICAgIDpwYXJhbSBpbnB1dF9sYXllcnNfbmFtZXM6ICBMaXN0IG9mIG5hbWVzIHRvIGFzc2lnbiB0byB0aGUgaW5wdXQgbm9kZXMgb2YgdGhlIGdyYXBoIGluIG9yZGVyLiBBbGwgb2YgdGhlIG90aGVyCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtZXRlcnMgKGlubmVyIGxheWVycykgY2FuIGJlIHNldCBhcyB3ZWxsIGJ5IHBhc3NpbmcgYWRkaXRpb25hbCBuYW1lcyBpbiB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdC4gVGhlIG9yZGVyIGlzIGJ5IHRoZSBvcmRlciBvZiB0aGUgcGFyYW1ldGVycyBpbiB0aGUgbW9kZWwuIElmIE5vbmUsIHRoZSBpbnB1dHMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lsbCBiZSByZWFkIGZyb20gdGhlIGhhbmRsZXIncyBpbnB1dHMuIElmIGl0cyBhbHNvIE5vbmUsIGl0IGlzIGRlZmF1bHRlZCB0bzoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImlucHV0XzAiLCAiaW5wdXRfMSIsIC4uLgogICAgICAgIDpwYXJhbSBvdXRwdXRfbGF5ZXJzX25hbWVzOiBMaXN0IG9mIG5hbWVzIHRvIGFzc2lnbiB0byB0aGUgb3V0cHV0IG5vZGVzIG9mIHRoZSBncmFwaCBpbiBvcmRlci4gSWYgTm9uZSwgdGhlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dHMgd2lsbCBiZSByZWFkIGZyb20gdGhlIGhhbmRsZXIncyBvdXRwdXRzLiBJZiBpdHMgYWxzbyBOb25lLCBpdCBpcyBkZWZhdWx0ZWQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG86ICJvdXRwdXRfMCIgKGZvciBtdWx0aXBsZSBvdXRwdXRzLCB0aGlzIHBhcmFtZXRlciBtdXN0IGJlIHByb3ZpZGVkKS4KICAgICAgICA6cGFyYW0gZHluYW1pY19heGVzOiAgICAgICAgSWYgcGFydCBvZiB0aGUgaW5wdXQgLyBvdXRwdXQgc2hhcGUgaXMgZHluYW1pYywgbGlrZSAoYmF0Y2hfc2l6ZSwgMywgMzIsIDMyKSB5b3UgY2FuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNpZnkgaXQgYnkgZ2l2aW5nIGEgZHluYW1pYyBheGlzIHRvIHRoZSBpbnB1dCAvIG91dHB1dCBsYXllciBieSBpdHMgbmFtZSBhcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb2xsb3dzOiB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaW5wdXQgbGF5ZXIgbmFtZSI6IHswOiAiYmF0Y2hfc2l6ZSJ9LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm91dHB1dCBsYXllciBuYW1lIjogezA6ICJiYXRjaF9zaXplIn0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSWYgcHJvdmlkZWQsIHRoZSAnaXNfYmF0Y2hlZCcgZmxhZyB3aWxsIGJlIGlnbm9yZWQuIERlZmF1bHRlZCB0byBOb25lLgogICAgICAgIDpwYXJhbSBpc19iYXRjaGVkOiAgICAgICAgICBXaGV0aGVyIHRvIGluY2x1ZGUgYSBiYXRjaCBzaXplIGFzIHRoZSBmaXJzdCBheGlzIGluIGV2ZXJ5IGlucHV0IGFuZCBvdXRwdXQgbGF5ZXIuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlZmF1bHRlZCB0byBUcnVlLiBXaWxsIGJlIGlnbm9yZWQgaWYgJ2R5bmFtaWNfYXhlcycgaXMgcHJvdmlkZWQuCiAgICAgICAgIiIiCiAgICAgICAgIyBJbXBvcnQgdGhlIGZyYW1ld29yayBhbmQgaGFuZGxlcjoKICAgICAgICBpbXBvcnQgdG9yY2gKICAgICAgICBmcm9tIG1scnVuLmZyYW1ld29ya3MucHl0b3JjaCBpbXBvcnQgUHlUb3JjaFV0aWxzCgogICAgICAgICMgUGFyc2UgdGhlICdpbnB1dF9zaWduYXR1cmUnIHBhcmFtZXRlcjoKICAgICAgICBpZiBpbnB1dF9zaWduYXR1cmUgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIGlucHV0X3NpZ25hdHVyZSA9IHR1cGxlKAogICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgIHRvcmNoLnplcm9zKAogICAgICAgICAgICAgICAgICAgICAgICBzaXplPXNoYXBlLAogICAgICAgICAgICAgICAgICAgICAgICBkdHlwZT1QeVRvcmNoVXRpbHMuY29udmVydF92YWx1ZV90eXBlX3RvX3RvcmNoX2R0eXBlKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVfdHlwZT12YWx1ZV90eXBlCiAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgIGZvciAoc2hhcGUsIHZhbHVlX3R5cGUpIGluIGlucHV0X3NpZ25hdHVyZQogICAgICAgICAgICAgICAgXQogICAgICAgICAgICApCgogICAgICAgICMgQ29udmVydCB0byBPTk5YOgogICAgICAgIG1vZGVsX2hhbmRsZXIudG9fb25ueCgKICAgICAgICAgICAgbW9kZWxfbmFtZT1vbm54X21vZGVsX25hbWUsCiAgICAgICAgICAgIGlucHV0X3NhbXBsZT1pbnB1dF9zaWduYXR1cmUsCiAgICAgICAgICAgIG9wdGltaXplPW9wdGltaXplX21vZGVsLAogICAgICAgICAgICBpbnB1dF9sYXllcnNfbmFtZXM9aW5wdXRfbGF5ZXJzX25hbWVzLAogICAgICAgICAgICBvdXRwdXRfbGF5ZXJzX25hbWVzPW91dHB1dF9sYXllcnNfbmFtZXMsCiAgICAgICAgICAgIGR5bmFtaWNfYXhlcz1keW5hbWljX2F4ZXMsCiAgICAgICAgICAgIGlzX2JhdGNoZWQ9aXNfYmF0Y2hlZCwKICAgICAgICApCgoKIyBNYXAgZm9yIGdldHRpbmcgdGhlIGNvbnZlcnNpb24gZnVuY3Rpb24gYWNjb3JkaW5nIHRvIHRoZSBwcm92aWRlZCBmcmFtZXdvcms6Cl9DT05WRVJTSU9OX01BUCA9IHsKICAgICJ0ZW5zb3JmbG93LmtlcmFzIjogX1RvT05OWENvbnZlcnNpb25zLnRmX2tlcmFzX3RvX29ubngsCiAgICAidG9yY2giOiBfVG9PTk5YQ29udmVyc2lvbnMucHl0b3JjaF90b19vbm54LAp9ICAjIHR5cGU6IERpY3Rbc3RyLCBDYWxsYWJsZV0KCgpkZWYgdG9fb25ueCgKICAgIGNvbnRleHQ6IG1scnVuLk1MQ2xpZW50Q3R4LAogICAgbW9kZWxfcGF0aDogc3RyLAogICAgbG9hZF9tb2RlbF9rd2FyZ3M6IGRpY3QgPSBOb25lLAogICAgb25ueF9tb2RlbF9uYW1lOiBzdHIgPSBOb25lLAogICAgb3B0aW1pemVfbW9kZWw6IGJvb2wgPSBUcnVlLAogICAgZnJhbWV3b3JrX2t3YXJnczogRGljdFtzdHIsIEFueV0gPSBOb25lLAopOgogICAgIiIiCiAgICBDb252ZXJ0IHRoZSBnaXZlbiBtb2RlbCB0byBhbiBPTk5YIG1vZGVsLgoKICAgIDpwYXJhbSBjb250ZXh0OiAgICAgICAgICAgVGhlIE1MUnVuIGZ1bmN0aW9uIGV4ZWN1dGlvbiBjb250ZXh0CiAgICA6cGFyYW0gbW9kZWxfcGF0aDogICAgICAgIFRoZSBtb2RlbCBwYXRoIHN0b3JlIG9iamVjdC4KICAgIDpwYXJhbSBsb2FkX21vZGVsX2t3YXJnczogS2V5d29yZCBhcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgYEF1dG9NTFJ1bi5sb2FkX21vZGVsYCBtZXRob2QuCiAgICA6cGFyYW0gb25ueF9tb2RlbF9uYW1lOiAgIFRoZSBuYW1lIHRvIHVzZSB0byBsb2cgdGhlIGNvbnZlcnRlZCBPTk5YIG1vZGVsLiBJZiBub3QgZ2l2ZW4sIHRoZSBnaXZlbiBgbW9kZWxfbmFtZWAgd2lsbAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZSB1c2VkIHdpdGggYW4gYWRkaXRpb25hbCBzdWZmaXggYF9vbm54YC4gRGVmYXVsdGVkIHRvIE5vbmUuCiAgICA6cGFyYW0gb3B0aW1pemVfbW9kZWw6ICAgIFdoZXRoZXIgdG8gb3B0aW1pemUgdGhlIE9OTlggbW9kZWwgdXNpbmcgJ29ubnhvcHRpbWl6ZXInIGJlZm9yZSBzYXZpbmcgdGhlIG1vZGVsLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEZWZhdWx0ZWQgdG8gVHJ1ZS4KICAgIDpwYXJhbSBmcmFtZXdvcmtfa3dhcmdzOiAgQWRkaXRpb25hbCBhcmd1bWVudHMgZWFjaCBmcmFtZXdvcmsgbWF5IHJlcXVpcmUgdG8gY29udmVydCB0byBPTk5YLiBUbyBnZXQgdGhlIGRvYyBzdHJpbmcKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2YgdGhlIGRlc2lyZWQgZnJhbWV3b3JrIG9ubnggY29udmVyc2lvbiBmdW5jdGlvbiwgcGFzcyAiaGVscCIuCiAgICAiIiIKICAgIGZyb20gbWxydW4uZnJhbWV3b3Jrcy5hdXRvX21scnVuLmF1dG9fbWxydW4gaW1wb3J0IEF1dG9NTFJ1bgoKICAgICMgR2V0IGEgbW9kZWwgaGFuZGxlciBvZiB0aGUgcmVxdWlyZWQgZnJhbWV3b3JrOgogICAgbG9hZF9tb2RlbF9rd2FyZ3MgPSBsb2FkX21vZGVsX2t3YXJncyBvciB7fQogICAgbW9kZWxfaGFuZGxlciA9IEF1dG9NTFJ1bi5sb2FkX21vZGVsKAogICAgICAgIG1vZGVsX3BhdGg9bW9kZWxfcGF0aCwgY29udGV4dD1jb250ZXh0LCAqKmxvYWRfbW9kZWxfa3dhcmdzCiAgICApCgogICAgIyBHZXQgdGhlIG1vZGVsJ3MgZnJhbWV3b3JrOgogICAgZnJhbWV3b3JrID0gbW9kZWxfaGFuZGxlci5GUkFNRVdPUktfTkFNRQoKICAgICMgVXNlIHRoZSBjb252ZXJzaW9uIG1hcCB0byBnZXQgdGhlIHNwZWNpZmljIGZyYW1ld29yayB0byBvbm54IGNvbnZlcnNpb246CiAgICBpZiBmcmFtZXdvcmsgbm90IGluIF9DT05WRVJTSU9OX01BUDoKICAgICAgICByYWlzZSBtbHJ1bi5lcnJvcnMuTUxSdW5JbnZhbGlkQXJndW1lbnRFcnJvcigKICAgICAgICAgICAgZiJUaGUgZm9sbG93aW5nIGZyYW1ld29yazogJ3tmcmFtZXdvcmt9JywgaGFzIG5vIE9OTlggY29udmVyc2lvbi4iCiAgICAgICAgKQogICAgY29udmVyc2lvbl9mdW5jdGlvbiA9IF9DT05WRVJTSU9OX01BUFtmcmFtZXdvcmtdCgogICAgIyBDaGVjayBpZiBuZWVkZWQgdG8gcHJpbnQgdGhlIGZ1bmN0aW9uJ3MgZG9jIHN0cmluZyAoImhlbHAiIGlzIHBhc3NlZCk6CiAgICBpZiBmcmFtZXdvcmtfa3dhcmdzID09ICJoZWxwIjoKICAgICAgICBwcmludChjb252ZXJzaW9uX2Z1bmN0aW9uLl9fZG9jX18pCiAgICAgICAgcmV0dXJuCgogICAgIyBTZXQgdGhlIGRlZmF1bHQgZW1wdHkgZnJhbWV3b3JrIGt3YXJncyBpZiBuZWVkZWQ6CiAgICBpZiBmcmFtZXdvcmtfa3dhcmdzIGlzIE5vbmU6CiAgICAgICAgZnJhbWV3b3JrX2t3YXJncyA9IHt9CgogICAgIyBSdW4gdGhlIGNvbnZlcnNpb246CiAgICB0cnk6CiAgICAgICAgY29udmVyc2lvbl9mdW5jdGlvbigKICAgICAgICAgICAgbW9kZWxfaGFuZGxlcj1tb2RlbF9oYW5kbGVyLAogICAgICAgICAgICBvbm54X21vZGVsX25hbWU9b25ueF9tb2RlbF9uYW1lLAogICAgICAgICAgICBvcHRpbWl6ZV9tb2RlbD1vcHRpbWl6ZV9tb2RlbCwKICAgICAgICAgICAgKipmcmFtZXdvcmtfa3dhcmdzLAogICAgICAgICkKICAgIGV4Y2VwdCBUeXBlRXJyb3IgYXMgZXhjZXB0aW9uOgogICAgICAgIHJhaXNlIG1scnVuLmVycm9ycy5NTFJ1bkludmFsaWRBcmd1bWVudEVycm9yKAogICAgICAgICAgICBmIkVSUk9SOiBBIFR5cGVFcnJvciBleGNlcHRpb24gd2FzIHJhaXNlZCBkdXJpbmcgdGhlIGNvbnZlcnNpb246XG57ZXhjZXB0aW9ufS4gIgogICAgICAgICAgICBmIlBsZWFzZSByZWFkIHRoZSB7ZnJhbWV3b3JrfSBmcmFtZXdvcmsgY29udmVyc2lvbiBmdW5jdGlvbiBkb2Mgc3RyaW5nIGJ5IHBhc3NpbmcgJ2hlbHAnIGluIHRoZSAiCiAgICAgICAgICAgIGYiJ2ZyYW1ld29ya19rd2FyZ3MnIGRpY3Rpb25hcnkgcGFyYW1ldGVyLiIKICAgICAgICApCgoKZGVmIG9wdGltaXplKAogICAgY29udGV4dDogbWxydW4uTUxDbGllbnRDdHgsCiAgICBtb2RlbF9wYXRoOiBzdHIsCiAgICBoYW5kbGVyX2luaXRfa3dhcmdzOiBkaWN0ID0gTm9uZSwKICAgIG9wdGltaXphdGlvbnM6IExpc3Rbc3RyXSA9IE5vbmUsCiAgICBmaXhlZF9wb2ludDogYm9vbCA9IEZhbHNlLAogICAgb3B0aW1pemVkX21vZGVsX25hbWU6IHN0ciA9IE5vbmUsCik6CiAgICAiIiIKICAgIE9wdGltaXplIHRoZSBnaXZlbiBPTk5YIG1vZGVsLgoKICAgIDpwYXJhbSBjb250ZXh0OiAgICAgICAgICAgICAgVGhlIE1MUnVuIGZ1bmN0aW9uIGV4ZWN1dGlvbiBjb250ZXh0LgogICAgOnBhcmFtIG1vZGVsX3BhdGg6ICAgICAgICAgICBQYXRoIHRvIHRoZSBPTk5YIG1vZGVsIG9iamVjdC4KICAgIDpwYXJhbSBoYW5kbGVyX2luaXRfa3dhcmdzOiAgS2V5d29yZCBhcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgYE9OTlhNb2RlbEhhbmRsZXJgIGluaXQgbWV0aG9kIHByZWxvYWRpbmcuCiAgICA6cGFyYW0gb3B0aW1pemF0aW9uczogICAgICAgIExpc3Qgb2YgcG9zc2libGUgb3B0aW1pemF0aW9ucy4gVG8gc2VlIHdoYXQgb3B0aW1pemF0aW9ucyBhcmUgYXZhaWxhYmxlLCBwYXNzICJoZWxwIi4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSWYgTm9uZSwgYWxsIHRoZSBvcHRpbWl6YXRpb25zIHdpbGwgYmUgdXNlZC4gRGVmYXVsdGVkIHRvIE5vbmUuCiAgICA6cGFyYW0gZml4ZWRfcG9pbnQ6ICAgICAgICAgIE9wdGltaXplIHRoZSB3ZWlnaHRzIHVzaW5nIGZpeGVkIHBvaW50LiBEZWZhdWx0ZWQgdG8gRmFsc2UuCiAgICA6cGFyYW0gb3B0aW1pemVkX21vZGVsX25hbWU6IFRoZSBuYW1lIG9mIHRoZSBvcHRpbWl6ZWQgbW9kZWwuIElmIE5vbmUsIHRoZSBvcmlnaW5hbCBtb2RlbCB3aWxsIGJlIG92ZXJyaWRkZW4uCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlZmF1bHRlZCB0byBOb25lLgogICAgIiIiCiAgICAjIEltcG9ydCB0aGUgbW9kZWwgaGFuZGxlcjoKICAgIGltcG9ydCBvbm54b3B0aW1pemVyCiAgICBmcm9tIG1scnVuLmZyYW1ld29ya3Mub25ueCBpbXBvcnQgT05OWE1vZGVsSGFuZGxlcgoKICAgICMgQ2hlY2sgaWYgbmVlZGVkIHRvIHByaW50IHRoZSBhdmFpbGFibGUgb3B0aW1pemF0aW9ucyAoImhlbHAiIGlzIHBhc3NlZCk6CiAgICBpZiBvcHRpbWl6YXRpb25zID09ICJoZWxwIjoKICAgICAgICBhdmFpbGFibGVfcGFzc2VzID0gIlxuKiAiLmpvaW4ob25ueG9wdGltaXplci5nZXRfYXZhaWxhYmxlX3Bhc3NlcygpKQogICAgICAgIHByaW50KGYiVGhlIGF2YWlsYWJsZSBvcHRpbWl6YXRpb25zIGFyZTpcbioge2F2YWlsYWJsZV9wYXNzZXN9IikKICAgICAgICByZXR1cm4KCiAgICAjIENyZWF0ZSB0aGUgbW9kZWwgaGFuZGxlcjoKICAgIGhhbmRsZXJfaW5pdF9rd2FyZ3MgPSBoYW5kbGVyX2luaXRfa3dhcmdzIG9yIHt9CiAgICBtb2RlbF9oYW5kbGVyID0gT05OWE1vZGVsSGFuZGxlcigKICAgICAgICBtb2RlbF9wYXRoPW1vZGVsX3BhdGgsIGNvbnRleHQ9Y29udGV4dCwgKipoYW5kbGVyX2luaXRfa3dhcmdzCiAgICApCgogICAgIyBMb2FkIHRoZSBPTk5YIG1vZGVsOgogICAgbW9kZWxfaGFuZGxlci5sb2FkKCkKCiAgICAjIE9wdGltaXplIHRoZSBtb2RlbCB1c2luZyB0aGUgZ2l2ZW4gY29uZmlndXJhdGlvbnM6CiAgICBtb2RlbF9oYW5kbGVyLm9wdGltaXplKG9wdGltaXphdGlvbnM9b3B0aW1pemF0aW9ucywgZml4ZWRfcG9pbnQ9Zml4ZWRfcG9pbnQpCgogICAgIyBSZW5hbWUgaWYgbmVlZGVkOgogICAgaWYgb3B0aW1pemVkX21vZGVsX25hbWUgaXMgbm90IE5vbmU6CiAgICAgICAgbW9kZWxfaGFuZGxlci5zZXRfbW9kZWxfbmFtZShtb2RlbF9uYW1lPW9wdGltaXplZF9tb2RlbF9uYW1lKQoKICAgICMgTG9nIHRoZSBvcHRpbWl6ZWQgbW9kZWw6CiAgICBtb2RlbF9oYW5kbGVyLmxvZygpCg==
+ base_image: mlrun/mlrun
+ with_mlrun: false
+ auto_build: true
+ requirements:
+ - tqdm~=4.67.1
+ - tensorflow~=2.19.0
+ - tf_keras~=2.19.0
+ - torch~=2.8.0
+ - torchvision~=0.23.0
+ - onnx~=1.17.0
+ - onnxruntime~=1.19.2
+ - onnxoptimizer~=0.3.13
+ - onnxmltools~=1.13.0
+ - tf2onnx~=1.16.1
+ - plotly~=5.23
+ origin_filename: ''
+ code_origin: ''
+verbose: false
+
+
+
+
+
\ No newline at end of file
diff --git a/functions/development/onnx_utils/1.4.0/static/item.html b/functions/development/onnx_utils/1.4.0/static/item.html
new file mode 100644
index 00000000..b4662c63
--- /dev/null
+++ b/functions/development/onnx_utils/1.4.0/static/item.html
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+ Source
+
+
+
+
+
+# Copyright 2019 Iguazio
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+fromtypingimportAny,Callable,Dict,List,Tuple
+
+importmlrun
+
+
+class_ToONNXConversions:
+"""
+ An ONNX conversion functions library class.
+ """
+
+ @staticmethod
+ deftf_keras_to_onnx(
+ model_handler,
+ onnx_model_name:str=None,
+ optimize_model:bool=True,
+ input_signature:List[Tuple[Tuple[int],str]]=None,
+ ):
+"""
+ Convert a TF.Keras model to an ONNX model and log it back to MLRun as a new model object.
+
+ :param model_handler: An initialized TFKerasModelHandler with a loaded model to convert to ONNX.
+ :param onnx_model_name: The name to use to log the converted ONNX model. If not given, the given `model_name`
+ will be used with an additional suffix `_onnx`. Defaulted to None.
+ :param optimize_model: Whether or not to optimize the ONNX model using 'onnxoptimizer' before saving the model.
+ Defaulted to True.
+ :param input_signature: A list of the input layers shape and data type properties. Expected to receive a list
+ where each element is an input layer tuple. An input layer tuple is a tuple of:
+ [0] = Layer's shape, a tuple of integers.
+ [1] = Layer's data type, a mlrun.data_types.ValueType string.
+ If None, the input signature will be tried to be read from the model artifact. Defaulted
+ to None.
+ """
+ # Import the framework and handler:
+ importtensorflowastf
+ frommlrun.frameworks.tf_kerasimportTFKerasUtils
+
+ # Check the given 'input_signature' parameter:
+ ifinput_signatureisNone:
+ # Read the inputs from the model:
+ try:
+ model_handler.read_inputs_from_model()
+ exceptExceptionaserror:
+ raisemlrun.errors.MLRunRuntimeError(
+ f"Please provide the 'input_signature' parameter. The function tried reading the input layers "
+ f"information automatically but failed with the following error: {error}"
+ )
+ else:
+ # Parse the 'input_signature' parameter:
+ input_signature=[
+ tf.TensorSpec(
+ shape=shape,
+ dtype=TFKerasUtils.convert_value_type_to_tf_dtype(
+ value_type=value_type
+ ),
+ )
+ for(shape,value_type)ininput_signature
+ ]
+
+ # Convert to ONNX:
+ model_handler.to_onnx(
+ model_name=onnx_model_name,
+ input_signature=input_signature,
+ optimize=optimize_model,
+ )
+
+ @staticmethod
+ defpytorch_to_onnx(
+ model_handler,
+ onnx_model_name:str=None,
+ optimize_model:bool=True,
+ input_signature:List[Tuple[Tuple[int,...],str]]=None,
+ input_layers_names:List[str]=None,
+ output_layers_names:List[str]=None,
+ dynamic_axes:Dict[str,Dict[int,str]]=None,
+ is_batched:bool=True,
+ ):
+"""
+ Convert a PyTorch model to an ONNX model and log it back to MLRun as a new model object.
+
+ :param model_handler: An initialized PyTorchModelHandler with a loaded model to convert to ONNX.
+ :param onnx_model_name: The name to use to log the converted ONNX model. If not given, the given
+ `model_name` will be used with an additional suffix `_onnx`. Defaulted to None.
+ :param optimize_model: Whether or not to optimize the ONNX model using 'onnxoptimizer' before saving the
+ model. Defaulted to True.
+ :param input_signature: A list of the input layers shape and data type properties. Expected to receive a
+ list where each element is an input layer tuple. An input layer tuple is a tuple of:
+ [0] = Layer's shape, a tuple of integers.
+ [1] = Layer's data type, a mlrun.data_types.ValueType string.
+ If None, the input signature will be tried to be read from the model artifact.
+ Defaulted to None.
+ :param input_layers_names: List of names to assign to the input nodes of the graph in order. All of the other
+ parameters (inner layers) can be set as well by passing additional names in the
+ list. The order is by the order of the parameters in the model. If None, the inputs
+ will be read from the handler's inputs. If its also None, it is defaulted to:
+ "input_0", "input_1", ...
+ :param output_layers_names: List of names to assign to the output nodes of the graph in order. If None, the
+ outputs will be read from the handler's outputs. If its also None, it is defaulted
+ to: "output_0" (for multiple outputs, this parameter must be provided).
+ :param dynamic_axes: If part of the input / output shape is dynamic, like (batch_size, 3, 32, 32) you can
+ specify it by giving a dynamic axis to the input / output layer by its name as
+ follows: {
+ "input layer name": {0: "batch_size"},
+ "output layer name": {0: "batch_size"},
+ }
+ If provided, the 'is_batched' flag will be ignored. Defaulted to None.
+ :param is_batched: Whether to include a batch size as the first axis in every input and output layer.
+ Defaulted to True. Will be ignored if 'dynamic_axes' is provided.
+ """
+ # Import the framework and handler:
+ importtorch
+ frommlrun.frameworks.pytorchimportPyTorchUtils
+
+ # Parse the 'input_signature' parameter:
+ ifinput_signatureisnotNone:
+ input_signature=tuple(
+ [
+ torch.zeros(
+ size=shape,
+ dtype=PyTorchUtils.convert_value_type_to_torch_dtype(
+ value_type=value_type
+ ),
+ )
+ for(shape,value_type)ininput_signature
+ ]
+ )
+
+ # Convert to ONNX:
+ model_handler.to_onnx(
+ model_name=onnx_model_name,
+ input_sample=input_signature,
+ optimize=optimize_model,
+ input_layers_names=input_layers_names,
+ output_layers_names=output_layers_names,
+ dynamic_axes=dynamic_axes,
+ is_batched=is_batched,
+ )
+
+
+# Map for getting the conversion function according to the provided framework:
+_CONVERSION_MAP={
+ "tensorflow.keras":_ToONNXConversions.tf_keras_to_onnx,
+ "torch":_ToONNXConversions.pytorch_to_onnx,
+}# type: Dict[str, Callable]
+
+
+
+[docs]
+defto_onnx(
+ context:mlrun.MLClientCtx,
+ model_path:str,
+ load_model_kwargs:dict=None,
+ onnx_model_name:str=None,
+ optimize_model:bool=True,
+ framework_kwargs:Dict[str,Any]=None,
+):
+"""
+ Convert the given model to an ONNX model.
+
+ :param context: The MLRun function execution context
+ :param model_path: The model path store object.
+ :param load_model_kwargs: Keyword arguments to pass to the `AutoMLRun.load_model` method.
+ :param onnx_model_name: The name to use to log the converted ONNX model. If not given, the given `model_name` will
+ be used with an additional suffix `_onnx`. Defaulted to None.
+ :param optimize_model: Whether to optimize the ONNX model using 'onnxoptimizer' before saving the model.
+ Defaulted to True.
+ :param framework_kwargs: Additional arguments each framework may require to convert to ONNX. To get the doc string
+ of the desired framework onnx conversion function, pass "help".
+ """
+ frommlrun.frameworks.auto_mlrun.auto_mlrunimportAutoMLRun
+
+ # Get a model handler of the required framework:
+ load_model_kwargs=load_model_kwargsor{}
+ model_handler=AutoMLRun.load_model(
+ model_path=model_path,context=context,**load_model_kwargs
+ )
+
+ # Get the model's framework:
+ framework=model_handler.FRAMEWORK_NAME
+
+ # Use the conversion map to get the specific framework to onnx conversion:
+ ifframeworknotin_CONVERSION_MAP:
+ raisemlrun.errors.MLRunInvalidArgumentError(
+ f"The following framework: '{framework}', has no ONNX conversion."
+ )
+ conversion_function=_CONVERSION_MAP[framework]
+
+ # Check if needed to print the function's doc string ("help" is passed):
+ ifframework_kwargs=="help":
+ print(conversion_function.__doc__)
+ return
+
+ # Set the default empty framework kwargs if needed:
+ ifframework_kwargsisNone:
+ framework_kwargs={}
+
+ # Run the conversion:
+ try:
+ conversion_function(
+ model_handler=model_handler,
+ onnx_model_name=onnx_model_name,
+ optimize_model=optimize_model,
+ **framework_kwargs,
+ )
+ exceptTypeErrorasexception:
+ raisemlrun.errors.MLRunInvalidArgumentError(
+ f"ERROR: A TypeError exception was raised during the conversion:\n{exception}. "
+ f"Please read the {framework} framework conversion function doc string by passing 'help' in the "
+ f"'framework_kwargs' dictionary parameter."
+ )
+
+
+
+
+[docs]
+defoptimize(
+ context:mlrun.MLClientCtx,
+ model_path:str,
+ handler_init_kwargs:dict=None,
+ optimizations:List[str]=None,
+ fixed_point:bool=False,
+ optimized_model_name:str=None,
+):
+"""
+ Optimize the given ONNX model.
+
+ :param context: The MLRun function execution context.
+ :param model_path: Path to the ONNX model object.
+ :param handler_init_kwargs: Keyword arguments to pass to the `ONNXModelHandler` init method preloading.
+ :param optimizations: List of possible optimizations. To see what optimizations are available, pass "help".
+ If None, all the optimizations will be used. Defaulted to None.
+ :param fixed_point: Optimize the weights using fixed point. Defaulted to False.
+ :param optimized_model_name: The name of the optimized model. If None, the original model will be overridden.
+ Defaulted to None.
+ """
+ # Import the model handler:
+ importonnxoptimizer
+ frommlrun.frameworks.onnximportONNXModelHandler
+
+ # Check if needed to print the available optimizations ("help" is passed):
+ ifoptimizations=="help":
+ available_passes="\n* ".join(onnxoptimizer.get_available_passes())
+ print(f"The available optimizations are:\n* {available_passes}")
+ return
+
+ # Create the model handler:
+ handler_init_kwargs=handler_init_kwargsor{}
+ model_handler=ONNXModelHandler(
+ model_path=model_path,context=context,**handler_init_kwargs
+ )
+
+ # Load the ONNX model:
+ model_handler.load()
+
+ # Optimize the model using the given configurations:
+ model_handler.optimize(optimizations=optimizations,fixed_point=fixed_point)
+
+ # Rename if needed:
+ ifoptimized_model_nameisnotNone:
+ model_handler.set_model_name(model_name=optimized_model_name)
+
+ # Log the optimized model:
+ model_handler.log()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/functions/development/onnx_utils/1.4.0/static/source.html b/functions/development/onnx_utils/1.4.0/static/source.html
new file mode 100644
index 00000000..77715e97
--- /dev/null
+++ b/functions/development/onnx_utils/1.4.0/static/source.html
@@ -0,0 +1,306 @@
+
+
+
+
+
+
+
+
+
+
+ Source
+
+
+
+
+
+
+# Copyright 2019 Iguazio
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+from typing import Any, Callable, Dict, List, Tuple
+
+import mlrun
+
+
+class _ToONNXConversions:
+ """
+ An ONNX conversion functions library class.
+ """
+
+ @staticmethod
+ def tf_keras_to_onnx(
+ model_handler,
+ onnx_model_name: str = None,
+ optimize_model: bool = True,
+ input_signature: List[Tuple[Tuple[int], str]] = None,
+ ):
+ """
+ Convert a TF.Keras model to an ONNX model and log it back to MLRun as a new model object.
+
+ :param model_handler: An initialized TFKerasModelHandler with a loaded model to convert to ONNX.
+ :param onnx_model_name: The name to use to log the converted ONNX model. If not given, the given `model_name`
+ will be used with an additional suffix `_onnx`. Defaulted to None.
+ :param optimize_model: Whether or not to optimize the ONNX model using 'onnxoptimizer' before saving the model.
+ Defaulted to True.
+ :param input_signature: A list of the input layers shape and data type properties. Expected to receive a list
+ where each element is an input layer tuple. An input layer tuple is a tuple of:
+ [0] = Layer's shape, a tuple of integers.
+ [1] = Layer's data type, a mlrun.data_types.ValueType string.
+ If None, the input signature will be tried to be read from the model artifact. Defaulted
+ to None.
+ """
+ # Import the framework and handler:
+ import tensorflow as tf
+ from mlrun.frameworks.tf_keras import TFKerasUtils
+
+ # Check the given 'input_signature' parameter:
+ if input_signature is None:
+ # Read the inputs from the model:
+ try:
+ model_handler.read_inputs_from_model()
+ except Exception as error:
+ raise mlrun.errors.MLRunRuntimeError(
+ f"Please provide the 'input_signature' parameter. The function tried reading the input layers "
+ f"information automatically but failed with the following error: {error}"
+ )
+ else:
+ # Parse the 'input_signature' parameter:
+ input_signature = [
+ tf.TensorSpec(
+ shape=shape,
+ dtype=TFKerasUtils.convert_value_type_to_tf_dtype(
+ value_type=value_type
+ ),
+ )
+ for (shape, value_type) in input_signature
+ ]
+
+ # Convert to ONNX:
+ model_handler.to_onnx(
+ model_name=onnx_model_name,
+ input_signature=input_signature,
+ optimize=optimize_model,
+ )
+
+ @staticmethod
+ def pytorch_to_onnx(
+ model_handler,
+ onnx_model_name: str = None,
+ optimize_model: bool = True,
+ input_signature: List[Tuple[Tuple[int, ...], str]] = None,
+ input_layers_names: List[str] = None,
+ output_layers_names: List[str] = None,
+ dynamic_axes: Dict[str, Dict[int, str]] = None,
+ is_batched: bool = True,
+ ):
+ """
+ Convert a PyTorch model to an ONNX model and log it back to MLRun as a new model object.
+
+ :param model_handler: An initialized PyTorchModelHandler with a loaded model to convert to ONNX.
+ :param onnx_model_name: The name to use to log the converted ONNX model. If not given, the given
+ `model_name` will be used with an additional suffix `_onnx`. Defaulted to None.
+ :param optimize_model: Whether or not to optimize the ONNX model using 'onnxoptimizer' before saving the
+ model. Defaulted to True.
+ :param input_signature: A list of the input layers shape and data type properties. Expected to receive a
+ list where each element is an input layer tuple. An input layer tuple is a tuple of:
+ [0] = Layer's shape, a tuple of integers.
+ [1] = Layer's data type, a mlrun.data_types.ValueType string.
+ If None, the input signature will be tried to be read from the model artifact.
+ Defaulted to None.
+ :param input_layers_names: List of names to assign to the input nodes of the graph in order. All of the other
+ parameters (inner layers) can be set as well by passing additional names in the
+ list. The order is by the order of the parameters in the model. If None, the inputs
+ will be read from the handler's inputs. If its also None, it is defaulted to:
+ "input_0", "input_1", ...
+ :param output_layers_names: List of names to assign to the output nodes of the graph in order. If None, the
+ outputs will be read from the handler's outputs. If its also None, it is defaulted
+ to: "output_0" (for multiple outputs, this parameter must be provided).
+ :param dynamic_axes: If part of the input / output shape is dynamic, like (batch_size, 3, 32, 32) you can
+ specify it by giving a dynamic axis to the input / output layer by its name as
+ follows: {
+ "input layer name": {0: "batch_size"},
+ "output layer name": {0: "batch_size"},
+ }
+ If provided, the 'is_batched' flag will be ignored. Defaulted to None.
+ :param is_batched: Whether to include a batch size as the first axis in every input and output layer.
+ Defaulted to True. Will be ignored if 'dynamic_axes' is provided.
+ """
+ # Import the framework and handler:
+ import torch
+ from mlrun.frameworks.pytorch import PyTorchUtils
+
+ # Parse the 'input_signature' parameter:
+ if input_signature is not None:
+ input_signature = tuple(
+ [
+ torch.zeros(
+ size=shape,
+ dtype=PyTorchUtils.convert_value_type_to_torch_dtype(
+ value_type=value_type
+ ),
+ )
+ for (shape, value_type) in input_signature
+ ]
+ )
+
+ # Convert to ONNX:
+ model_handler.to_onnx(
+ model_name=onnx_model_name,
+ input_sample=input_signature,
+ optimize=optimize_model,
+ input_layers_names=input_layers_names,
+ output_layers_names=output_layers_names,
+ dynamic_axes=dynamic_axes,
+ is_batched=is_batched,
+ )
+
+
+# Map for getting the conversion function according to the provided framework:
+_CONVERSION_MAP = {
+ "tensorflow.keras": _ToONNXConversions.tf_keras_to_onnx,
+ "torch": _ToONNXConversions.pytorch_to_onnx,
+} # type: Dict[str, Callable]
+
+
+def to_onnx(
+ context: mlrun.MLClientCtx,
+ model_path: str,
+ load_model_kwargs: dict = None,
+ onnx_model_name: str = None,
+ optimize_model: bool = True,
+ framework_kwargs: Dict[str, Any] = None,
+):
+ """
+ Convert the given model to an ONNX model.
+
+ :param context: The MLRun function execution context
+ :param model_path: The model path store object.
+ :param load_model_kwargs: Keyword arguments to pass to the `AutoMLRun.load_model` method.
+ :param onnx_model_name: The name to use to log the converted ONNX model. If not given, the given `model_name` will
+ be used with an additional suffix `_onnx`. Defaulted to None.
+ :param optimize_model: Whether to optimize the ONNX model using 'onnxoptimizer' before saving the model.
+ Defaulted to True.
+ :param framework_kwargs: Additional arguments each framework may require to convert to ONNX. To get the doc string
+ of the desired framework onnx conversion function, pass "help".
+ """
+ from mlrun.frameworks.auto_mlrun.auto_mlrun import AutoMLRun
+
+ # Get a model handler of the required framework:
+ load_model_kwargs = load_model_kwargs or {}
+ model_handler = AutoMLRun.load_model(
+ model_path=model_path, context=context, **load_model_kwargs
+ )
+
+ # Get the model's framework:
+ framework = model_handler.FRAMEWORK_NAME
+
+ # Use the conversion map to get the specific framework to onnx conversion:
+ if framework not in _CONVERSION_MAP:
+ raise mlrun.errors.MLRunInvalidArgumentError(
+ f"The following framework: '{framework}', has no ONNX conversion."
+ )
+ conversion_function = _CONVERSION_MAP[framework]
+
+ # Check if needed to print the function's doc string ("help" is passed):
+ if framework_kwargs == "help":
+ print(conversion_function.__doc__)
+ return
+
+ # Set the default empty framework kwargs if needed:
+ if framework_kwargs is None:
+ framework_kwargs = {}
+
+ # Run the conversion:
+ try:
+ conversion_function(
+ model_handler=model_handler,
+ onnx_model_name=onnx_model_name,
+ optimize_model=optimize_model,
+ **framework_kwargs,
+ )
+ except TypeError as exception:
+ raise mlrun.errors.MLRunInvalidArgumentError(
+ f"ERROR: A TypeError exception was raised during the conversion:\n{exception}. "
+ f"Please read the {framework} framework conversion function doc string by passing 'help' in the "
+ f"'framework_kwargs' dictionary parameter."
+ )
+
+
+def optimize(
+ context: mlrun.MLClientCtx,
+ model_path: str,
+ handler_init_kwargs: dict = None,
+ optimizations: List[str] = None,
+ fixed_point: bool = False,
+ optimized_model_name: str = None,
+):
+ """
+ Optimize the given ONNX model.
+
+ :param context: The MLRun function execution context.
+ :param model_path: Path to the ONNX model object.
+ :param handler_init_kwargs: Keyword arguments to pass to the `ONNXModelHandler` init method preloading.
+ :param optimizations: List of possible optimizations. To see what optimizations are available, pass "help".
+ If None, all the optimizations will be used. Defaulted to None.
+ :param fixed_point: Optimize the weights using fixed point. Defaulted to False.
+ :param optimized_model_name: The name of the optimized model. If None, the original model will be overridden.
+ Defaulted to None.
+ """
+ # Import the model handler:
+ import onnxoptimizer
+ from mlrun.frameworks.onnx import ONNXModelHandler
+
+ # Check if needed to print the available optimizations ("help" is passed):
+ if optimizations == "help":
+ available_passes = "\n* ".join(onnxoptimizer.get_available_passes())
+ print(f"The available optimizations are:\n* {available_passes}")
+ return
+
+ # Create the model handler:
+ handler_init_kwargs = handler_init_kwargs or {}
+ model_handler = ONNXModelHandler(
+ model_path=model_path, context=context, **handler_init_kwargs
+ )
+
+ # Load the ONNX model:
+ model_handler.load()
+
+ # Optimize the model using the given configurations:
+ model_handler.optimize(optimizations=optimizations, fixed_point=fixed_point)
+
+ # Rename if needed:
+ if optimized_model_name is not None:
+ model_handler.set_model_name(model_name=optimized_model_name)
+
+ # Log the optimized model:
+ model_handler.log()
+
+
+
+
+
\ No newline at end of file
diff --git a/functions/development/onnx_utils/latest/src/function.yaml b/functions/development/onnx_utils/latest/src/function.yaml
index 05a0f0bc..091002cd 100644
--- a/functions/development/onnx_utils/latest/src/function.yaml
+++ b/functions/development/onnx_utils/latest/src/function.yaml
@@ -1,39 +1,13 @@
-kind: job
metadata:
+ name: onnx-utils
+ tag: ''
categories:
- utilities
- deep-learning
- name: onnx-utils
- tag: ''
-verbose: false
+kind: job
spec:
- build:
- code_origin: ''
- base_image: mlrun/mlrun
- origin_filename: ''
- functionSourceCode: IyBDb3B5cmlnaHQgMjAxOSBJZ3VhemlvCiMKIyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiMgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiMKIyAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiMKIyBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiMgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KIyBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiMgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiMKZnJvbSB0eXBpbmcgaW1wb3J0IEFueSwgQ2FsbGFibGUsIERpY3QsIExpc3QsIFR1cGxlCgppbXBvcnQgbWxydW4KCgpjbGFzcyBfVG9PTk5YQ29udmVyc2lvbnM6CiAgICAiIiIKICAgIEFuIE9OTlggY29udmVyc2lvbiBmdW5jdGlvbnMgbGlicmFyeSBjbGFzcy4KICAgICIiIgoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiB0Zl9rZXJhc190b19vbm54KAogICAgICAgIG1vZGVsX2hhbmRsZXIsCiAgICAgICAgb25ueF9tb2RlbF9uYW1lOiBzdHIgPSBOb25lLAogICAgICAgIG9wdGltaXplX21vZGVsOiBib29sID0gVHJ1ZSwKICAgICAgICBpbnB1dF9zaWduYXR1cmU6IExpc3RbVHVwbGVbVHVwbGVbaW50XSwgc3RyXV0gPSBOb25lLAogICAgKToKICAgICAgICAiIiIKICAgICAgICBDb252ZXJ0IGEgVEYuS2VyYXMgbW9kZWwgdG8gYW4gT05OWCBtb2RlbCBhbmQgbG9nIGl0IGJhY2sgdG8gTUxSdW4gYXMgYSBuZXcgbW9kZWwgb2JqZWN0LgoKICAgICAgICA6cGFyYW0gbW9kZWxfaGFuZGxlcjogICBBbiBpbml0aWFsaXplZCBURktlcmFzTW9kZWxIYW5kbGVyIHdpdGggYSBsb2FkZWQgbW9kZWwgdG8gY29udmVydCB0byBPTk5YLgogICAgICAgIDpwYXJhbSBvbm54X21vZGVsX25hbWU6IFRoZSBuYW1lIHRvIHVzZSB0byBsb2cgdGhlIGNvbnZlcnRlZCBPTk5YIG1vZGVsLiBJZiBub3QgZ2l2ZW4sIHRoZSBnaXZlbiBgbW9kZWxfbmFtZWAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aWxsIGJlIHVzZWQgd2l0aCBhbiBhZGRpdGlvbmFsIHN1ZmZpeCBgX29ubnhgLiBEZWZhdWx0ZWQgdG8gTm9uZS4KICAgICAgICA6cGFyYW0gb3B0aW1pemVfbW9kZWw6ICBXaGV0aGVyIG9yIG5vdCB0byBvcHRpbWl6ZSB0aGUgT05OWCBtb2RlbCB1c2luZyAnb25ueG9wdGltaXplcicgYmVmb3JlIHNhdmluZyB0aGUgbW9kZWwuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVmYXVsdGVkIHRvIFRydWUuCiAgICAgICAgOnBhcmFtIGlucHV0X3NpZ25hdHVyZTogQSBsaXN0IG9mIHRoZSBpbnB1dCBsYXllcnMgc2hhcGUgYW5kIGRhdGEgdHlwZSBwcm9wZXJ0aWVzLiBFeHBlY3RlZCB0byByZWNlaXZlIGEgbGlzdAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoZXJlIGVhY2ggZWxlbWVudCBpcyBhbiBpbnB1dCBsYXllciB0dXBsZS4gQW4gaW5wdXQgbGF5ZXIgdHVwbGUgaXMgYSB0dXBsZSBvZjoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbMF0gPSBMYXllcidzIHNoYXBlLCBhIHR1cGxlIG9mIGludGVnZXJzLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFsxXSA9IExheWVyJ3MgZGF0YSB0eXBlLCBhIG1scnVuLmRhdGFfdHlwZXMuVmFsdWVUeXBlIHN0cmluZy4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJZiBOb25lLCB0aGUgaW5wdXQgc2lnbmF0dXJlIHdpbGwgYmUgdHJpZWQgdG8gYmUgcmVhZCBmcm9tIHRoZSBtb2RlbCBhcnRpZmFjdC4gRGVmYXVsdGVkCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG8gTm9uZS4KICAgICAgICAiIiIKICAgICAgICAjIEltcG9ydCB0aGUgZnJhbWV3b3JrIGFuZCBoYW5kbGVyOgogICAgICAgIGltcG9ydCB0ZW5zb3JmbG93IGFzIHRmCiAgICAgICAgZnJvbSBtbHJ1bi5mcmFtZXdvcmtzLnRmX2tlcmFzIGltcG9ydCBURktlcmFzVXRpbHMKCiAgICAgICAgIyBDaGVjayB0aGUgZ2l2ZW4gJ2lucHV0X3NpZ25hdHVyZScgcGFyYW1ldGVyOgogICAgICAgIGlmIGlucHV0X3NpZ25hdHVyZSBpcyBOb25lOgogICAgICAgICAgICAjIFJlYWQgdGhlIGlucHV0cyBmcm9tIHRoZSBtb2RlbDoKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgbW9kZWxfaGFuZGxlci5yZWFkX2lucHV0c19mcm9tX21vZGVsKCkKICAgICAgICAgICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlcnJvcjoKICAgICAgICAgICAgICAgIHJhaXNlIG1scnVuLmVycm9ycy5NTFJ1blJ1bnRpbWVFcnJvcigKICAgICAgICAgICAgICAgICAgICBmIlBsZWFzZSBwcm92aWRlIHRoZSAnaW5wdXRfc2lnbmF0dXJlJyBwYXJhbWV0ZXIuIFRoZSBmdW5jdGlvbiB0cmllZCByZWFkaW5nIHRoZSBpbnB1dCBsYXllcnMgIgogICAgICAgICAgICAgICAgICAgIGYiaW5mb3JtYXRpb24gYXV0b21hdGljYWxseSBidXQgZmFpbGVkIHdpdGggdGhlIGZvbGxvd2luZyBlcnJvcjoge2Vycm9yfSIKICAgICAgICAgICAgICAgICkKICAgICAgICBlbHNlOgogICAgICAgICAgICAjIFBhcnNlIHRoZSAnaW5wdXRfc2lnbmF0dXJlJyBwYXJhbWV0ZXI6CiAgICAgICAgICAgIGlucHV0X3NpZ25hdHVyZSA9IFsKICAgICAgICAgICAgICAgIHRmLlRlbnNvclNwZWMoCiAgICAgICAgICAgICAgICAgICAgc2hhcGU9c2hhcGUsCiAgICAgICAgICAgICAgICAgICAgZHR5cGU9VEZLZXJhc1V0aWxzLmNvbnZlcnRfdmFsdWVfdHlwZV90b190Zl9kdHlwZSgKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVfdHlwZT12YWx1ZV90eXBlCiAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIGZvciAoc2hhcGUsIHZhbHVlX3R5cGUpIGluIGlucHV0X3NpZ25hdHVyZQogICAgICAgICAgICBdCgogICAgICAgICMgQ29udmVydCB0byBPTk5YOgogICAgICAgIG1vZGVsX2hhbmRsZXIudG9fb25ueCgKICAgICAgICAgICAgbW9kZWxfbmFtZT1vbm54X21vZGVsX25hbWUsCiAgICAgICAgICAgIGlucHV0X3NpZ25hdHVyZT1pbnB1dF9zaWduYXR1cmUsCiAgICAgICAgICAgIG9wdGltaXplPW9wdGltaXplX21vZGVsLAogICAgICAgICkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgcHl0b3JjaF90b19vbm54KAogICAgICAgIG1vZGVsX2hhbmRsZXIsCiAgICAgICAgb25ueF9tb2RlbF9uYW1lOiBzdHIgPSBOb25lLAogICAgICAgIG9wdGltaXplX21vZGVsOiBib29sID0gVHJ1ZSwKICAgICAgICBpbnB1dF9zaWduYXR1cmU6IExpc3RbVHVwbGVbVHVwbGVbaW50LCAuLi5dLCBzdHJdXSA9IE5vbmUsCiAgICAgICAgaW5wdXRfbGF5ZXJzX25hbWVzOiBMaXN0W3N0cl0gPSBOb25lLAogICAgICAgIG91dHB1dF9sYXllcnNfbmFtZXM6IExpc3Rbc3RyXSA9IE5vbmUsCiAgICAgICAgZHluYW1pY19heGVzOiBEaWN0W3N0ciwgRGljdFtpbnQsIHN0cl1dID0gTm9uZSwKICAgICAgICBpc19iYXRjaGVkOiBib29sID0gVHJ1ZSwKICAgICk6CiAgICAgICAgIiIiCiAgICAgICAgQ29udmVydCBhIFB5VG9yY2ggbW9kZWwgdG8gYW4gT05OWCBtb2RlbCBhbmQgbG9nIGl0IGJhY2sgdG8gTUxSdW4gYXMgYSBuZXcgbW9kZWwgb2JqZWN0LgoKICAgICAgICA6cGFyYW0gbW9kZWxfaGFuZGxlcjogICAgICAgQW4gaW5pdGlhbGl6ZWQgUHlUb3JjaE1vZGVsSGFuZGxlciB3aXRoIGEgbG9hZGVkIG1vZGVsIHRvIGNvbnZlcnQgdG8gT05OWC4KICAgICAgICA6cGFyYW0gb25ueF9tb2RlbF9uYW1lOiAgICAgVGhlIG5hbWUgdG8gdXNlIHRvIGxvZyB0aGUgY29udmVydGVkIE9OTlggbW9kZWwuIElmIG5vdCBnaXZlbiwgdGhlIGdpdmVuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBtb2RlbF9uYW1lYCB3aWxsIGJlIHVzZWQgd2l0aCBhbiBhZGRpdGlvbmFsIHN1ZmZpeCBgX29ubnhgLiBEZWZhdWx0ZWQgdG8gTm9uZS4KICAgICAgICA6cGFyYW0gb3B0aW1pemVfbW9kZWw6ICAgICAgV2hldGhlciBvciBub3QgdG8gb3B0aW1pemUgdGhlIE9OTlggbW9kZWwgdXNpbmcgJ29ubnhvcHRpbWl6ZXInIGJlZm9yZSBzYXZpbmcgdGhlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLiBEZWZhdWx0ZWQgdG8gVHJ1ZS4KICAgICAgICA6cGFyYW0gaW5wdXRfc2lnbmF0dXJlOiAgICAgQSBsaXN0IG9mIHRoZSBpbnB1dCBsYXllcnMgc2hhcGUgYW5kIGRhdGEgdHlwZSBwcm9wZXJ0aWVzLiBFeHBlY3RlZCB0byByZWNlaXZlIGEKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdCB3aGVyZSBlYWNoIGVsZW1lbnQgaXMgYW4gaW5wdXQgbGF5ZXIgdHVwbGUuIEFuIGlucHV0IGxheWVyIHR1cGxlIGlzIGEgdHVwbGUgb2Y6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFswXSA9IExheWVyJ3Mgc2hhcGUsIGEgdHVwbGUgb2YgaW50ZWdlcnMuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFsxXSA9IExheWVyJ3MgZGF0YSB0eXBlLCBhIG1scnVuLmRhdGFfdHlwZXMuVmFsdWVUeXBlIHN0cmluZy4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSWYgTm9uZSwgdGhlIGlucHV0IHNpZ25hdHVyZSB3aWxsIGJlIHRyaWVkIHRvIGJlIHJlYWQgZnJvbSB0aGUgbW9kZWwgYXJ0aWZhY3QuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlZmF1bHRlZCB0byBOb25lLgogICAgICAgIDpwYXJhbSBpbnB1dF9sYXllcnNfbmFtZXM6ICBMaXN0IG9mIG5hbWVzIHRvIGFzc2lnbiB0byB0aGUgaW5wdXQgbm9kZXMgb2YgdGhlIGdyYXBoIGluIG9yZGVyLiBBbGwgb2YgdGhlIG90aGVyCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtZXRlcnMgKGlubmVyIGxheWVycykgY2FuIGJlIHNldCBhcyB3ZWxsIGJ5IHBhc3NpbmcgYWRkaXRpb25hbCBuYW1lcyBpbiB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdC4gVGhlIG9yZGVyIGlzIGJ5IHRoZSBvcmRlciBvZiB0aGUgcGFyYW1ldGVycyBpbiB0aGUgbW9kZWwuIElmIE5vbmUsIHRoZSBpbnB1dHMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lsbCBiZSByZWFkIGZyb20gdGhlIGhhbmRsZXIncyBpbnB1dHMuIElmIGl0cyBhbHNvIE5vbmUsIGl0IGlzIGRlZmF1bHRlZCB0bzoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImlucHV0XzAiLCAiaW5wdXRfMSIsIC4uLgogICAgICAgIDpwYXJhbSBvdXRwdXRfbGF5ZXJzX25hbWVzOiBMaXN0IG9mIG5hbWVzIHRvIGFzc2lnbiB0byB0aGUgb3V0cHV0IG5vZGVzIG9mIHRoZSBncmFwaCBpbiBvcmRlci4gSWYgTm9uZSwgdGhlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dHMgd2lsbCBiZSByZWFkIGZyb20gdGhlIGhhbmRsZXIncyBvdXRwdXRzLiBJZiBpdHMgYWxzbyBOb25lLCBpdCBpcyBkZWZhdWx0ZWQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG86ICJvdXRwdXRfMCIgKGZvciBtdWx0aXBsZSBvdXRwdXRzLCB0aGlzIHBhcmFtZXRlciBtdXN0IGJlIHByb3ZpZGVkKS4KICAgICAgICA6cGFyYW0gZHluYW1pY19heGVzOiAgICAgICAgSWYgcGFydCBvZiB0aGUgaW5wdXQgLyBvdXRwdXQgc2hhcGUgaXMgZHluYW1pYywgbGlrZSAoYmF0Y2hfc2l6ZSwgMywgMzIsIDMyKSB5b3UgY2FuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNpZnkgaXQgYnkgZ2l2aW5nIGEgZHluYW1pYyBheGlzIHRvIHRoZSBpbnB1dCAvIG91dHB1dCBsYXllciBieSBpdHMgbmFtZSBhcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb2xsb3dzOiB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaW5wdXQgbGF5ZXIgbmFtZSI6IHswOiAiYmF0Y2hfc2l6ZSJ9LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm91dHB1dCBsYXllciBuYW1lIjogezA6ICJiYXRjaF9zaXplIn0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSWYgcHJvdmlkZWQsIHRoZSAnaXNfYmF0Y2hlZCcgZmxhZyB3aWxsIGJlIGlnbm9yZWQuIERlZmF1bHRlZCB0byBOb25lLgogICAgICAgIDpwYXJhbSBpc19iYXRjaGVkOiAgICAgICAgICBXaGV0aGVyIHRvIGluY2x1ZGUgYSBiYXRjaCBzaXplIGFzIHRoZSBmaXJzdCBheGlzIGluIGV2ZXJ5IGlucHV0IGFuZCBvdXRwdXQgbGF5ZXIuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlZmF1bHRlZCB0byBUcnVlLiBXaWxsIGJlIGlnbm9yZWQgaWYgJ2R5bmFtaWNfYXhlcycgaXMgcHJvdmlkZWQuCiAgICAgICAgIiIiCiAgICAgICAgIyBJbXBvcnQgdGhlIGZyYW1ld29yayBhbmQgaGFuZGxlcjoKICAgICAgICBpbXBvcnQgdG9yY2gKICAgICAgICBmcm9tIG1scnVuLmZyYW1ld29ya3MucHl0b3JjaCBpbXBvcnQgUHlUb3JjaFV0aWxzCgogICAgICAgICMgUGFyc2UgdGhlICdpbnB1dF9zaWduYXR1cmUnIHBhcmFtZXRlcjoKICAgICAgICBpZiBpbnB1dF9zaWduYXR1cmUgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIGlucHV0X3NpZ25hdHVyZSA9IHR1cGxlKAogICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgIHRvcmNoLnplcm9zKAogICAgICAgICAgICAgICAgICAgICAgICBzaXplPXNoYXBlLAogICAgICAgICAgICAgICAgICAgICAgICBkdHlwZT1QeVRvcmNoVXRpbHMuY29udmVydF92YWx1ZV90eXBlX3RvX3RvcmNoX2R0eXBlKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVfdHlwZT12YWx1ZV90eXBlCiAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgIGZvciAoc2hhcGUsIHZhbHVlX3R5cGUpIGluIGlucHV0X3NpZ25hdHVyZQogICAgICAgICAgICAgICAgXQogICAgICAgICAgICApCgogICAgICAgICMgQ29udmVydCB0byBPTk5YOgogICAgICAgIG1vZGVsX2hhbmRsZXIudG9fb25ueCgKICAgICAgICAgICAgbW9kZWxfbmFtZT1vbm54X21vZGVsX25hbWUsCiAgICAgICAgICAgIGlucHV0X3NhbXBsZT1pbnB1dF9zaWduYXR1cmUsCiAgICAgICAgICAgIG9wdGltaXplPW9wdGltaXplX21vZGVsLAogICAgICAgICAgICBpbnB1dF9sYXllcnNfbmFtZXM9aW5wdXRfbGF5ZXJzX25hbWVzLAogICAgICAgICAgICBvdXRwdXRfbGF5ZXJzX25hbWVzPW91dHB1dF9sYXllcnNfbmFtZXMsCiAgICAgICAgICAgIGR5bmFtaWNfYXhlcz1keW5hbWljX2F4ZXMsCiAgICAgICAgICAgIGlzX2JhdGNoZWQ9aXNfYmF0Y2hlZCwKICAgICAgICApCgoKIyBNYXAgZm9yIGdldHRpbmcgdGhlIGNvbnZlcnNpb24gZnVuY3Rpb24gYWNjb3JkaW5nIHRvIHRoZSBwcm92aWRlZCBmcmFtZXdvcms6Cl9DT05WRVJTSU9OX01BUCA9IHsKICAgICJ0ZW5zb3JmbG93LmtlcmFzIjogX1RvT05OWENvbnZlcnNpb25zLnRmX2tlcmFzX3RvX29ubngsCiAgICAidG9yY2giOiBfVG9PTk5YQ29udmVyc2lvbnMucHl0b3JjaF90b19vbm54LAp9ICAjIHR5cGU6IERpY3Rbc3RyLCBDYWxsYWJsZV0KCgpkZWYgdG9fb25ueCgKICAgIGNvbnRleHQ6IG1scnVuLk1MQ2xpZW50Q3R4LAogICAgbW9kZWxfcGF0aDogc3RyLAogICAgbG9hZF9tb2RlbF9rd2FyZ3M6IGRpY3QgPSBOb25lLAogICAgb25ueF9tb2RlbF9uYW1lOiBzdHIgPSBOb25lLAogICAgb3B0aW1pemVfbW9kZWw6IGJvb2wgPSBUcnVlLAogICAgZnJhbWV3b3JrX2t3YXJnczogRGljdFtzdHIsIEFueV0gPSBOb25lLAopOgogICAgIiIiCiAgICBDb252ZXJ0IHRoZSBnaXZlbiBtb2RlbCB0byBhbiBPTk5YIG1vZGVsLgoKICAgIDpwYXJhbSBjb250ZXh0OiAgICAgICAgICAgVGhlIE1MUnVuIGZ1bmN0aW9uIGV4ZWN1dGlvbiBjb250ZXh0CiAgICA6cGFyYW0gbW9kZWxfcGF0aDogICAgICAgIFRoZSBtb2RlbCBwYXRoIHN0b3JlIG9iamVjdC4KICAgIDpwYXJhbSBsb2FkX21vZGVsX2t3YXJnczogS2V5d29yZCBhcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgYEF1dG9NTFJ1bi5sb2FkX21vZGVsYCBtZXRob2QuCiAgICA6cGFyYW0gb25ueF9tb2RlbF9uYW1lOiAgIFRoZSBuYW1lIHRvIHVzZSB0byBsb2cgdGhlIGNvbnZlcnRlZCBPTk5YIG1vZGVsLiBJZiBub3QgZ2l2ZW4sIHRoZSBnaXZlbiBgbW9kZWxfbmFtZWAgd2lsbAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZSB1c2VkIHdpdGggYW4gYWRkaXRpb25hbCBzdWZmaXggYF9vbm54YC4gRGVmYXVsdGVkIHRvIE5vbmUuCiAgICA6cGFyYW0gb3B0aW1pemVfbW9kZWw6ICAgIFdoZXRoZXIgdG8gb3B0aW1pemUgdGhlIE9OTlggbW9kZWwgdXNpbmcgJ29ubnhvcHRpbWl6ZXInIGJlZm9yZSBzYXZpbmcgdGhlIG1vZGVsLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEZWZhdWx0ZWQgdG8gVHJ1ZS4KICAgIDpwYXJhbSBmcmFtZXdvcmtfa3dhcmdzOiAgQWRkaXRpb25hbCBhcmd1bWVudHMgZWFjaCBmcmFtZXdvcmsgbWF5IHJlcXVpcmUgdG8gY29udmVydCB0byBPTk5YLiBUbyBnZXQgdGhlIGRvYyBzdHJpbmcKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2YgdGhlIGRlc2lyZWQgZnJhbWV3b3JrIG9ubnggY29udmVyc2lvbiBmdW5jdGlvbiwgcGFzcyAiaGVscCIuCiAgICAiIiIKICAgIGZyb20gbWxydW4uZnJhbWV3b3Jrcy5hdXRvX21scnVuLmF1dG9fbWxydW4gaW1wb3J0IEF1dG9NTFJ1bgoKICAgICMgR2V0IGEgbW9kZWwgaGFuZGxlciBvZiB0aGUgcmVxdWlyZWQgZnJhbWV3b3JrOgogICAgbG9hZF9tb2RlbF9rd2FyZ3MgPSBsb2FkX21vZGVsX2t3YXJncyBvciB7fQogICAgbW9kZWxfaGFuZGxlciA9IEF1dG9NTFJ1bi5sb2FkX21vZGVsKAogICAgICAgIG1vZGVsX3BhdGg9bW9kZWxfcGF0aCwgY29udGV4dD1jb250ZXh0LCAqKmxvYWRfbW9kZWxfa3dhcmdzCiAgICApCgogICAgIyBHZXQgdGhlIG1vZGVsJ3MgZnJhbWV3b3JrOgogICAgZnJhbWV3b3JrID0gbW9kZWxfaGFuZGxlci5GUkFNRVdPUktfTkFNRQoKICAgICMgVXNlIHRoZSBjb252ZXJzaW9uIG1hcCB0byBnZXQgdGhlIHNwZWNpZmljIGZyYW1ld29yayB0byBvbm54IGNvbnZlcnNpb246CiAgICBpZiBmcmFtZXdvcmsgbm90IGluIF9DT05WRVJTSU9OX01BUDoKICAgICAgICByYWlzZSBtbHJ1bi5lcnJvcnMuTUxSdW5JbnZhbGlkQXJndW1lbnRFcnJvcigKICAgICAgICAgICAgZiJUaGUgZm9sbG93aW5nIGZyYW1ld29yazogJ3tmcmFtZXdvcmt9JywgaGFzIG5vIE9OTlggY29udmVyc2lvbi4iCiAgICAgICAgKQogICAgY29udmVyc2lvbl9mdW5jdGlvbiA9IF9DT05WRVJTSU9OX01BUFtmcmFtZXdvcmtdCgogICAgIyBDaGVjayBpZiBuZWVkZWQgdG8gcHJpbnQgdGhlIGZ1bmN0aW9uJ3MgZG9jIHN0cmluZyAoImhlbHAiIGlzIHBhc3NlZCk6CiAgICBpZiBmcmFtZXdvcmtfa3dhcmdzID09ICJoZWxwIjoKICAgICAgICBwcmludChjb252ZXJzaW9uX2Z1bmN0aW9uLl9fZG9jX18pCiAgICAgICAgcmV0dXJuCgogICAgIyBTZXQgdGhlIGRlZmF1bHQgZW1wdHkgZnJhbWV3b3JrIGt3YXJncyBpZiBuZWVkZWQ6CiAgICBpZiBmcmFtZXdvcmtfa3dhcmdzIGlzIE5vbmU6CiAgICAgICAgZnJhbWV3b3JrX2t3YXJncyA9IHt9CgogICAgIyBSdW4gdGhlIGNvbnZlcnNpb246CiAgICB0cnk6CiAgICAgICAgY29udmVyc2lvbl9mdW5jdGlvbigKICAgICAgICAgICAgbW9kZWxfaGFuZGxlcj1tb2RlbF9oYW5kbGVyLAogICAgICAgICAgICBvbm54X21vZGVsX25hbWU9b25ueF9tb2RlbF9uYW1lLAogICAgICAgICAgICBvcHRpbWl6ZV9tb2RlbD1vcHRpbWl6ZV9tb2RlbCwKICAgICAgICAgICAgKipmcmFtZXdvcmtfa3dhcmdzLAogICAgICAgICkKICAgIGV4Y2VwdCBUeXBlRXJyb3IgYXMgZXhjZXB0aW9uOgogICAgICAgIHJhaXNlIG1scnVuLmVycm9ycy5NTFJ1bkludmFsaWRBcmd1bWVudEVycm9yKAogICAgICAgICAgICBmIkVSUk9SOiBBIFR5cGVFcnJvciBleGNlcHRpb24gd2FzIHJhaXNlZCBkdXJpbmcgdGhlIGNvbnZlcnNpb246XG57ZXhjZXB0aW9ufS4gIgogICAgICAgICAgICBmIlBsZWFzZSByZWFkIHRoZSB7ZnJhbWV3b3JrfSBmcmFtZXdvcmsgY29udmVyc2lvbiBmdW5jdGlvbiBkb2Mgc3RyaW5nIGJ5IHBhc3NpbmcgJ2hlbHAnIGluIHRoZSAiCiAgICAgICAgICAgIGYiJ2ZyYW1ld29ya19rd2FyZ3MnIGRpY3Rpb25hcnkgcGFyYW1ldGVyLiIKICAgICAgICApCgoKZGVmIG9wdGltaXplKAogICAgY29udGV4dDogbWxydW4uTUxDbGllbnRDdHgsCiAgICBtb2RlbF9wYXRoOiBzdHIsCiAgICBoYW5kbGVyX2luaXRfa3dhcmdzOiBkaWN0ID0gTm9uZSwKICAgIG9wdGltaXphdGlvbnM6IExpc3Rbc3RyXSA9IE5vbmUsCiAgICBmaXhlZF9wb2ludDogYm9vbCA9IEZhbHNlLAogICAgb3B0aW1pemVkX21vZGVsX25hbWU6IHN0ciA9IE5vbmUsCik6CiAgICAiIiIKICAgIE9wdGltaXplIHRoZSBnaXZlbiBPTk5YIG1vZGVsLgoKICAgIDpwYXJhbSBjb250ZXh0OiAgICAgICAgICAgICAgVGhlIE1MUnVuIGZ1bmN0aW9uIGV4ZWN1dGlvbiBjb250ZXh0LgogICAgOnBhcmFtIG1vZGVsX3BhdGg6ICAgICAgICAgICBQYXRoIHRvIHRoZSBPTk5YIG1vZGVsIG9iamVjdC4KICAgIDpwYXJhbSBoYW5kbGVyX2luaXRfa3dhcmdzOiAgS2V5d29yZCBhcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgYE9OTlhNb2RlbEhhbmRsZXJgIGluaXQgbWV0aG9kIHByZWxvYWRpbmcuCiAgICA6cGFyYW0gb3B0aW1pemF0aW9uczogICAgICAgIExpc3Qgb2YgcG9zc2libGUgb3B0aW1pemF0aW9ucy4gVG8gc2VlIHdoYXQgb3B0aW1pemF0aW9ucyBhcmUgYXZhaWxhYmxlLCBwYXNzICJoZWxwIi4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSWYgTm9uZSwgYWxsIHRoZSBvcHRpbWl6YXRpb25zIHdpbGwgYmUgdXNlZC4gRGVmYXVsdGVkIHRvIE5vbmUuCiAgICA6cGFyYW0gZml4ZWRfcG9pbnQ6ICAgICAgICAgIE9wdGltaXplIHRoZSB3ZWlnaHRzIHVzaW5nIGZpeGVkIHBvaW50LiBEZWZhdWx0ZWQgdG8gRmFsc2UuCiAgICA6cGFyYW0gb3B0aW1pemVkX21vZGVsX25hbWU6IFRoZSBuYW1lIG9mIHRoZSBvcHRpbWl6ZWQgbW9kZWwuIElmIE5vbmUsIHRoZSBvcmlnaW5hbCBtb2RlbCB3aWxsIGJlIG92ZXJyaWRkZW4uCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlZmF1bHRlZCB0byBOb25lLgogICAgIiIiCiAgICAjIEltcG9ydCB0aGUgbW9kZWwgaGFuZGxlcjoKICAgIGltcG9ydCBvbm54b3B0aW1pemVyCiAgICBmcm9tIG1scnVuLmZyYW1ld29ya3Mub25ueCBpbXBvcnQgT05OWE1vZGVsSGFuZGxlcgoKICAgICMgQ2hlY2sgaWYgbmVlZGVkIHRvIHByaW50IHRoZSBhdmFpbGFibGUgb3B0aW1pemF0aW9ucyAoImhlbHAiIGlzIHBhc3NlZCk6CiAgICBpZiBvcHRpbWl6YXRpb25zID09ICJoZWxwIjoKICAgICAgICBhdmFpbGFibGVfcGFzc2VzID0gIlxuKiAiLmpvaW4ob25ueG9wdGltaXplci5nZXRfYXZhaWxhYmxlX3Bhc3NlcygpKQogICAgICAgIHByaW50KGYiVGhlIGF2YWlsYWJsZSBvcHRpbWl6YXRpb25zIGFyZTpcbioge2F2YWlsYWJsZV9wYXNzZXN9IikKICAgICAgICByZXR1cm4KCiAgICAjIENyZWF0ZSB0aGUgbW9kZWwgaGFuZGxlcjoKICAgIGhhbmRsZXJfaW5pdF9rd2FyZ3MgPSBoYW5kbGVyX2luaXRfa3dhcmdzIG9yIHt9CiAgICBtb2RlbF9oYW5kbGVyID0gT05OWE1vZGVsSGFuZGxlcigKICAgICAgICBtb2RlbF9wYXRoPW1vZGVsX3BhdGgsIGNvbnRleHQ9Y29udGV4dCwgKipoYW5kbGVyX2luaXRfa3dhcmdzCiAgICApCgogICAgIyBMb2FkIHRoZSBPTk5YIG1vZGVsOgogICAgbW9kZWxfaGFuZGxlci5sb2FkKCkKCiAgICAjIE9wdGltaXplIHRoZSBtb2RlbCB1c2luZyB0aGUgZ2l2ZW4gY29uZmlndXJhdGlvbnM6CiAgICBtb2RlbF9oYW5kbGVyLm9wdGltaXplKG9wdGltaXphdGlvbnM9b3B0aW1pemF0aW9ucywgZml4ZWRfcG9pbnQ9Zml4ZWRfcG9pbnQpCgogICAgIyBSZW5hbWUgaWYgbmVlZGVkOgogICAgaWYgb3B0aW1pemVkX21vZGVsX25hbWUgaXMgbm90IE5vbmU6CiAgICAgICAgbW9kZWxfaGFuZGxlci5zZXRfbW9kZWxfbmFtZShtb2RlbF9uYW1lPW9wdGltaXplZF9tb2RlbF9uYW1lKQoKICAgICMgTG9nIHRoZSBvcHRpbWl6ZWQgbW9kZWw6CiAgICBtb2RlbF9oYW5kbGVyLmxvZygpCg==
- requirements:
- - tqdm~=4.67.1
- - tensorflow~=2.19.0
- - tf_keras~=2.19.0
- - torch~=2.6.0
- - torchvision~=0.21.0
- - onnx~=1.17.0
- - onnxruntime~=1.19.2
- - onnxoptimizer~=0.3.13
- - onnxmltools~=1.13.0
- - tf2onnx~=1.16.1
- - plotly~=5.23
- with_mlrun: false
- auto_build: true
- disable_auto_mount: false
- description: ONNX intigration in MLRun, some utils functions for the ONNX framework,
- optimizing and converting models from different framework to ONNX using MLRun.
- image: ''
entry_points:
tf_keras_to_onnx:
- doc: Convert a TF.Keras model to an ONNX model and log it back to MLRun as a
- new model object.
name: tf_keras_to_onnx
parameters:
- name: model_handler
@@ -58,12 +32,12 @@ spec:
data type, a mlrun.data_types.ValueType string. If None, the input signature
will be tried to be read from the model artifact. Defaulted to None.'
default: null
+ doc: Convert a TF.Keras model to an ONNX model and log it back to MLRun as a
+ new model object.
+ lineno: 26
has_varargs: false
has_kwargs: false
- lineno: 26
pytorch_to_onnx:
- doc: Convert a PyTorch model to an ONNX model and log it back to MLRun as a
- new model object.
name: pytorch_to_onnx
parameters:
- name: model_handler
@@ -116,11 +90,12 @@ spec:
doc: Whether to include a batch size as the first axis in every input and
output layer. Defaulted to True. Will be ignored if 'dynamic_axes' is provided.
default: true
+ doc: Convert a PyTorch model to an ONNX model and log it back to MLRun as a
+ new model object.
+ lineno: 81
has_varargs: false
has_kwargs: false
- lineno: 81
to_onnx:
- doc: Convert the given model to an ONNX model.
name: to_onnx
parameters:
- name: context
@@ -150,11 +125,11 @@ spec:
get the doc string of the desired framework onnx conversion function, pass
"help".
default: null
+ doc: Convert the given model to an ONNX model.
+ lineno: 160
has_varargs: false
has_kwargs: false
- lineno: 160
optimize:
- doc: Optimize the given ONNX model.
name: optimize
parameters:
- name: context
@@ -181,9 +156,34 @@ spec:
doc: The name of the optimized model. If None, the original model will be
overridden. Defaulted to None.
default: null
+ doc: Optimize the given ONNX model.
+ lineno: 224
has_varargs: false
has_kwargs: false
- lineno: 224
+ image: ''
default_handler: to_onnx
allow_empty_resources: true
command: ''
+ disable_auto_mount: false
+ description: ONNX intigration in MLRun, some utils functions for the ONNX framework,
+ optimizing and converting models from different framework to ONNX using MLRun.
+ build:
+ functionSourceCode: IyBDb3B5cmlnaHQgMjAxOSBJZ3VhemlvCiMKIyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiMgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiMKIyAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiMKIyBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiMgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KIyBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiMgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiMKZnJvbSB0eXBpbmcgaW1wb3J0IEFueSwgQ2FsbGFibGUsIERpY3QsIExpc3QsIFR1cGxlCgppbXBvcnQgbWxydW4KCgpjbGFzcyBfVG9PTk5YQ29udmVyc2lvbnM6CiAgICAiIiIKICAgIEFuIE9OTlggY29udmVyc2lvbiBmdW5jdGlvbnMgbGlicmFyeSBjbGFzcy4KICAgICIiIgoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiB0Zl9rZXJhc190b19vbm54KAogICAgICAgIG1vZGVsX2hhbmRsZXIsCiAgICAgICAgb25ueF9tb2RlbF9uYW1lOiBzdHIgPSBOb25lLAogICAgICAgIG9wdGltaXplX21vZGVsOiBib29sID0gVHJ1ZSwKICAgICAgICBpbnB1dF9zaWduYXR1cmU6IExpc3RbVHVwbGVbVHVwbGVbaW50XSwgc3RyXV0gPSBOb25lLAogICAgKToKICAgICAgICAiIiIKICAgICAgICBDb252ZXJ0IGEgVEYuS2VyYXMgbW9kZWwgdG8gYW4gT05OWCBtb2RlbCBhbmQgbG9nIGl0IGJhY2sgdG8gTUxSdW4gYXMgYSBuZXcgbW9kZWwgb2JqZWN0LgoKICAgICAgICA6cGFyYW0gbW9kZWxfaGFuZGxlcjogICBBbiBpbml0aWFsaXplZCBURktlcmFzTW9kZWxIYW5kbGVyIHdpdGggYSBsb2FkZWQgbW9kZWwgdG8gY29udmVydCB0byBPTk5YLgogICAgICAgIDpwYXJhbSBvbm54X21vZGVsX25hbWU6IFRoZSBuYW1lIHRvIHVzZSB0byBsb2cgdGhlIGNvbnZlcnRlZCBPTk5YIG1vZGVsLiBJZiBub3QgZ2l2ZW4sIHRoZSBnaXZlbiBgbW9kZWxfbmFtZWAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aWxsIGJlIHVzZWQgd2l0aCBhbiBhZGRpdGlvbmFsIHN1ZmZpeCBgX29ubnhgLiBEZWZhdWx0ZWQgdG8gTm9uZS4KICAgICAgICA6cGFyYW0gb3B0aW1pemVfbW9kZWw6ICBXaGV0aGVyIG9yIG5vdCB0byBvcHRpbWl6ZSB0aGUgT05OWCBtb2RlbCB1c2luZyAnb25ueG9wdGltaXplcicgYmVmb3JlIHNhdmluZyB0aGUgbW9kZWwuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVmYXVsdGVkIHRvIFRydWUuCiAgICAgICAgOnBhcmFtIGlucHV0X3NpZ25hdHVyZTogQSBsaXN0IG9mIHRoZSBpbnB1dCBsYXllcnMgc2hhcGUgYW5kIGRhdGEgdHlwZSBwcm9wZXJ0aWVzLiBFeHBlY3RlZCB0byByZWNlaXZlIGEgbGlzdAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoZXJlIGVhY2ggZWxlbWVudCBpcyBhbiBpbnB1dCBsYXllciB0dXBsZS4gQW4gaW5wdXQgbGF5ZXIgdHVwbGUgaXMgYSB0dXBsZSBvZjoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbMF0gPSBMYXllcidzIHNoYXBlLCBhIHR1cGxlIG9mIGludGVnZXJzLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFsxXSA9IExheWVyJ3MgZGF0YSB0eXBlLCBhIG1scnVuLmRhdGFfdHlwZXMuVmFsdWVUeXBlIHN0cmluZy4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJZiBOb25lLCB0aGUgaW5wdXQgc2lnbmF0dXJlIHdpbGwgYmUgdHJpZWQgdG8gYmUgcmVhZCBmcm9tIHRoZSBtb2RlbCBhcnRpZmFjdC4gRGVmYXVsdGVkCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG8gTm9uZS4KICAgICAgICAiIiIKICAgICAgICAjIEltcG9ydCB0aGUgZnJhbWV3b3JrIGFuZCBoYW5kbGVyOgogICAgICAgIGltcG9ydCB0ZW5zb3JmbG93IGFzIHRmCiAgICAgICAgZnJvbSBtbHJ1bi5mcmFtZXdvcmtzLnRmX2tlcmFzIGltcG9ydCBURktlcmFzVXRpbHMKCiAgICAgICAgIyBDaGVjayB0aGUgZ2l2ZW4gJ2lucHV0X3NpZ25hdHVyZScgcGFyYW1ldGVyOgogICAgICAgIGlmIGlucHV0X3NpZ25hdHVyZSBpcyBOb25lOgogICAgICAgICAgICAjIFJlYWQgdGhlIGlucHV0cyBmcm9tIHRoZSBtb2RlbDoKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgbW9kZWxfaGFuZGxlci5yZWFkX2lucHV0c19mcm9tX21vZGVsKCkKICAgICAgICAgICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlcnJvcjoKICAgICAgICAgICAgICAgIHJhaXNlIG1scnVuLmVycm9ycy5NTFJ1blJ1bnRpbWVFcnJvcigKICAgICAgICAgICAgICAgICAgICBmIlBsZWFzZSBwcm92aWRlIHRoZSAnaW5wdXRfc2lnbmF0dXJlJyBwYXJhbWV0ZXIuIFRoZSBmdW5jdGlvbiB0cmllZCByZWFkaW5nIHRoZSBpbnB1dCBsYXllcnMgIgogICAgICAgICAgICAgICAgICAgIGYiaW5mb3JtYXRpb24gYXV0b21hdGljYWxseSBidXQgZmFpbGVkIHdpdGggdGhlIGZvbGxvd2luZyBlcnJvcjoge2Vycm9yfSIKICAgICAgICAgICAgICAgICkKICAgICAgICBlbHNlOgogICAgICAgICAgICAjIFBhcnNlIHRoZSAnaW5wdXRfc2lnbmF0dXJlJyBwYXJhbWV0ZXI6CiAgICAgICAgICAgIGlucHV0X3NpZ25hdHVyZSA9IFsKICAgICAgICAgICAgICAgIHRmLlRlbnNvclNwZWMoCiAgICAgICAgICAgICAgICAgICAgc2hhcGU9c2hhcGUsCiAgICAgICAgICAgICAgICAgICAgZHR5cGU9VEZLZXJhc1V0aWxzLmNvbnZlcnRfdmFsdWVfdHlwZV90b190Zl9kdHlwZSgKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVfdHlwZT12YWx1ZV90eXBlCiAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIGZvciAoc2hhcGUsIHZhbHVlX3R5cGUpIGluIGlucHV0X3NpZ25hdHVyZQogICAgICAgICAgICBdCgogICAgICAgICMgQ29udmVydCB0byBPTk5YOgogICAgICAgIG1vZGVsX2hhbmRsZXIudG9fb25ueCgKICAgICAgICAgICAgbW9kZWxfbmFtZT1vbm54X21vZGVsX25hbWUsCiAgICAgICAgICAgIGlucHV0X3NpZ25hdHVyZT1pbnB1dF9zaWduYXR1cmUsCiAgICAgICAgICAgIG9wdGltaXplPW9wdGltaXplX21vZGVsLAogICAgICAgICkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgcHl0b3JjaF90b19vbm54KAogICAgICAgIG1vZGVsX2hhbmRsZXIsCiAgICAgICAgb25ueF9tb2RlbF9uYW1lOiBzdHIgPSBOb25lLAogICAgICAgIG9wdGltaXplX21vZGVsOiBib29sID0gVHJ1ZSwKICAgICAgICBpbnB1dF9zaWduYXR1cmU6IExpc3RbVHVwbGVbVHVwbGVbaW50LCAuLi5dLCBzdHJdXSA9IE5vbmUsCiAgICAgICAgaW5wdXRfbGF5ZXJzX25hbWVzOiBMaXN0W3N0cl0gPSBOb25lLAogICAgICAgIG91dHB1dF9sYXllcnNfbmFtZXM6IExpc3Rbc3RyXSA9IE5vbmUsCiAgICAgICAgZHluYW1pY19heGVzOiBEaWN0W3N0ciwgRGljdFtpbnQsIHN0cl1dID0gTm9uZSwKICAgICAgICBpc19iYXRjaGVkOiBib29sID0gVHJ1ZSwKICAgICk6CiAgICAgICAgIiIiCiAgICAgICAgQ29udmVydCBhIFB5VG9yY2ggbW9kZWwgdG8gYW4gT05OWCBtb2RlbCBhbmQgbG9nIGl0IGJhY2sgdG8gTUxSdW4gYXMgYSBuZXcgbW9kZWwgb2JqZWN0LgoKICAgICAgICA6cGFyYW0gbW9kZWxfaGFuZGxlcjogICAgICAgQW4gaW5pdGlhbGl6ZWQgUHlUb3JjaE1vZGVsSGFuZGxlciB3aXRoIGEgbG9hZGVkIG1vZGVsIHRvIGNvbnZlcnQgdG8gT05OWC4KICAgICAgICA6cGFyYW0gb25ueF9tb2RlbF9uYW1lOiAgICAgVGhlIG5hbWUgdG8gdXNlIHRvIGxvZyB0aGUgY29udmVydGVkIE9OTlggbW9kZWwuIElmIG5vdCBnaXZlbiwgdGhlIGdpdmVuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBtb2RlbF9uYW1lYCB3aWxsIGJlIHVzZWQgd2l0aCBhbiBhZGRpdGlvbmFsIHN1ZmZpeCBgX29ubnhgLiBEZWZhdWx0ZWQgdG8gTm9uZS4KICAgICAgICA6cGFyYW0gb3B0aW1pemVfbW9kZWw6ICAgICAgV2hldGhlciBvciBub3QgdG8gb3B0aW1pemUgdGhlIE9OTlggbW9kZWwgdXNpbmcgJ29ubnhvcHRpbWl6ZXInIGJlZm9yZSBzYXZpbmcgdGhlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLiBEZWZhdWx0ZWQgdG8gVHJ1ZS4KICAgICAgICA6cGFyYW0gaW5wdXRfc2lnbmF0dXJlOiAgICAgQSBsaXN0IG9mIHRoZSBpbnB1dCBsYXllcnMgc2hhcGUgYW5kIGRhdGEgdHlwZSBwcm9wZXJ0aWVzLiBFeHBlY3RlZCB0byByZWNlaXZlIGEKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdCB3aGVyZSBlYWNoIGVsZW1lbnQgaXMgYW4gaW5wdXQgbGF5ZXIgdHVwbGUuIEFuIGlucHV0IGxheWVyIHR1cGxlIGlzIGEgdHVwbGUgb2Y6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFswXSA9IExheWVyJ3Mgc2hhcGUsIGEgdHVwbGUgb2YgaW50ZWdlcnMuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFsxXSA9IExheWVyJ3MgZGF0YSB0eXBlLCBhIG1scnVuLmRhdGFfdHlwZXMuVmFsdWVUeXBlIHN0cmluZy4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSWYgTm9uZSwgdGhlIGlucHV0IHNpZ25hdHVyZSB3aWxsIGJlIHRyaWVkIHRvIGJlIHJlYWQgZnJvbSB0aGUgbW9kZWwgYXJ0aWZhY3QuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlZmF1bHRlZCB0byBOb25lLgogICAgICAgIDpwYXJhbSBpbnB1dF9sYXllcnNfbmFtZXM6ICBMaXN0IG9mIG5hbWVzIHRvIGFzc2lnbiB0byB0aGUgaW5wdXQgbm9kZXMgb2YgdGhlIGdyYXBoIGluIG9yZGVyLiBBbGwgb2YgdGhlIG90aGVyCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtZXRlcnMgKGlubmVyIGxheWVycykgY2FuIGJlIHNldCBhcyB3ZWxsIGJ5IHBhc3NpbmcgYWRkaXRpb25hbCBuYW1lcyBpbiB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdC4gVGhlIG9yZGVyIGlzIGJ5IHRoZSBvcmRlciBvZiB0aGUgcGFyYW1ldGVycyBpbiB0aGUgbW9kZWwuIElmIE5vbmUsIHRoZSBpbnB1dHMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lsbCBiZSByZWFkIGZyb20gdGhlIGhhbmRsZXIncyBpbnB1dHMuIElmIGl0cyBhbHNvIE5vbmUsIGl0IGlzIGRlZmF1bHRlZCB0bzoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImlucHV0XzAiLCAiaW5wdXRfMSIsIC4uLgogICAgICAgIDpwYXJhbSBvdXRwdXRfbGF5ZXJzX25hbWVzOiBMaXN0IG9mIG5hbWVzIHRvIGFzc2lnbiB0byB0aGUgb3V0cHV0IG5vZGVzIG9mIHRoZSBncmFwaCBpbiBvcmRlci4gSWYgTm9uZSwgdGhlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dHMgd2lsbCBiZSByZWFkIGZyb20gdGhlIGhhbmRsZXIncyBvdXRwdXRzLiBJZiBpdHMgYWxzbyBOb25lLCBpdCBpcyBkZWZhdWx0ZWQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG86ICJvdXRwdXRfMCIgKGZvciBtdWx0aXBsZSBvdXRwdXRzLCB0aGlzIHBhcmFtZXRlciBtdXN0IGJlIHByb3ZpZGVkKS4KICAgICAgICA6cGFyYW0gZHluYW1pY19heGVzOiAgICAgICAgSWYgcGFydCBvZiB0aGUgaW5wdXQgLyBvdXRwdXQgc2hhcGUgaXMgZHluYW1pYywgbGlrZSAoYmF0Y2hfc2l6ZSwgMywgMzIsIDMyKSB5b3UgY2FuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNpZnkgaXQgYnkgZ2l2aW5nIGEgZHluYW1pYyBheGlzIHRvIHRoZSBpbnB1dCAvIG91dHB1dCBsYXllciBieSBpdHMgbmFtZSBhcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb2xsb3dzOiB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaW5wdXQgbGF5ZXIgbmFtZSI6IHswOiAiYmF0Y2hfc2l6ZSJ9LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm91dHB1dCBsYXllciBuYW1lIjogezA6ICJiYXRjaF9zaXplIn0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSWYgcHJvdmlkZWQsIHRoZSAnaXNfYmF0Y2hlZCcgZmxhZyB3aWxsIGJlIGlnbm9yZWQuIERlZmF1bHRlZCB0byBOb25lLgogICAgICAgIDpwYXJhbSBpc19iYXRjaGVkOiAgICAgICAgICBXaGV0aGVyIHRvIGluY2x1ZGUgYSBiYXRjaCBzaXplIGFzIHRoZSBmaXJzdCBheGlzIGluIGV2ZXJ5IGlucHV0IGFuZCBvdXRwdXQgbGF5ZXIuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlZmF1bHRlZCB0byBUcnVlLiBXaWxsIGJlIGlnbm9yZWQgaWYgJ2R5bmFtaWNfYXhlcycgaXMgcHJvdmlkZWQuCiAgICAgICAgIiIiCiAgICAgICAgIyBJbXBvcnQgdGhlIGZyYW1ld29yayBhbmQgaGFuZGxlcjoKICAgICAgICBpbXBvcnQgdG9yY2gKICAgICAgICBmcm9tIG1scnVuLmZyYW1ld29ya3MucHl0b3JjaCBpbXBvcnQgUHlUb3JjaFV0aWxzCgogICAgICAgICMgUGFyc2UgdGhlICdpbnB1dF9zaWduYXR1cmUnIHBhcmFtZXRlcjoKICAgICAgICBpZiBpbnB1dF9zaWduYXR1cmUgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIGlucHV0X3NpZ25hdHVyZSA9IHR1cGxlKAogICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgIHRvcmNoLnplcm9zKAogICAgICAgICAgICAgICAgICAgICAgICBzaXplPXNoYXBlLAogICAgICAgICAgICAgICAgICAgICAgICBkdHlwZT1QeVRvcmNoVXRpbHMuY29udmVydF92YWx1ZV90eXBlX3RvX3RvcmNoX2R0eXBlKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVfdHlwZT12YWx1ZV90eXBlCiAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgIGZvciAoc2hhcGUsIHZhbHVlX3R5cGUpIGluIGlucHV0X3NpZ25hdHVyZQogICAgICAgICAgICAgICAgXQogICAgICAgICAgICApCgogICAgICAgICMgQ29udmVydCB0byBPTk5YOgogICAgICAgIG1vZGVsX2hhbmRsZXIudG9fb25ueCgKICAgICAgICAgICAgbW9kZWxfbmFtZT1vbm54X21vZGVsX25hbWUsCiAgICAgICAgICAgIGlucHV0X3NhbXBsZT1pbnB1dF9zaWduYXR1cmUsCiAgICAgICAgICAgIG9wdGltaXplPW9wdGltaXplX21vZGVsLAogICAgICAgICAgICBpbnB1dF9sYXllcnNfbmFtZXM9aW5wdXRfbGF5ZXJzX25hbWVzLAogICAgICAgICAgICBvdXRwdXRfbGF5ZXJzX25hbWVzPW91dHB1dF9sYXllcnNfbmFtZXMsCiAgICAgICAgICAgIGR5bmFtaWNfYXhlcz1keW5hbWljX2F4ZXMsCiAgICAgICAgICAgIGlzX2JhdGNoZWQ9aXNfYmF0Y2hlZCwKICAgICAgICApCgoKIyBNYXAgZm9yIGdldHRpbmcgdGhlIGNvbnZlcnNpb24gZnVuY3Rpb24gYWNjb3JkaW5nIHRvIHRoZSBwcm92aWRlZCBmcmFtZXdvcms6Cl9DT05WRVJTSU9OX01BUCA9IHsKICAgICJ0ZW5zb3JmbG93LmtlcmFzIjogX1RvT05OWENvbnZlcnNpb25zLnRmX2tlcmFzX3RvX29ubngsCiAgICAidG9yY2giOiBfVG9PTk5YQ29udmVyc2lvbnMucHl0b3JjaF90b19vbm54LAp9ICAjIHR5cGU6IERpY3Rbc3RyLCBDYWxsYWJsZV0KCgpkZWYgdG9fb25ueCgKICAgIGNvbnRleHQ6IG1scnVuLk1MQ2xpZW50Q3R4LAogICAgbW9kZWxfcGF0aDogc3RyLAogICAgbG9hZF9tb2RlbF9rd2FyZ3M6IGRpY3QgPSBOb25lLAogICAgb25ueF9tb2RlbF9uYW1lOiBzdHIgPSBOb25lLAogICAgb3B0aW1pemVfbW9kZWw6IGJvb2wgPSBUcnVlLAogICAgZnJhbWV3b3JrX2t3YXJnczogRGljdFtzdHIsIEFueV0gPSBOb25lLAopOgogICAgIiIiCiAgICBDb252ZXJ0IHRoZSBnaXZlbiBtb2RlbCB0byBhbiBPTk5YIG1vZGVsLgoKICAgIDpwYXJhbSBjb250ZXh0OiAgICAgICAgICAgVGhlIE1MUnVuIGZ1bmN0aW9uIGV4ZWN1dGlvbiBjb250ZXh0CiAgICA6cGFyYW0gbW9kZWxfcGF0aDogICAgICAgIFRoZSBtb2RlbCBwYXRoIHN0b3JlIG9iamVjdC4KICAgIDpwYXJhbSBsb2FkX21vZGVsX2t3YXJnczogS2V5d29yZCBhcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgYEF1dG9NTFJ1bi5sb2FkX21vZGVsYCBtZXRob2QuCiAgICA6cGFyYW0gb25ueF9tb2RlbF9uYW1lOiAgIFRoZSBuYW1lIHRvIHVzZSB0byBsb2cgdGhlIGNvbnZlcnRlZCBPTk5YIG1vZGVsLiBJZiBub3QgZ2l2ZW4sIHRoZSBnaXZlbiBgbW9kZWxfbmFtZWAgd2lsbAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZSB1c2VkIHdpdGggYW4gYWRkaXRpb25hbCBzdWZmaXggYF9vbm54YC4gRGVmYXVsdGVkIHRvIE5vbmUuCiAgICA6cGFyYW0gb3B0aW1pemVfbW9kZWw6ICAgIFdoZXRoZXIgdG8gb3B0aW1pemUgdGhlIE9OTlggbW9kZWwgdXNpbmcgJ29ubnhvcHRpbWl6ZXInIGJlZm9yZSBzYXZpbmcgdGhlIG1vZGVsLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEZWZhdWx0ZWQgdG8gVHJ1ZS4KICAgIDpwYXJhbSBmcmFtZXdvcmtfa3dhcmdzOiAgQWRkaXRpb25hbCBhcmd1bWVudHMgZWFjaCBmcmFtZXdvcmsgbWF5IHJlcXVpcmUgdG8gY29udmVydCB0byBPTk5YLiBUbyBnZXQgdGhlIGRvYyBzdHJpbmcKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2YgdGhlIGRlc2lyZWQgZnJhbWV3b3JrIG9ubnggY29udmVyc2lvbiBmdW5jdGlvbiwgcGFzcyAiaGVscCIuCiAgICAiIiIKICAgIGZyb20gbWxydW4uZnJhbWV3b3Jrcy5hdXRvX21scnVuLmF1dG9fbWxydW4gaW1wb3J0IEF1dG9NTFJ1bgoKICAgICMgR2V0IGEgbW9kZWwgaGFuZGxlciBvZiB0aGUgcmVxdWlyZWQgZnJhbWV3b3JrOgogICAgbG9hZF9tb2RlbF9rd2FyZ3MgPSBsb2FkX21vZGVsX2t3YXJncyBvciB7fQogICAgbW9kZWxfaGFuZGxlciA9IEF1dG9NTFJ1bi5sb2FkX21vZGVsKAogICAgICAgIG1vZGVsX3BhdGg9bW9kZWxfcGF0aCwgY29udGV4dD1jb250ZXh0LCAqKmxvYWRfbW9kZWxfa3dhcmdzCiAgICApCgogICAgIyBHZXQgdGhlIG1vZGVsJ3MgZnJhbWV3b3JrOgogICAgZnJhbWV3b3JrID0gbW9kZWxfaGFuZGxlci5GUkFNRVdPUktfTkFNRQoKICAgICMgVXNlIHRoZSBjb252ZXJzaW9uIG1hcCB0byBnZXQgdGhlIHNwZWNpZmljIGZyYW1ld29yayB0byBvbm54IGNvbnZlcnNpb246CiAgICBpZiBmcmFtZXdvcmsgbm90IGluIF9DT05WRVJTSU9OX01BUDoKICAgICAgICByYWlzZSBtbHJ1bi5lcnJvcnMuTUxSdW5JbnZhbGlkQXJndW1lbnRFcnJvcigKICAgICAgICAgICAgZiJUaGUgZm9sbG93aW5nIGZyYW1ld29yazogJ3tmcmFtZXdvcmt9JywgaGFzIG5vIE9OTlggY29udmVyc2lvbi4iCiAgICAgICAgKQogICAgY29udmVyc2lvbl9mdW5jdGlvbiA9IF9DT05WRVJTSU9OX01BUFtmcmFtZXdvcmtdCgogICAgIyBDaGVjayBpZiBuZWVkZWQgdG8gcHJpbnQgdGhlIGZ1bmN0aW9uJ3MgZG9jIHN0cmluZyAoImhlbHAiIGlzIHBhc3NlZCk6CiAgICBpZiBmcmFtZXdvcmtfa3dhcmdzID09ICJoZWxwIjoKICAgICAgICBwcmludChjb252ZXJzaW9uX2Z1bmN0aW9uLl9fZG9jX18pCiAgICAgICAgcmV0dXJuCgogICAgIyBTZXQgdGhlIGRlZmF1bHQgZW1wdHkgZnJhbWV3b3JrIGt3YXJncyBpZiBuZWVkZWQ6CiAgICBpZiBmcmFtZXdvcmtfa3dhcmdzIGlzIE5vbmU6CiAgICAgICAgZnJhbWV3b3JrX2t3YXJncyA9IHt9CgogICAgIyBSdW4gdGhlIGNvbnZlcnNpb246CiAgICB0cnk6CiAgICAgICAgY29udmVyc2lvbl9mdW5jdGlvbigKICAgICAgICAgICAgbW9kZWxfaGFuZGxlcj1tb2RlbF9oYW5kbGVyLAogICAgICAgICAgICBvbm54X21vZGVsX25hbWU9b25ueF9tb2RlbF9uYW1lLAogICAgICAgICAgICBvcHRpbWl6ZV9tb2RlbD1vcHRpbWl6ZV9tb2RlbCwKICAgICAgICAgICAgKipmcmFtZXdvcmtfa3dhcmdzLAogICAgICAgICkKICAgIGV4Y2VwdCBUeXBlRXJyb3IgYXMgZXhjZXB0aW9uOgogICAgICAgIHJhaXNlIG1scnVuLmVycm9ycy5NTFJ1bkludmFsaWRBcmd1bWVudEVycm9yKAogICAgICAgICAgICBmIkVSUk9SOiBBIFR5cGVFcnJvciBleGNlcHRpb24gd2FzIHJhaXNlZCBkdXJpbmcgdGhlIGNvbnZlcnNpb246XG57ZXhjZXB0aW9ufS4gIgogICAgICAgICAgICBmIlBsZWFzZSByZWFkIHRoZSB7ZnJhbWV3b3JrfSBmcmFtZXdvcmsgY29udmVyc2lvbiBmdW5jdGlvbiBkb2Mgc3RyaW5nIGJ5IHBhc3NpbmcgJ2hlbHAnIGluIHRoZSAiCiAgICAgICAgICAgIGYiJ2ZyYW1ld29ya19rd2FyZ3MnIGRpY3Rpb25hcnkgcGFyYW1ldGVyLiIKICAgICAgICApCgoKZGVmIG9wdGltaXplKAogICAgY29udGV4dDogbWxydW4uTUxDbGllbnRDdHgsCiAgICBtb2RlbF9wYXRoOiBzdHIsCiAgICBoYW5kbGVyX2luaXRfa3dhcmdzOiBkaWN0ID0gTm9uZSwKICAgIG9wdGltaXphdGlvbnM6IExpc3Rbc3RyXSA9IE5vbmUsCiAgICBmaXhlZF9wb2ludDogYm9vbCA9IEZhbHNlLAogICAgb3B0aW1pemVkX21vZGVsX25hbWU6IHN0ciA9IE5vbmUsCik6CiAgICAiIiIKICAgIE9wdGltaXplIHRoZSBnaXZlbiBPTk5YIG1vZGVsLgoKICAgIDpwYXJhbSBjb250ZXh0OiAgICAgICAgICAgICAgVGhlIE1MUnVuIGZ1bmN0aW9uIGV4ZWN1dGlvbiBjb250ZXh0LgogICAgOnBhcmFtIG1vZGVsX3BhdGg6ICAgICAgICAgICBQYXRoIHRvIHRoZSBPTk5YIG1vZGVsIG9iamVjdC4KICAgIDpwYXJhbSBoYW5kbGVyX2luaXRfa3dhcmdzOiAgS2V5d29yZCBhcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgYE9OTlhNb2RlbEhhbmRsZXJgIGluaXQgbWV0aG9kIHByZWxvYWRpbmcuCiAgICA6cGFyYW0gb3B0aW1pemF0aW9uczogICAgICAgIExpc3Qgb2YgcG9zc2libGUgb3B0aW1pemF0aW9ucy4gVG8gc2VlIHdoYXQgb3B0aW1pemF0aW9ucyBhcmUgYXZhaWxhYmxlLCBwYXNzICJoZWxwIi4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSWYgTm9uZSwgYWxsIHRoZSBvcHRpbWl6YXRpb25zIHdpbGwgYmUgdXNlZC4gRGVmYXVsdGVkIHRvIE5vbmUuCiAgICA6cGFyYW0gZml4ZWRfcG9pbnQ6ICAgICAgICAgIE9wdGltaXplIHRoZSB3ZWlnaHRzIHVzaW5nIGZpeGVkIHBvaW50LiBEZWZhdWx0ZWQgdG8gRmFsc2UuCiAgICA6cGFyYW0gb3B0aW1pemVkX21vZGVsX25hbWU6IFRoZSBuYW1lIG9mIHRoZSBvcHRpbWl6ZWQgbW9kZWwuIElmIE5vbmUsIHRoZSBvcmlnaW5hbCBtb2RlbCB3aWxsIGJlIG92ZXJyaWRkZW4uCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlZmF1bHRlZCB0byBOb25lLgogICAgIiIiCiAgICAjIEltcG9ydCB0aGUgbW9kZWwgaGFuZGxlcjoKICAgIGltcG9ydCBvbm54b3B0aW1pemVyCiAgICBmcm9tIG1scnVuLmZyYW1ld29ya3Mub25ueCBpbXBvcnQgT05OWE1vZGVsSGFuZGxlcgoKICAgICMgQ2hlY2sgaWYgbmVlZGVkIHRvIHByaW50IHRoZSBhdmFpbGFibGUgb3B0aW1pemF0aW9ucyAoImhlbHAiIGlzIHBhc3NlZCk6CiAgICBpZiBvcHRpbWl6YXRpb25zID09ICJoZWxwIjoKICAgICAgICBhdmFpbGFibGVfcGFzc2VzID0gIlxuKiAiLmpvaW4ob25ueG9wdGltaXplci5nZXRfYXZhaWxhYmxlX3Bhc3NlcygpKQogICAgICAgIHByaW50KGYiVGhlIGF2YWlsYWJsZSBvcHRpbWl6YXRpb25zIGFyZTpcbioge2F2YWlsYWJsZV9wYXNzZXN9IikKICAgICAgICByZXR1cm4KCiAgICAjIENyZWF0ZSB0aGUgbW9kZWwgaGFuZGxlcjoKICAgIGhhbmRsZXJfaW5pdF9rd2FyZ3MgPSBoYW5kbGVyX2luaXRfa3dhcmdzIG9yIHt9CiAgICBtb2RlbF9oYW5kbGVyID0gT05OWE1vZGVsSGFuZGxlcigKICAgICAgICBtb2RlbF9wYXRoPW1vZGVsX3BhdGgsIGNvbnRleHQ9Y29udGV4dCwgKipoYW5kbGVyX2luaXRfa3dhcmdzCiAgICApCgogICAgIyBMb2FkIHRoZSBPTk5YIG1vZGVsOgogICAgbW9kZWxfaGFuZGxlci5sb2FkKCkKCiAgICAjIE9wdGltaXplIHRoZSBtb2RlbCB1c2luZyB0aGUgZ2l2ZW4gY29uZmlndXJhdGlvbnM6CiAgICBtb2RlbF9oYW5kbGVyLm9wdGltaXplKG9wdGltaXphdGlvbnM9b3B0aW1pemF0aW9ucywgZml4ZWRfcG9pbnQ9Zml4ZWRfcG9pbnQpCgogICAgIyBSZW5hbWUgaWYgbmVlZGVkOgogICAgaWYgb3B0aW1pemVkX21vZGVsX25hbWUgaXMgbm90IE5vbmU6CiAgICAgICAgbW9kZWxfaGFuZGxlci5zZXRfbW9kZWxfbmFtZShtb2RlbF9uYW1lPW9wdGltaXplZF9tb2RlbF9uYW1lKQoKICAgICMgTG9nIHRoZSBvcHRpbWl6ZWQgbW9kZWw6CiAgICBtb2RlbF9oYW5kbGVyLmxvZygpCg==
+ base_image: mlrun/mlrun
+ with_mlrun: false
+ auto_build: true
+ requirements:
+ - tqdm~=4.67.1
+ - tensorflow~=2.19.0
+ - tf_keras~=2.19.0
+ - torch~=2.8.0
+ - torchvision~=0.23.0
+ - onnx~=1.17.0
+ - onnxruntime~=1.19.2
+ - onnxoptimizer~=0.3.13
+ - onnxmltools~=1.13.0
+ - tf2onnx~=1.16.1
+ - plotly~=5.23
+ origin_filename: ''
+ code_origin: ''
+verbose: false
diff --git a/functions/development/onnx_utils/latest/src/item.yaml b/functions/development/onnx_utils/latest/src/item.yaml
index 803bd259..5f129389 100644
--- a/functions/development/onnx_utils/latest/src/item.yaml
+++ b/functions/development/onnx_utils/latest/src/item.yaml
@@ -13,7 +13,7 @@ labels:
author: Iguazio
maintainers: []
marketplaceType: ''
-mlrunVersion: 1.7.2
+mlrunVersion: 1.10.0
name: onnx_utils
platformVersion: 3.5.0
spec:
@@ -30,8 +30,8 @@ spec:
- tqdm~=4.67.1
- tensorflow~=2.19.0
- tf_keras~=2.19.0
- - torch~=2.6.0
- - torchvision~=0.21.0
+ - torch~=2.8.0
+ - torchvision~=0.23.0
- onnx~=1.17.0
- onnxruntime~=1.19.2
- onnxoptimizer~=0.3.13
@@ -39,4 +39,4 @@ spec:
- tf2onnx~=1.16.1
- plotly~=5.23
url: ''
-version: 1.3.0
+version: 1.4.0
diff --git a/functions/development/onnx_utils/latest/src/onnx_utils.ipynb b/functions/development/onnx_utils/latest/src/onnx_utils.ipynb
index 78203a45..14c810fa 100644
--- a/functions/development/onnx_utils/latest/src/onnx_utils.ipynb
+++ b/functions/development/onnx_utils/latest/src/onnx_utils.ipynb
@@ -77,9 +77,9 @@
"source": [
"### 1.2. Demo\n",
"\n",
- "We will use the `TF.Keras` framework, a `MobileNetV2` as our model and we will convert it to ONNX using the `to_onnx` handler.\n",
+ "We will use the `PyTorch` framework, a `MobileNetV2` as our model and we will convert it to ONNX using the `to_onnx` handler.\n",
"\n",
- "1.2.1. First we will set a temporary artifact path for our model to be saved in and choose the models names:"
+ "1.2.1. First we will set the artifact path for our model to be saved in and choose the models names:"
]
},
{
@@ -87,16 +87,21 @@
"metadata": {
"pycharm": {
"name": "#%%\n"
+ },
+ "ExecuteTime": {
+ "end_time": "2026-02-10T14:13:28.256582Z",
+ "start_time": "2026-02-10T14:13:28.250886Z"
}
},
"source": [
"import os\n",
- "os.environ[\"TF_USE_LEGACY_KERAS\"] = \"true\"\n",
- "from tempfile import TemporaryDirectory\n",
+ "import tempfile\n",
+ "# Use a temporary directory for model artifacts (safe cleanup):\n",
+ "ARTIFACT_PATH = tempfile.mkdtemp()\n",
+ "os.environ[\"MLRUN_ARTIFACT_PATH\"] = ARTIFACT_PATH\n",
"\n",
- "# Create a temporary directory for the model artifact:\n",
- "ARTIFACT_PATH = TemporaryDirectory().name\n",
- "os.makedirs(ARTIFACT_PATH)\n",
+ "# Project name:\n",
+ "PROJECT_NAME = \"onnx-utils\"\n",
"\n",
"# Choose our model's name:\n",
"MODEL_NAME = \"mobilenetv2\"\n",
@@ -108,7 +113,7 @@
"OPTIMIZED_ONNX_MODEL_NAME = \"optimized_onnx_mobilenetv2\""
],
"outputs": [],
- "execution_count": null
+ "execution_count": 1
},
{
"cell_type": "markdown",
@@ -118,87 +123,88 @@
}
},
"source": [
- "1.2.2. Download the model from `keras.applications` and log it with MLRun's `TFKerasModelHandler`:"
+ "1.2.2. Download the model from `torchvision.models` and log it with MLRun's `PyTorchModelHandler`:"
]
},
{
- "cell_type": "code",
"metadata": {
- "pycharm": {
- "name": "#%%\n"
+ "ExecuteTime": {
+ "end_time": "2026-02-10T14:00:15.032590Z",
+ "start_time": "2026-02-10T14:00:15.031196Z"
}
},
- "source": [
- "# mlrun: start-code"
- ],
+ "cell_type": "code",
+ "source": "# mlrun: start-code",
"outputs": [],
- "execution_count": null
+ "execution_count": 8
},
{
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2026-02-10T14:14:00.992001Z",
+ "start_time": "2026-02-10T14:13:33.115438Z"
+ }
+ },
"cell_type": "code",
- "metadata": {},
"source": [
- "from tensorflow import keras\n",
+ "import torchvision\n",
"\n",
"import mlrun\n",
- "import mlrun.frameworks.tf_keras as mlrun_tf_keras\n",
+ "from mlrun.frameworks.pytorch import PyTorchModelHandler\n",
"\n",
"\n",
"def get_model(context: mlrun.MLClientCtx, model_name: str):\n",
" # Download the MobileNetV2 model:\n",
- " model = keras.applications.mobilenet_v2.MobileNetV2()\n",
+ " model = torchvision.models.mobilenet_v2()\n",
"\n",
" # Initialize a model handler for logging the model:\n",
- " model_handler = mlrun_tf_keras.TFKerasModelHandler(\n",
+ " model_handler = PyTorchModelHandler(\n",
" model_name=model_name,\n",
" model=model,\n",
- " context=context\n",
+ " model_class=\"mobilenet_v2\",\n",
+ " modules_map={\"torchvision.models\": \"mobilenet_v2\"},\n",
+ " context=context,\n",
" )\n",
"\n",
" # Log the model:\n",
" model_handler.log()"
],
"outputs": [],
- "execution_count": null
+ "execution_count": 2
},
{
- "cell_type": "code",
"metadata": {
- "pycharm": {
- "name": "#%%\n"
+ "ExecuteTime": {
+ "end_time": "2026-02-10T14:00:15.040221Z",
+ "start_time": "2026-02-10T14:00:15.038886Z"
}
},
- "source": [
- "# mlrun: end-code"
- ],
+ "cell_type": "code",
+ "source": "# mlrun: end-code",
"outputs": [],
- "execution_count": null
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "pycharm": {
- "name": "#%% md\n"
- }
- },
- "source": [
- "1.2.3. Create the function using MLRun's `code_to_function` and run it:"
- ]
+ "execution_count": 10
},
{
"cell_type": "code",
"metadata": {
"pycharm": {
"name": "#%%\n"
+ },
+ "ExecuteTime": {
+ "end_time": "2026-02-10T14:14:34.429194Z",
+ "start_time": "2026-02-10T14:14:07.906087Z"
}
},
"source": [
"import mlrun\n",
"\n",
+ "# Create or get the MLRun project:\n",
+ "project = mlrun.get_or_create_project(PROJECT_NAME, context=\"./\")\n",
"\n",
"# Create the function parsing this notebook's code using 'code_to_function':\n",
"get_model_function = mlrun.code_to_function(\n",
" name=\"get_mobilenetv2\",\n",
+ " project=PROJECT_NAME,\n",
" kind=\"job\",\n",
" image=\"mlrun/ml-models\"\n",
")\n",
@@ -206,15 +212,267 @@
"# Run the function to log the model:\n",
"get_model_run = get_model_function.run(\n",
" handler=\"get_model\",\n",
- " artifact_path=ARTIFACT_PATH,\n",
+ " output_path=ARTIFACT_PATH,\n",
" params={\n",
" \"model_name\": MODEL_NAME\n",
" },\n",
" local=True\n",
")"
],
- "outputs": [],
- "execution_count": null
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "> 2026-02-10 16:14:24,932 [info] Created and saved project: {\"context\":\"./\",\"from_template\":null,\"name\":\"onnx-utils\",\"overwrite\":false,\"save\":true}\n",
+ "> 2026-02-10 16:14:24,933 [info] Project created successfully: {\"project_name\":\"onnx-utils\",\"stored_in_db\":true}\n",
+ "> 2026-02-10 16:14:31,659 [info] Storing function: {\"db\":null,\"name\":\"get-mobilenetv2-get-model\",\"uid\":\"7b9d1b54375b44e191d73685a382c910\"}\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ],
+ "text/html": [
+ "\n",
+ "
We will use the TF.Keras framework, a MobileNetV2 as our model and we will convert it to ONNX using the to_onnx handler.
-
1.2.1. First we will set a temporary artifact path for our model to be saved in and choose the models names:
+
We will use the PyTorch framework, a MobileNetV2 as our model and we will convert it to ONNX using the to_onnx handler.
+
1.2.1. First we will set the artifact path for our model to be saved in and choose the models names:
importos
-os.environ["TF_USE_LEGACY_KERAS"]="true"
-fromtempfileimportTemporaryDirectory
+importtempfile
+# Use a temporary directory for model artifacts (safe cleanup):
+ARTIFACT_PATH=tempfile.mkdtemp()
+os.environ["MLRUN_ARTIFACT_PATH"]=ARTIFACT_PATH
-# Create a temporary directory for the model artifact:
-ARTIFACT_PATH=TemporaryDirectory().name
-os.makedirs(ARTIFACT_PATH)
+# Project name:
+PROJECT_NAME="onnx-utils"# Choose our model's name:MODEL_NAME="mobilenetv2"
@@ -275,7 +276,7 @@
1.2.3. Create the function using MLRun’s code_to_function and run it:
importmlrun
+# Create or get the MLRun project:
+project=mlrun.get_or_create_project(PROJECT_NAME,context="./")# Create the function parsing this notebook's code using 'code_to_function':get_model_function=mlrun.code_to_function(name="get_mobilenetv2",
+ project=PROJECT_NAME,kind="job",image="mlrun/ml-models")
@@ -331,7 +336,7 @@
> to track results use the .show() or .logs() methods or click here to open in UI
> 2026-02-10 16:14:34,427 [info] Run execution finished: {"name":"get-mobilenetv2-get-model","status":"completed"}
+
+
+
1.2.4. Import the onnx_utils MLRun function and run it:
# Import the ONNX function from the marketplace:
-onnx_utils_function=mlrun.import_function("hub://onnx_utils")
+onnx_utils_function=mlrun.import_function("hub://onnx_utils",project=PROJECT_NAME)
+
+# Construct the model path from the run directory structure:
+model_path=os.path.join(ARTIFACT_PATH,"get-mobilenetv2-get-model","0","model")
+modules_map_path=os.path.join(ARTIFACT_PATH,"get-mobilenetv2-get-model","0","mobilenetv2_modules_map.json.json")# Run the function to convert our model to ONNX:to_onnx_run=onnx_utils_function.run(handler="to_onnx",
- artifact_path=ARTIFACT_PATH,
+ output_path=ARTIFACT_PATH,params={"model_name":MODEL_NAME,
- "model_path":get_model_run.outputs[MODEL_NAME],# <- Take the logged model from the previous function.
+ "model_path":model_path,
+ "load_model_kwargs":{
+ "model_name":MODEL_NAME,
+ "model_class":"mobilenet_v2",
+ "modules_map":modules_map_path,
+ },"onnx_model_name":ONNX_MODEL_NAME,
- "optimize_model":False# <- For optimizing it later in the demo, we mark the flag as False
+ "optimize_model":False,# <- For optimizing it later in the demo, we mark the flag as False
+ "framework_kwargs":{"input_signature":[((32,3,224,224),"float32")]},},local=True)
> to track results use the .show() or .logs() methods or click here to open in UI
> 2026-02-10 16:14:53,862 [info] Run execution finished: {"name":"onnx-utils-to-onnx","status":"completed"}
+
+
+
-
1.2.5. Now, listing the artifact directory we will see both our tf.keras model and the onnx model:
+
1.2.5. Now we verify the ONNX model was created:
importos
-
-print(os.listdir(ARTIFACT_PATH))
+onnx_model_file=os.path.join(ARTIFACT_PATH,"onnx-utils-to-onnx","0","model","onnx_mobilenetv2.onnx")
+assertos.path.isfile(onnx_model_file),f"ONNX model not found at {onnx_model_file}"
+print(f"ONNX model created at: {onnx_model_file}")
+
+
+
+
+
ONNX model created at: /var/folders/rn/q8gs952n26982d36y50w_2rw0000gp/T/tmpvs5qvbxr/onnx-utils-to-onnx/0/model/onnx_mobilenetv2.onnx
@@ -399,12 +842,15 @@
2.2. Demo#2.2.1. We will call now the optimize handler:
-
onnx_utils_function.run(
+
# Construct the ONNX model path from the run directory structure:
+onnx_model_path=os.path.join(ARTIFACT_PATH,"onnx-utils-to-onnx","0","model")
+
+onnx_utils_function.run(handler="optimize",
- artifact_path=ARTIFACT_PATH,
+ output_path=ARTIFACT_PATH,params={
- "model_name":ONNX_MODEL_NAME,
- "model_path":to_onnx_run.output(ONNX_MODEL_NAME),# <- Take the logged model from the previous function.
+ "model_path":onnx_model_path,
+ "handler_init_kwargs":{"model_name":ONNX_MODEL_NAME},"optimized_model_name":OPTIMIZED_ONNX_MODEL_NAME,},local=True
@@ -412,22 +858,243 @@
> to track results use the .show() or .logs() methods or click here to open in UI
> 2026-02-10 16:15:03,414 [info] Run execution finished: {"name":"onnx-utils-optimize","status":"completed"}
+
+
+
<mlrun.model.RunObject at 0x106148190>
+
+
+
+
+
2.2.2. And now our model was optimized. Let us verify:
-
print(os.listdir(ARTIFACT_PATH))
+
optimized_model_file=os.path.join(ARTIFACT_PATH,"onnx-utils-optimize","0","model","optimized_onnx_mobilenetv2.onnx")
+assertos.path.isfile(optimized_model_file),f"Optimized ONNX model not found at {optimized_model_file}"
+print(f"Optimized ONNX model created at: {optimized_model_file}")
+
+
Optimized ONNX model created at: /var/folders/rn/q8gs952n26982d36y50w_2rw0000gp/T/tmpvs5qvbxr/onnx-utils-optimize/0/model/optimized_onnx_mobilenetv2.onnx
+
+
-
Lastly, run this code to clean up the models:
+
+
Lastly, run this code to clean up all generated files and directories:
importshutil
-
-shutil.rmtree(ARTIFACT_PATH)
+# Clean up the temporary artifact directory:
+ifos.path.exists(ARTIFACT_PATH):
+ shutil.rmtree(ARTIFACT_PATH)
-kind: job
metadata:
+ name: onnx-utils
+ tag: ''
categories:
- utilities
- deep-learning
- name: onnx-utils
- tag: ''
-verbose: false
+kind: job
spec:
- build:
- code_origin: ''
- base_image: mlrun/mlrun
- origin_filename: ''
- functionSourceCode: IyBDb3B5cmlnaHQgMjAxOSBJZ3VhemlvCiMKIyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiMgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiMKIyAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiMKIyBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiMgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KIyBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiMgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiMKZnJvbSB0eXBpbmcgaW1wb3J0IEFueSwgQ2FsbGFibGUsIERpY3QsIExpc3QsIFR1cGxlCgppbXBvcnQgbWxydW4KCgpjbGFzcyBfVG9PTk5YQ29udmVyc2lvbnM6CiAgICAiIiIKICAgIEFuIE9OTlggY29udmVyc2lvbiBmdW5jdGlvbnMgbGlicmFyeSBjbGFzcy4KICAgICIiIgoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiB0Zl9rZXJhc190b19vbm54KAogICAgICAgIG1vZGVsX2hhbmRsZXIsCiAgICAgICAgb25ueF9tb2RlbF9uYW1lOiBzdHIgPSBOb25lLAogICAgICAgIG9wdGltaXplX21vZGVsOiBib29sID0gVHJ1ZSwKICAgICAgICBpbnB1dF9zaWduYXR1cmU6IExpc3RbVHVwbGVbVHVwbGVbaW50XSwgc3RyXV0gPSBOb25lLAogICAgKToKICAgICAgICAiIiIKICAgICAgICBDb252ZXJ0IGEgVEYuS2VyYXMgbW9kZWwgdG8gYW4gT05OWCBtb2RlbCBhbmQgbG9nIGl0IGJhY2sgdG8gTUxSdW4gYXMgYSBuZXcgbW9kZWwgb2JqZWN0LgoKICAgICAgICA6cGFyYW0gbW9kZWxfaGFuZGxlcjogICBBbiBpbml0aWFsaXplZCBURktlcmFzTW9kZWxIYW5kbGVyIHdpdGggYSBsb2FkZWQgbW9kZWwgdG8gY29udmVydCB0byBPTk5YLgogICAgICAgIDpwYXJhbSBvbm54X21vZGVsX25hbWU6IFRoZSBuYW1lIHRvIHVzZSB0byBsb2cgdGhlIGNvbnZlcnRlZCBPTk5YIG1vZGVsLiBJZiBub3QgZ2l2ZW4sIHRoZSBnaXZlbiBgbW9kZWxfbmFtZWAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aWxsIGJlIHVzZWQgd2l0aCBhbiBhZGRpdGlvbmFsIHN1ZmZpeCBgX29ubnhgLiBEZWZhdWx0ZWQgdG8gTm9uZS4KICAgICAgICA6cGFyYW0gb3B0aW1pemVfbW9kZWw6ICBXaGV0aGVyIG9yIG5vdCB0byBvcHRpbWl6ZSB0aGUgT05OWCBtb2RlbCB1c2luZyAnb25ueG9wdGltaXplcicgYmVmb3JlIHNhdmluZyB0aGUgbW9kZWwuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVmYXVsdGVkIHRvIFRydWUuCiAgICAgICAgOnBhcmFtIGlucHV0X3NpZ25hdHVyZTogQSBsaXN0IG9mIHRoZSBpbnB1dCBsYXllcnMgc2hhcGUgYW5kIGRhdGEgdHlwZSBwcm9wZXJ0aWVzLiBFeHBlY3RlZCB0byByZWNlaXZlIGEgbGlzdAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoZXJlIGVhY2ggZWxlbWVudCBpcyBhbiBpbnB1dCBsYXllciB0dXBsZS4gQW4gaW5wdXQgbGF5ZXIgdHVwbGUgaXMgYSB0dXBsZSBvZjoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbMF0gPSBMYXllcidzIHNoYXBlLCBhIHR1cGxlIG9mIGludGVnZXJzLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFsxXSA9IExheWVyJ3MgZGF0YSB0eXBlLCBhIG1scnVuLmRhdGFfdHlwZXMuVmFsdWVUeXBlIHN0cmluZy4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJZiBOb25lLCB0aGUgaW5wdXQgc2lnbmF0dXJlIHdpbGwgYmUgdHJpZWQgdG8gYmUgcmVhZCBmcm9tIHRoZSBtb2RlbCBhcnRpZmFjdC4gRGVmYXVsdGVkCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG8gTm9uZS4KICAgICAgICAiIiIKICAgICAgICAjIEltcG9ydCB0aGUgZnJhbWV3b3JrIGFuZCBoYW5kbGVyOgogICAgICAgIGltcG9ydCB0ZW5zb3JmbG93IGFzIHRmCiAgICAgICAgZnJvbSBtbHJ1bi5mcmFtZXdvcmtzLnRmX2tlcmFzIGltcG9ydCBURktlcmFzVXRpbHMKCiAgICAgICAgIyBDaGVjayB0aGUgZ2l2ZW4gJ2lucHV0X3NpZ25hdHVyZScgcGFyYW1ldGVyOgogICAgICAgIGlmIGlucHV0X3NpZ25hdHVyZSBpcyBOb25lOgogICAgICAgICAgICAjIFJlYWQgdGhlIGlucHV0cyBmcm9tIHRoZSBtb2RlbDoKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgbW9kZWxfaGFuZGxlci5yZWFkX2lucHV0c19mcm9tX21vZGVsKCkKICAgICAgICAgICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlcnJvcjoKICAgICAgICAgICAgICAgIHJhaXNlIG1scnVuLmVycm9ycy5NTFJ1blJ1bnRpbWVFcnJvcigKICAgICAgICAgICAgICAgICAgICBmIlBsZWFzZSBwcm92aWRlIHRoZSAnaW5wdXRfc2lnbmF0dXJlJyBwYXJhbWV0ZXIuIFRoZSBmdW5jdGlvbiB0cmllZCByZWFkaW5nIHRoZSBpbnB1dCBsYXllcnMgIgogICAgICAgICAgICAgICAgICAgIGYiaW5mb3JtYXRpb24gYXV0b21hdGljYWxseSBidXQgZmFpbGVkIHdpdGggdGhlIGZvbGxvd2luZyBlcnJvcjoge2Vycm9yfSIKICAgICAgICAgICAgICAgICkKICAgICAgICBlbHNlOgogICAgICAgICAgICAjIFBhcnNlIHRoZSAnaW5wdXRfc2lnbmF0dXJlJyBwYXJhbWV0ZXI6CiAgICAgICAgICAgIGlucHV0X3NpZ25hdHVyZSA9IFsKICAgICAgICAgICAgICAgIHRmLlRlbnNvclNwZWMoCiAgICAgICAgICAgICAgICAgICAgc2hhcGU9c2hhcGUsCiAgICAgICAgICAgICAgICAgICAgZHR5cGU9VEZLZXJhc1V0aWxzLmNvbnZlcnRfdmFsdWVfdHlwZV90b190Zl9kdHlwZSgKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVfdHlwZT12YWx1ZV90eXBlCiAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIGZvciAoc2hhcGUsIHZhbHVlX3R5cGUpIGluIGlucHV0X3NpZ25hdHVyZQogICAgICAgICAgICBdCgogICAgICAgICMgQ29udmVydCB0byBPTk5YOgogICAgICAgIG1vZGVsX2hhbmRsZXIudG9fb25ueCgKICAgICAgICAgICAgbW9kZWxfbmFtZT1vbm54X21vZGVsX25hbWUsCiAgICAgICAgICAgIGlucHV0X3NpZ25hdHVyZT1pbnB1dF9zaWduYXR1cmUsCiAgICAgICAgICAgIG9wdGltaXplPW9wdGltaXplX21vZGVsLAogICAgICAgICkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgcHl0b3JjaF90b19vbm54KAogICAgICAgIG1vZGVsX2hhbmRsZXIsCiAgICAgICAgb25ueF9tb2RlbF9uYW1lOiBzdHIgPSBOb25lLAogICAgICAgIG9wdGltaXplX21vZGVsOiBib29sID0gVHJ1ZSwKICAgICAgICBpbnB1dF9zaWduYXR1cmU6IExpc3RbVHVwbGVbVHVwbGVbaW50LCAuLi5dLCBzdHJdXSA9IE5vbmUsCiAgICAgICAgaW5wdXRfbGF5ZXJzX25hbWVzOiBMaXN0W3N0cl0gPSBOb25lLAogICAgICAgIG91dHB1dF9sYXllcnNfbmFtZXM6IExpc3Rbc3RyXSA9IE5vbmUsCiAgICAgICAgZHluYW1pY19heGVzOiBEaWN0W3N0ciwgRGljdFtpbnQsIHN0cl1dID0gTm9uZSwKICAgICAgICBpc19iYXRjaGVkOiBib29sID0gVHJ1ZSwKICAgICk6CiAgICAgICAgIiIiCiAgICAgICAgQ29udmVydCBhIFB5VG9yY2ggbW9kZWwgdG8gYW4gT05OWCBtb2RlbCBhbmQgbG9nIGl0IGJhY2sgdG8gTUxSdW4gYXMgYSBuZXcgbW9kZWwgb2JqZWN0LgoKICAgICAgICA6cGFyYW0gbW9kZWxfaGFuZGxlcjogICAgICAgQW4gaW5pdGlhbGl6ZWQgUHlUb3JjaE1vZGVsSGFuZGxlciB3aXRoIGEgbG9hZGVkIG1vZGVsIHRvIGNvbnZlcnQgdG8gT05OWC4KICAgICAgICA6cGFyYW0gb25ueF9tb2RlbF9uYW1lOiAgICAgVGhlIG5hbWUgdG8gdXNlIHRvIGxvZyB0aGUgY29udmVydGVkIE9OTlggbW9kZWwuIElmIG5vdCBnaXZlbiwgdGhlIGdpdmVuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBtb2RlbF9uYW1lYCB3aWxsIGJlIHVzZWQgd2l0aCBhbiBhZGRpdGlvbmFsIHN1ZmZpeCBgX29ubnhgLiBEZWZhdWx0ZWQgdG8gTm9uZS4KICAgICAgICA6cGFyYW0gb3B0aW1pemVfbW9kZWw6ICAgICAgV2hldGhlciBvciBub3QgdG8gb3B0aW1pemUgdGhlIE9OTlggbW9kZWwgdXNpbmcgJ29ubnhvcHRpbWl6ZXInIGJlZm9yZSBzYXZpbmcgdGhlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLiBEZWZhdWx0ZWQgdG8gVHJ1ZS4KICAgICAgICA6cGFyYW0gaW5wdXRfc2lnbmF0dXJlOiAgICAgQSBsaXN0IG9mIHRoZSBpbnB1dCBsYXllcnMgc2hhcGUgYW5kIGRhdGEgdHlwZSBwcm9wZXJ0aWVzLiBFeHBlY3RlZCB0byByZWNlaXZlIGEKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdCB3aGVyZSBlYWNoIGVsZW1lbnQgaXMgYW4gaW5wdXQgbGF5ZXIgdHVwbGUuIEFuIGlucHV0IGxheWVyIHR1cGxlIGlzIGEgdHVwbGUgb2Y6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFswXSA9IExheWVyJ3Mgc2hhcGUsIGEgdHVwbGUgb2YgaW50ZWdlcnMuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFsxXSA9IExheWVyJ3MgZGF0YSB0eXBlLCBhIG1scnVuLmRhdGFfdHlwZXMuVmFsdWVUeXBlIHN0cmluZy4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSWYgTm9uZSwgdGhlIGlucHV0IHNpZ25hdHVyZSB3aWxsIGJlIHRyaWVkIHRvIGJlIHJlYWQgZnJvbSB0aGUgbW9kZWwgYXJ0aWZhY3QuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlZmF1bHRlZCB0byBOb25lLgogICAgICAgIDpwYXJhbSBpbnB1dF9sYXllcnNfbmFtZXM6ICBMaXN0IG9mIG5hbWVzIHRvIGFzc2lnbiB0byB0aGUgaW5wdXQgbm9kZXMgb2YgdGhlIGdyYXBoIGluIG9yZGVyLiBBbGwgb2YgdGhlIG90aGVyCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtZXRlcnMgKGlubmVyIGxheWVycykgY2FuIGJlIHNldCBhcyB3ZWxsIGJ5IHBhc3NpbmcgYWRkaXRpb25hbCBuYW1lcyBpbiB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdC4gVGhlIG9yZGVyIGlzIGJ5IHRoZSBvcmRlciBvZiB0aGUgcGFyYW1ldGVycyBpbiB0aGUgbW9kZWwuIElmIE5vbmUsIHRoZSBpbnB1dHMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lsbCBiZSByZWFkIGZyb20gdGhlIGhhbmRsZXIncyBpbnB1dHMuIElmIGl0cyBhbHNvIE5vbmUsIGl0IGlzIGRlZmF1bHRlZCB0bzoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImlucHV0XzAiLCAiaW5wdXRfMSIsIC4uLgogICAgICAgIDpwYXJhbSBvdXRwdXRfbGF5ZXJzX25hbWVzOiBMaXN0IG9mIG5hbWVzIHRvIGFzc2lnbiB0byB0aGUgb3V0cHV0IG5vZGVzIG9mIHRoZSBncmFwaCBpbiBvcmRlci4gSWYgTm9uZSwgdGhlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dHMgd2lsbCBiZSByZWFkIGZyb20gdGhlIGhhbmRsZXIncyBvdXRwdXRzLiBJZiBpdHMgYWxzbyBOb25lLCBpdCBpcyBkZWZhdWx0ZWQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG86ICJvdXRwdXRfMCIgKGZvciBtdWx0aXBsZSBvdXRwdXRzLCB0aGlzIHBhcmFtZXRlciBtdXN0IGJlIHByb3ZpZGVkKS4KICAgICAgICA6cGFyYW0gZHluYW1pY19heGVzOiAgICAgICAgSWYgcGFydCBvZiB0aGUgaW5wdXQgLyBvdXRwdXQgc2hhcGUgaXMgZHluYW1pYywgbGlrZSAoYmF0Y2hfc2l6ZSwgMywgMzIsIDMyKSB5b3UgY2FuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNpZnkgaXQgYnkgZ2l2aW5nIGEgZHluYW1pYyBheGlzIHRvIHRoZSBpbnB1dCAvIG91dHB1dCBsYXllciBieSBpdHMgbmFtZSBhcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb2xsb3dzOiB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaW5wdXQgbGF5ZXIgbmFtZSI6IHswOiAiYmF0Y2hfc2l6ZSJ9LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm91dHB1dCBsYXllciBuYW1lIjogezA6ICJiYXRjaF9zaXplIn0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSWYgcHJvdmlkZWQsIHRoZSAnaXNfYmF0Y2hlZCcgZmxhZyB3aWxsIGJlIGlnbm9yZWQuIERlZmF1bHRlZCB0byBOb25lLgogICAgICAgIDpwYXJhbSBpc19iYXRjaGVkOiAgICAgICAgICBXaGV0aGVyIHRvIGluY2x1ZGUgYSBiYXRjaCBzaXplIGFzIHRoZSBmaXJzdCBheGlzIGluIGV2ZXJ5IGlucHV0IGFuZCBvdXRwdXQgbGF5ZXIuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlZmF1bHRlZCB0byBUcnVlLiBXaWxsIGJlIGlnbm9yZWQgaWYgJ2R5bmFtaWNfYXhlcycgaXMgcHJvdmlkZWQuCiAgICAgICAgIiIiCiAgICAgICAgIyBJbXBvcnQgdGhlIGZyYW1ld29yayBhbmQgaGFuZGxlcjoKICAgICAgICBpbXBvcnQgdG9yY2gKICAgICAgICBmcm9tIG1scnVuLmZyYW1ld29ya3MucHl0b3JjaCBpbXBvcnQgUHlUb3JjaFV0aWxzCgogICAgICAgICMgUGFyc2UgdGhlICdpbnB1dF9zaWduYXR1cmUnIHBhcmFtZXRlcjoKICAgICAgICBpZiBpbnB1dF9zaWduYXR1cmUgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIGlucHV0X3NpZ25hdHVyZSA9IHR1cGxlKAogICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgIHRvcmNoLnplcm9zKAogICAgICAgICAgICAgICAgICAgICAgICBzaXplPXNoYXBlLAogICAgICAgICAgICAgICAgICAgICAgICBkdHlwZT1QeVRvcmNoVXRpbHMuY29udmVydF92YWx1ZV90eXBlX3RvX3RvcmNoX2R0eXBlKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVfdHlwZT12YWx1ZV90eXBlCiAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgIGZvciAoc2hhcGUsIHZhbHVlX3R5cGUpIGluIGlucHV0X3NpZ25hdHVyZQogICAgICAgICAgICAgICAgXQogICAgICAgICAgICApCgogICAgICAgICMgQ29udmVydCB0byBPTk5YOgogICAgICAgIG1vZGVsX2hhbmRsZXIudG9fb25ueCgKICAgICAgICAgICAgbW9kZWxfbmFtZT1vbm54X21vZGVsX25hbWUsCiAgICAgICAgICAgIGlucHV0X3NhbXBsZT1pbnB1dF9zaWduYXR1cmUsCiAgICAgICAgICAgIG9wdGltaXplPW9wdGltaXplX21vZGVsLAogICAgICAgICAgICBpbnB1dF9sYXllcnNfbmFtZXM9aW5wdXRfbGF5ZXJzX25hbWVzLAogICAgICAgICAgICBvdXRwdXRfbGF5ZXJzX25hbWVzPW91dHB1dF9sYXllcnNfbmFtZXMsCiAgICAgICAgICAgIGR5bmFtaWNfYXhlcz1keW5hbWljX2F4ZXMsCiAgICAgICAgICAgIGlzX2JhdGNoZWQ9aXNfYmF0Y2hlZCwKICAgICAgICApCgoKIyBNYXAgZm9yIGdldHRpbmcgdGhlIGNvbnZlcnNpb24gZnVuY3Rpb24gYWNjb3JkaW5nIHRvIHRoZSBwcm92aWRlZCBmcmFtZXdvcms6Cl9DT05WRVJTSU9OX01BUCA9IHsKICAgICJ0ZW5zb3JmbG93LmtlcmFzIjogX1RvT05OWENvbnZlcnNpb25zLnRmX2tlcmFzX3RvX29ubngsCiAgICAidG9yY2giOiBfVG9PTk5YQ29udmVyc2lvbnMucHl0b3JjaF90b19vbm54LAp9ICAjIHR5cGU6IERpY3Rbc3RyLCBDYWxsYWJsZV0KCgpkZWYgdG9fb25ueCgKICAgIGNvbnRleHQ6IG1scnVuLk1MQ2xpZW50Q3R4LAogICAgbW9kZWxfcGF0aDogc3RyLAogICAgbG9hZF9tb2RlbF9rd2FyZ3M6IGRpY3QgPSBOb25lLAogICAgb25ueF9tb2RlbF9uYW1lOiBzdHIgPSBOb25lLAogICAgb3B0aW1pemVfbW9kZWw6IGJvb2wgPSBUcnVlLAogICAgZnJhbWV3b3JrX2t3YXJnczogRGljdFtzdHIsIEFueV0gPSBOb25lLAopOgogICAgIiIiCiAgICBDb252ZXJ0IHRoZSBnaXZlbiBtb2RlbCB0byBhbiBPTk5YIG1vZGVsLgoKICAgIDpwYXJhbSBjb250ZXh0OiAgICAgICAgICAgVGhlIE1MUnVuIGZ1bmN0aW9uIGV4ZWN1dGlvbiBjb250ZXh0CiAgICA6cGFyYW0gbW9kZWxfcGF0aDogICAgICAgIFRoZSBtb2RlbCBwYXRoIHN0b3JlIG9iamVjdC4KICAgIDpwYXJhbSBsb2FkX21vZGVsX2t3YXJnczogS2V5d29yZCBhcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgYEF1dG9NTFJ1bi5sb2FkX21vZGVsYCBtZXRob2QuCiAgICA6cGFyYW0gb25ueF9tb2RlbF9uYW1lOiAgIFRoZSBuYW1lIHRvIHVzZSB0byBsb2cgdGhlIGNvbnZlcnRlZCBPTk5YIG1vZGVsLiBJZiBub3QgZ2l2ZW4sIHRoZSBnaXZlbiBgbW9kZWxfbmFtZWAgd2lsbAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZSB1c2VkIHdpdGggYW4gYWRkaXRpb25hbCBzdWZmaXggYF9vbm54YC4gRGVmYXVsdGVkIHRvIE5vbmUuCiAgICA6cGFyYW0gb3B0aW1pemVfbW9kZWw6ICAgIFdoZXRoZXIgdG8gb3B0aW1pemUgdGhlIE9OTlggbW9kZWwgdXNpbmcgJ29ubnhvcHRpbWl6ZXInIGJlZm9yZSBzYXZpbmcgdGhlIG1vZGVsLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEZWZhdWx0ZWQgdG8gVHJ1ZS4KICAgIDpwYXJhbSBmcmFtZXdvcmtfa3dhcmdzOiAgQWRkaXRpb25hbCBhcmd1bWVudHMgZWFjaCBmcmFtZXdvcmsgbWF5IHJlcXVpcmUgdG8gY29udmVydCB0byBPTk5YLiBUbyBnZXQgdGhlIGRvYyBzdHJpbmcKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2YgdGhlIGRlc2lyZWQgZnJhbWV3b3JrIG9ubnggY29udmVyc2lvbiBmdW5jdGlvbiwgcGFzcyAiaGVscCIuCiAgICAiIiIKICAgIGZyb20gbWxydW4uZnJhbWV3b3Jrcy5hdXRvX21scnVuLmF1dG9fbWxydW4gaW1wb3J0IEF1dG9NTFJ1bgoKICAgICMgR2V0IGEgbW9kZWwgaGFuZGxlciBvZiB0aGUgcmVxdWlyZWQgZnJhbWV3b3JrOgogICAgbG9hZF9tb2RlbF9rd2FyZ3MgPSBsb2FkX21vZGVsX2t3YXJncyBvciB7fQogICAgbW9kZWxfaGFuZGxlciA9IEF1dG9NTFJ1bi5sb2FkX21vZGVsKAogICAgICAgIG1vZGVsX3BhdGg9bW9kZWxfcGF0aCwgY29udGV4dD1jb250ZXh0LCAqKmxvYWRfbW9kZWxfa3dhcmdzCiAgICApCgogICAgIyBHZXQgdGhlIG1vZGVsJ3MgZnJhbWV3b3JrOgogICAgZnJhbWV3b3JrID0gbW9kZWxfaGFuZGxlci5GUkFNRVdPUktfTkFNRQoKICAgICMgVXNlIHRoZSBjb252ZXJzaW9uIG1hcCB0byBnZXQgdGhlIHNwZWNpZmljIGZyYW1ld29yayB0byBvbm54IGNvbnZlcnNpb246CiAgICBpZiBmcmFtZXdvcmsgbm90IGluIF9DT05WRVJTSU9OX01BUDoKICAgICAgICByYWlzZSBtbHJ1bi5lcnJvcnMuTUxSdW5JbnZhbGlkQXJndW1lbnRFcnJvcigKICAgICAgICAgICAgZiJUaGUgZm9sbG93aW5nIGZyYW1ld29yazogJ3tmcmFtZXdvcmt9JywgaGFzIG5vIE9OTlggY29udmVyc2lvbi4iCiAgICAgICAgKQogICAgY29udmVyc2lvbl9mdW5jdGlvbiA9IF9DT05WRVJTSU9OX01BUFtmcmFtZXdvcmtdCgogICAgIyBDaGVjayBpZiBuZWVkZWQgdG8gcHJpbnQgdGhlIGZ1bmN0aW9uJ3MgZG9jIHN0cmluZyAoImhlbHAiIGlzIHBhc3NlZCk6CiAgICBpZiBmcmFtZXdvcmtfa3dhcmdzID09ICJoZWxwIjoKICAgICAgICBwcmludChjb252ZXJzaW9uX2Z1bmN0aW9uLl9fZG9jX18pCiAgICAgICAgcmV0dXJuCgogICAgIyBTZXQgdGhlIGRlZmF1bHQgZW1wdHkgZnJhbWV3b3JrIGt3YXJncyBpZiBuZWVkZWQ6CiAgICBpZiBmcmFtZXdvcmtfa3dhcmdzIGlzIE5vbmU6CiAgICAgICAgZnJhbWV3b3JrX2t3YXJncyA9IHt9CgogICAgIyBSdW4gdGhlIGNvbnZlcnNpb246CiAgICB0cnk6CiAgICAgICAgY29udmVyc2lvbl9mdW5jdGlvbigKICAgICAgICAgICAgbW9kZWxfaGFuZGxlcj1tb2RlbF9oYW5kbGVyLAogICAgICAgICAgICBvbm54X21vZGVsX25hbWU9b25ueF9tb2RlbF9uYW1lLAogICAgICAgICAgICBvcHRpbWl6ZV9tb2RlbD1vcHRpbWl6ZV9tb2RlbCwKICAgICAgICAgICAgKipmcmFtZXdvcmtfa3dhcmdzLAogICAgICAgICkKICAgIGV4Y2VwdCBUeXBlRXJyb3IgYXMgZXhjZXB0aW9uOgogICAgICAgIHJhaXNlIG1scnVuLmVycm9ycy5NTFJ1bkludmFsaWRBcmd1bWVudEVycm9yKAogICAgICAgICAgICBmIkVSUk9SOiBBIFR5cGVFcnJvciBleGNlcHRpb24gd2FzIHJhaXNlZCBkdXJpbmcgdGhlIGNvbnZlcnNpb246XG57ZXhjZXB0aW9ufS4gIgogICAgICAgICAgICBmIlBsZWFzZSByZWFkIHRoZSB7ZnJhbWV3b3JrfSBmcmFtZXdvcmsgY29udmVyc2lvbiBmdW5jdGlvbiBkb2Mgc3RyaW5nIGJ5IHBhc3NpbmcgJ2hlbHAnIGluIHRoZSAiCiAgICAgICAgICAgIGYiJ2ZyYW1ld29ya19rd2FyZ3MnIGRpY3Rpb25hcnkgcGFyYW1ldGVyLiIKICAgICAgICApCgoKZGVmIG9wdGltaXplKAogICAgY29udGV4dDogbWxydW4uTUxDbGllbnRDdHgsCiAgICBtb2RlbF9wYXRoOiBzdHIsCiAgICBoYW5kbGVyX2luaXRfa3dhcmdzOiBkaWN0ID0gTm9uZSwKICAgIG9wdGltaXphdGlvbnM6IExpc3Rbc3RyXSA9IE5vbmUsCiAgICBmaXhlZF9wb2ludDogYm9vbCA9IEZhbHNlLAogICAgb3B0aW1pemVkX21vZGVsX25hbWU6IHN0ciA9IE5vbmUsCik6CiAgICAiIiIKICAgIE9wdGltaXplIHRoZSBnaXZlbiBPTk5YIG1vZGVsLgoKICAgIDpwYXJhbSBjb250ZXh0OiAgICAgICAgICAgICAgVGhlIE1MUnVuIGZ1bmN0aW9uIGV4ZWN1dGlvbiBjb250ZXh0LgogICAgOnBhcmFtIG1vZGVsX3BhdGg6ICAgICAgICAgICBQYXRoIHRvIHRoZSBPTk5YIG1vZGVsIG9iamVjdC4KICAgIDpwYXJhbSBoYW5kbGVyX2luaXRfa3dhcmdzOiAgS2V5d29yZCBhcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgYE9OTlhNb2RlbEhhbmRsZXJgIGluaXQgbWV0aG9kIHByZWxvYWRpbmcuCiAgICA6cGFyYW0gb3B0aW1pemF0aW9uczogICAgICAgIExpc3Qgb2YgcG9zc2libGUgb3B0aW1pemF0aW9ucy4gVG8gc2VlIHdoYXQgb3B0aW1pemF0aW9ucyBhcmUgYXZhaWxhYmxlLCBwYXNzICJoZWxwIi4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSWYgTm9uZSwgYWxsIHRoZSBvcHRpbWl6YXRpb25zIHdpbGwgYmUgdXNlZC4gRGVmYXVsdGVkIHRvIE5vbmUuCiAgICA6cGFyYW0gZml4ZWRfcG9pbnQ6ICAgICAgICAgIE9wdGltaXplIHRoZSB3ZWlnaHRzIHVzaW5nIGZpeGVkIHBvaW50LiBEZWZhdWx0ZWQgdG8gRmFsc2UuCiAgICA6cGFyYW0gb3B0aW1pemVkX21vZGVsX25hbWU6IFRoZSBuYW1lIG9mIHRoZSBvcHRpbWl6ZWQgbW9kZWwuIElmIE5vbmUsIHRoZSBvcmlnaW5hbCBtb2RlbCB3aWxsIGJlIG92ZXJyaWRkZW4uCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlZmF1bHRlZCB0byBOb25lLgogICAgIiIiCiAgICAjIEltcG9ydCB0aGUgbW9kZWwgaGFuZGxlcjoKICAgIGltcG9ydCBvbm54b3B0aW1pemVyCiAgICBmcm9tIG1scnVuLmZyYW1ld29ya3Mub25ueCBpbXBvcnQgT05OWE1vZGVsSGFuZGxlcgoKICAgICMgQ2hlY2sgaWYgbmVlZGVkIHRvIHByaW50IHRoZSBhdmFpbGFibGUgb3B0aW1pemF0aW9ucyAoImhlbHAiIGlzIHBhc3NlZCk6CiAgICBpZiBvcHRpbWl6YXRpb25zID09ICJoZWxwIjoKICAgICAgICBhdmFpbGFibGVfcGFzc2VzID0gIlxuKiAiLmpvaW4ob25ueG9wdGltaXplci5nZXRfYXZhaWxhYmxlX3Bhc3NlcygpKQogICAgICAgIHByaW50KGYiVGhlIGF2YWlsYWJsZSBvcHRpbWl6YXRpb25zIGFyZTpcbioge2F2YWlsYWJsZV9wYXNzZXN9IikKICAgICAgICByZXR1cm4KCiAgICAjIENyZWF0ZSB0aGUgbW9kZWwgaGFuZGxlcjoKICAgIGhhbmRsZXJfaW5pdF9rd2FyZ3MgPSBoYW5kbGVyX2luaXRfa3dhcmdzIG9yIHt9CiAgICBtb2RlbF9oYW5kbGVyID0gT05OWE1vZGVsSGFuZGxlcigKICAgICAgICBtb2RlbF9wYXRoPW1vZGVsX3BhdGgsIGNvbnRleHQ9Y29udGV4dCwgKipoYW5kbGVyX2luaXRfa3dhcmdzCiAgICApCgogICAgIyBMb2FkIHRoZSBPTk5YIG1vZGVsOgogICAgbW9kZWxfaGFuZGxlci5sb2FkKCkKCiAgICAjIE9wdGltaXplIHRoZSBtb2RlbCB1c2luZyB0aGUgZ2l2ZW4gY29uZmlndXJhdGlvbnM6CiAgICBtb2RlbF9oYW5kbGVyLm9wdGltaXplKG9wdGltaXphdGlvbnM9b3B0aW1pemF0aW9ucywgZml4ZWRfcG9pbnQ9Zml4ZWRfcG9pbnQpCgogICAgIyBSZW5hbWUgaWYgbmVlZGVkOgogICAgaWYgb3B0aW1pemVkX21vZGVsX25hbWUgaXMgbm90IE5vbmU6CiAgICAgICAgbW9kZWxfaGFuZGxlci5zZXRfbW9kZWxfbmFtZShtb2RlbF9uYW1lPW9wdGltaXplZF9tb2RlbF9uYW1lKQoKICAgICMgTG9nIHRoZSBvcHRpbWl6ZWQgbW9kZWw6CiAgICBtb2RlbF9oYW5kbGVyLmxvZygpCg==
- requirements:
- - tqdm~=4.67.1
- - tensorflow~=2.19.0
- - tf_keras~=2.19.0
- - torch~=2.6.0
- - torchvision~=0.21.0
- - onnx~=1.17.0
- - onnxruntime~=1.19.2
- - onnxoptimizer~=0.3.13
- - onnxmltools~=1.13.0
- - tf2onnx~=1.16.1
- - plotly~=5.23
- with_mlrun: false
- auto_build: true
- disable_auto_mount: false
- description: ONNX intigration in MLRun, some utils functions for the ONNX framework,
- optimizing and converting models from different framework to ONNX using MLRun.
- image: ''
entry_points:
tf_keras_to_onnx:
- doc: Convert a TF.Keras model to an ONNX model and log it back to MLRun as a
- new model object.
name: tf_keras_to_onnx
parameters:
- name: model_handler
@@ -88,12 +62,12 @@
data type, a mlrun.data_types.ValueType string. If None, the input signature
will be tried to be read from the model artifact. Defaulted to None.'
default: null
+ doc: Convert a TF.Keras model to an ONNX model and log it back to MLRun as a
+ new model object.
+ lineno: 26
has_varargs: false
has_kwargs: false
- lineno: 26
pytorch_to_onnx:
- doc: Convert a PyTorch model to an ONNX model and log it back to MLRun as a
- new model object.
name: pytorch_to_onnx
parameters:
- name: model_handler
@@ -146,11 +120,12 @@
doc: Whether to include a batch size as the first axis in every input and
output layer. Defaulted to True. Will be ignored if 'dynamic_axes' is provided.
default: true
+ doc: Convert a PyTorch model to an ONNX model and log it back to MLRun as a
+ new model object.
+ lineno: 81
has_varargs: false
has_kwargs: false
- lineno: 81
to_onnx:
- doc: Convert the given model to an ONNX model.
name: to_onnx
parameters:
- name: context
@@ -180,11 +155,11 @@
get the doc string of the desired framework onnx conversion function, pass
"help".
default: null
+ doc: Convert the given model to an ONNX model.
+ lineno: 160
has_varargs: false
has_kwargs: false
- lineno: 160
optimize:
- doc: Optimize the given ONNX model.
name: optimize
parameters:
- name: context
@@ -211,12 +186,37 @@
doc: The name of the optimized model. If None, the original model will be
overridden. Defaulted to None.
default: null
+ doc: Optimize the given ONNX model.
+ lineno: 224
has_varargs: false
has_kwargs: false
- lineno: 224
+ image: ''
default_handler: to_onnx
allow_empty_resources: true
command: ''
+ disable_auto_mount: false
+ description: ONNX intigration in MLRun, some utils functions for the ONNX framework,
+ optimizing and converting models from different framework to ONNX using MLRun.
+ build:
+ functionSourceCode: IyBDb3B5cmlnaHQgMjAxOSBJZ3VhemlvCiMKIyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiMgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiMKIyAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiMKIyBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiMgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KIyBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiMgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiMKZnJvbSB0eXBpbmcgaW1wb3J0IEFueSwgQ2FsbGFibGUsIERpY3QsIExpc3QsIFR1cGxlCgppbXBvcnQgbWxydW4KCgpjbGFzcyBfVG9PTk5YQ29udmVyc2lvbnM6CiAgICAiIiIKICAgIEFuIE9OTlggY29udmVyc2lvbiBmdW5jdGlvbnMgbGlicmFyeSBjbGFzcy4KICAgICIiIgoKICAgIEBzdGF0aWNtZXRob2QKICAgIGRlZiB0Zl9rZXJhc190b19vbm54KAogICAgICAgIG1vZGVsX2hhbmRsZXIsCiAgICAgICAgb25ueF9tb2RlbF9uYW1lOiBzdHIgPSBOb25lLAogICAgICAgIG9wdGltaXplX21vZGVsOiBib29sID0gVHJ1ZSwKICAgICAgICBpbnB1dF9zaWduYXR1cmU6IExpc3RbVHVwbGVbVHVwbGVbaW50XSwgc3RyXV0gPSBOb25lLAogICAgKToKICAgICAgICAiIiIKICAgICAgICBDb252ZXJ0IGEgVEYuS2VyYXMgbW9kZWwgdG8gYW4gT05OWCBtb2RlbCBhbmQgbG9nIGl0IGJhY2sgdG8gTUxSdW4gYXMgYSBuZXcgbW9kZWwgb2JqZWN0LgoKICAgICAgICA6cGFyYW0gbW9kZWxfaGFuZGxlcjogICBBbiBpbml0aWFsaXplZCBURktlcmFzTW9kZWxIYW5kbGVyIHdpdGggYSBsb2FkZWQgbW9kZWwgdG8gY29udmVydCB0byBPTk5YLgogICAgICAgIDpwYXJhbSBvbm54X21vZGVsX25hbWU6IFRoZSBuYW1lIHRvIHVzZSB0byBsb2cgdGhlIGNvbnZlcnRlZCBPTk5YIG1vZGVsLiBJZiBub3QgZ2l2ZW4sIHRoZSBnaXZlbiBgbW9kZWxfbmFtZWAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aWxsIGJlIHVzZWQgd2l0aCBhbiBhZGRpdGlvbmFsIHN1ZmZpeCBgX29ubnhgLiBEZWZhdWx0ZWQgdG8gTm9uZS4KICAgICAgICA6cGFyYW0gb3B0aW1pemVfbW9kZWw6ICBXaGV0aGVyIG9yIG5vdCB0byBvcHRpbWl6ZSB0aGUgT05OWCBtb2RlbCB1c2luZyAnb25ueG9wdGltaXplcicgYmVmb3JlIHNhdmluZyB0aGUgbW9kZWwuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVmYXVsdGVkIHRvIFRydWUuCiAgICAgICAgOnBhcmFtIGlucHV0X3NpZ25hdHVyZTogQSBsaXN0IG9mIHRoZSBpbnB1dCBsYXllcnMgc2hhcGUgYW5kIGRhdGEgdHlwZSBwcm9wZXJ0aWVzLiBFeHBlY3RlZCB0byByZWNlaXZlIGEgbGlzdAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoZXJlIGVhY2ggZWxlbWVudCBpcyBhbiBpbnB1dCBsYXllciB0dXBsZS4gQW4gaW5wdXQgbGF5ZXIgdHVwbGUgaXMgYSB0dXBsZSBvZjoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbMF0gPSBMYXllcidzIHNoYXBlLCBhIHR1cGxlIG9mIGludGVnZXJzLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFsxXSA9IExheWVyJ3MgZGF0YSB0eXBlLCBhIG1scnVuLmRhdGFfdHlwZXMuVmFsdWVUeXBlIHN0cmluZy4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJZiBOb25lLCB0aGUgaW5wdXQgc2lnbmF0dXJlIHdpbGwgYmUgdHJpZWQgdG8gYmUgcmVhZCBmcm9tIHRoZSBtb2RlbCBhcnRpZmFjdC4gRGVmYXVsdGVkCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG8gTm9uZS4KICAgICAgICAiIiIKICAgICAgICAjIEltcG9ydCB0aGUgZnJhbWV3b3JrIGFuZCBoYW5kbGVyOgogICAgICAgIGltcG9ydCB0ZW5zb3JmbG93IGFzIHRmCiAgICAgICAgZnJvbSBtbHJ1bi5mcmFtZXdvcmtzLnRmX2tlcmFzIGltcG9ydCBURktlcmFzVXRpbHMKCiAgICAgICAgIyBDaGVjayB0aGUgZ2l2ZW4gJ2lucHV0X3NpZ25hdHVyZScgcGFyYW1ldGVyOgogICAgICAgIGlmIGlucHV0X3NpZ25hdHVyZSBpcyBOb25lOgogICAgICAgICAgICAjIFJlYWQgdGhlIGlucHV0cyBmcm9tIHRoZSBtb2RlbDoKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgbW9kZWxfaGFuZGxlci5yZWFkX2lucHV0c19mcm9tX21vZGVsKCkKICAgICAgICAgICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBlcnJvcjoKICAgICAgICAgICAgICAgIHJhaXNlIG1scnVuLmVycm9ycy5NTFJ1blJ1bnRpbWVFcnJvcigKICAgICAgICAgICAgICAgICAgICBmIlBsZWFzZSBwcm92aWRlIHRoZSAnaW5wdXRfc2lnbmF0dXJlJyBwYXJhbWV0ZXIuIFRoZSBmdW5jdGlvbiB0cmllZCByZWFkaW5nIHRoZSBpbnB1dCBsYXllcnMgIgogICAgICAgICAgICAgICAgICAgIGYiaW5mb3JtYXRpb24gYXV0b21hdGljYWxseSBidXQgZmFpbGVkIHdpdGggdGhlIGZvbGxvd2luZyBlcnJvcjoge2Vycm9yfSIKICAgICAgICAgICAgICAgICkKICAgICAgICBlbHNlOgogICAgICAgICAgICAjIFBhcnNlIHRoZSAnaW5wdXRfc2lnbmF0dXJlJyBwYXJhbWV0ZXI6CiAgICAgICAgICAgIGlucHV0X3NpZ25hdHVyZSA9IFsKICAgICAgICAgICAgICAgIHRmLlRlbnNvclNwZWMoCiAgICAgICAgICAgICAgICAgICAgc2hhcGU9c2hhcGUsCiAgICAgICAgICAgICAgICAgICAgZHR5cGU9VEZLZXJhc1V0aWxzLmNvbnZlcnRfdmFsdWVfdHlwZV90b190Zl9kdHlwZSgKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVfdHlwZT12YWx1ZV90eXBlCiAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIGZvciAoc2hhcGUsIHZhbHVlX3R5cGUpIGluIGlucHV0X3NpZ25hdHVyZQogICAgICAgICAgICBdCgogICAgICAgICMgQ29udmVydCB0byBPTk5YOgogICAgICAgIG1vZGVsX2hhbmRsZXIudG9fb25ueCgKICAgICAgICAgICAgbW9kZWxfbmFtZT1vbm54X21vZGVsX25hbWUsCiAgICAgICAgICAgIGlucHV0X3NpZ25hdHVyZT1pbnB1dF9zaWduYXR1cmUsCiAgICAgICAgICAgIG9wdGltaXplPW9wdGltaXplX21vZGVsLAogICAgICAgICkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgcHl0b3JjaF90b19vbm54KAogICAgICAgIG1vZGVsX2hhbmRsZXIsCiAgICAgICAgb25ueF9tb2RlbF9uYW1lOiBzdHIgPSBOb25lLAogICAgICAgIG9wdGltaXplX21vZGVsOiBib29sID0gVHJ1ZSwKICAgICAgICBpbnB1dF9zaWduYXR1cmU6IExpc3RbVHVwbGVbVHVwbGVbaW50LCAuLi5dLCBzdHJdXSA9IE5vbmUsCiAgICAgICAgaW5wdXRfbGF5ZXJzX25hbWVzOiBMaXN0W3N0cl0gPSBOb25lLAogICAgICAgIG91dHB1dF9sYXllcnNfbmFtZXM6IExpc3Rbc3RyXSA9IE5vbmUsCiAgICAgICAgZHluYW1pY19heGVzOiBEaWN0W3N0ciwgRGljdFtpbnQsIHN0cl1dID0gTm9uZSwKICAgICAgICBpc19iYXRjaGVkOiBib29sID0gVHJ1ZSwKICAgICk6CiAgICAgICAgIiIiCiAgICAgICAgQ29udmVydCBhIFB5VG9yY2ggbW9kZWwgdG8gYW4gT05OWCBtb2RlbCBhbmQgbG9nIGl0IGJhY2sgdG8gTUxSdW4gYXMgYSBuZXcgbW9kZWwgb2JqZWN0LgoKICAgICAgICA6cGFyYW0gbW9kZWxfaGFuZGxlcjogICAgICAgQW4gaW5pdGlhbGl6ZWQgUHlUb3JjaE1vZGVsSGFuZGxlciB3aXRoIGEgbG9hZGVkIG1vZGVsIHRvIGNvbnZlcnQgdG8gT05OWC4KICAgICAgICA6cGFyYW0gb25ueF9tb2RlbF9uYW1lOiAgICAgVGhlIG5hbWUgdG8gdXNlIHRvIGxvZyB0aGUgY29udmVydGVkIE9OTlggbW9kZWwuIElmIG5vdCBnaXZlbiwgdGhlIGdpdmVuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBtb2RlbF9uYW1lYCB3aWxsIGJlIHVzZWQgd2l0aCBhbiBhZGRpdGlvbmFsIHN1ZmZpeCBgX29ubnhgLiBEZWZhdWx0ZWQgdG8gTm9uZS4KICAgICAgICA6cGFyYW0gb3B0aW1pemVfbW9kZWw6ICAgICAgV2hldGhlciBvciBub3QgdG8gb3B0aW1pemUgdGhlIE9OTlggbW9kZWwgdXNpbmcgJ29ubnhvcHRpbWl6ZXInIGJlZm9yZSBzYXZpbmcgdGhlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLiBEZWZhdWx0ZWQgdG8gVHJ1ZS4KICAgICAgICA6cGFyYW0gaW5wdXRfc2lnbmF0dXJlOiAgICAgQSBsaXN0IG9mIHRoZSBpbnB1dCBsYXllcnMgc2hhcGUgYW5kIGRhdGEgdHlwZSBwcm9wZXJ0aWVzLiBFeHBlY3RlZCB0byByZWNlaXZlIGEKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdCB3aGVyZSBlYWNoIGVsZW1lbnQgaXMgYW4gaW5wdXQgbGF5ZXIgdHVwbGUuIEFuIGlucHV0IGxheWVyIHR1cGxlIGlzIGEgdHVwbGUgb2Y6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFswXSA9IExheWVyJ3Mgc2hhcGUsIGEgdHVwbGUgb2YgaW50ZWdlcnMuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFsxXSA9IExheWVyJ3MgZGF0YSB0eXBlLCBhIG1scnVuLmRhdGFfdHlwZXMuVmFsdWVUeXBlIHN0cmluZy4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSWYgTm9uZSwgdGhlIGlucHV0IHNpZ25hdHVyZSB3aWxsIGJlIHRyaWVkIHRvIGJlIHJlYWQgZnJvbSB0aGUgbW9kZWwgYXJ0aWZhY3QuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlZmF1bHRlZCB0byBOb25lLgogICAgICAgIDpwYXJhbSBpbnB1dF9sYXllcnNfbmFtZXM6ICBMaXN0IG9mIG5hbWVzIHRvIGFzc2lnbiB0byB0aGUgaW5wdXQgbm9kZXMgb2YgdGhlIGdyYXBoIGluIG9yZGVyLiBBbGwgb2YgdGhlIG90aGVyCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtZXRlcnMgKGlubmVyIGxheWVycykgY2FuIGJlIHNldCBhcyB3ZWxsIGJ5IHBhc3NpbmcgYWRkaXRpb25hbCBuYW1lcyBpbiB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdC4gVGhlIG9yZGVyIGlzIGJ5IHRoZSBvcmRlciBvZiB0aGUgcGFyYW1ldGVycyBpbiB0aGUgbW9kZWwuIElmIE5vbmUsIHRoZSBpbnB1dHMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lsbCBiZSByZWFkIGZyb20gdGhlIGhhbmRsZXIncyBpbnB1dHMuIElmIGl0cyBhbHNvIE5vbmUsIGl0IGlzIGRlZmF1bHRlZCB0bzoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImlucHV0XzAiLCAiaW5wdXRfMSIsIC4uLgogICAgICAgIDpwYXJhbSBvdXRwdXRfbGF5ZXJzX25hbWVzOiBMaXN0IG9mIG5hbWVzIHRvIGFzc2lnbiB0byB0aGUgb3V0cHV0IG5vZGVzIG9mIHRoZSBncmFwaCBpbiBvcmRlci4gSWYgTm9uZSwgdGhlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dHMgd2lsbCBiZSByZWFkIGZyb20gdGhlIGhhbmRsZXIncyBvdXRwdXRzLiBJZiBpdHMgYWxzbyBOb25lLCBpdCBpcyBkZWZhdWx0ZWQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG86ICJvdXRwdXRfMCIgKGZvciBtdWx0aXBsZSBvdXRwdXRzLCB0aGlzIHBhcmFtZXRlciBtdXN0IGJlIHByb3ZpZGVkKS4KICAgICAgICA6cGFyYW0gZHluYW1pY19heGVzOiAgICAgICAgSWYgcGFydCBvZiB0aGUgaW5wdXQgLyBvdXRwdXQgc2hhcGUgaXMgZHluYW1pYywgbGlrZSAoYmF0Y2hfc2l6ZSwgMywgMzIsIDMyKSB5b3UgY2FuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNpZnkgaXQgYnkgZ2l2aW5nIGEgZHluYW1pYyBheGlzIHRvIHRoZSBpbnB1dCAvIG91dHB1dCBsYXllciBieSBpdHMgbmFtZSBhcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb2xsb3dzOiB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaW5wdXQgbGF5ZXIgbmFtZSI6IHswOiAiYmF0Y2hfc2l6ZSJ9LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm91dHB1dCBsYXllciBuYW1lIjogezA6ICJiYXRjaF9zaXplIn0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSWYgcHJvdmlkZWQsIHRoZSAnaXNfYmF0Y2hlZCcgZmxhZyB3aWxsIGJlIGlnbm9yZWQuIERlZmF1bHRlZCB0byBOb25lLgogICAgICAgIDpwYXJhbSBpc19iYXRjaGVkOiAgICAgICAgICBXaGV0aGVyIHRvIGluY2x1ZGUgYSBiYXRjaCBzaXplIGFzIHRoZSBmaXJzdCBheGlzIGluIGV2ZXJ5IGlucHV0IGFuZCBvdXRwdXQgbGF5ZXIuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlZmF1bHRlZCB0byBUcnVlLiBXaWxsIGJlIGlnbm9yZWQgaWYgJ2R5bmFtaWNfYXhlcycgaXMgcHJvdmlkZWQuCiAgICAgICAgIiIiCiAgICAgICAgIyBJbXBvcnQgdGhlIGZyYW1ld29yayBhbmQgaGFuZGxlcjoKICAgICAgICBpbXBvcnQgdG9yY2gKICAgICAgICBmcm9tIG1scnVuLmZyYW1ld29ya3MucHl0b3JjaCBpbXBvcnQgUHlUb3JjaFV0aWxzCgogICAgICAgICMgUGFyc2UgdGhlICdpbnB1dF9zaWduYXR1cmUnIHBhcmFtZXRlcjoKICAgICAgICBpZiBpbnB1dF9zaWduYXR1cmUgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIGlucHV0X3NpZ25hdHVyZSA9IHR1cGxlKAogICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgIHRvcmNoLnplcm9zKAogICAgICAgICAgICAgICAgICAgICAgICBzaXplPXNoYXBlLAogICAgICAgICAgICAgICAgICAgICAgICBkdHlwZT1QeVRvcmNoVXRpbHMuY29udmVydF92YWx1ZV90eXBlX3RvX3RvcmNoX2R0eXBlKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVfdHlwZT12YWx1ZV90eXBlCiAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgIGZvciAoc2hhcGUsIHZhbHVlX3R5cGUpIGluIGlucHV0X3NpZ25hdHVyZQogICAgICAgICAgICAgICAgXQogICAgICAgICAgICApCgogICAgICAgICMgQ29udmVydCB0byBPTk5YOgogICAgICAgIG1vZGVsX2hhbmRsZXIudG9fb25ueCgKICAgICAgICAgICAgbW9kZWxfbmFtZT1vbm54X21vZGVsX25hbWUsCiAgICAgICAgICAgIGlucHV0X3NhbXBsZT1pbnB1dF9zaWduYXR1cmUsCiAgICAgICAgICAgIG9wdGltaXplPW9wdGltaXplX21vZGVsLAogICAgICAgICAgICBpbnB1dF9sYXllcnNfbmFtZXM9aW5wdXRfbGF5ZXJzX25hbWVzLAogICAgICAgICAgICBvdXRwdXRfbGF5ZXJzX25hbWVzPW91dHB1dF9sYXllcnNfbmFtZXMsCiAgICAgICAgICAgIGR5bmFtaWNfYXhlcz1keW5hbWljX2F4ZXMsCiAgICAgICAgICAgIGlzX2JhdGNoZWQ9aXNfYmF0Y2hlZCwKICAgICAgICApCgoKIyBNYXAgZm9yIGdldHRpbmcgdGhlIGNvbnZlcnNpb24gZnVuY3Rpb24gYWNjb3JkaW5nIHRvIHRoZSBwcm92aWRlZCBmcmFtZXdvcms6Cl9DT05WRVJTSU9OX01BUCA9IHsKICAgICJ0ZW5zb3JmbG93LmtlcmFzIjogX1RvT05OWENvbnZlcnNpb25zLnRmX2tlcmFzX3RvX29ubngsCiAgICAidG9yY2giOiBfVG9PTk5YQ29udmVyc2lvbnMucHl0b3JjaF90b19vbm54LAp9ICAjIHR5cGU6IERpY3Rbc3RyLCBDYWxsYWJsZV0KCgpkZWYgdG9fb25ueCgKICAgIGNvbnRleHQ6IG1scnVuLk1MQ2xpZW50Q3R4LAogICAgbW9kZWxfcGF0aDogc3RyLAogICAgbG9hZF9tb2RlbF9rd2FyZ3M6IGRpY3QgPSBOb25lLAogICAgb25ueF9tb2RlbF9uYW1lOiBzdHIgPSBOb25lLAogICAgb3B0aW1pemVfbW9kZWw6IGJvb2wgPSBUcnVlLAogICAgZnJhbWV3b3JrX2t3YXJnczogRGljdFtzdHIsIEFueV0gPSBOb25lLAopOgogICAgIiIiCiAgICBDb252ZXJ0IHRoZSBnaXZlbiBtb2RlbCB0byBhbiBPTk5YIG1vZGVsLgoKICAgIDpwYXJhbSBjb250ZXh0OiAgICAgICAgICAgVGhlIE1MUnVuIGZ1bmN0aW9uIGV4ZWN1dGlvbiBjb250ZXh0CiAgICA6cGFyYW0gbW9kZWxfcGF0aDogICAgICAgIFRoZSBtb2RlbCBwYXRoIHN0b3JlIG9iamVjdC4KICAgIDpwYXJhbSBsb2FkX21vZGVsX2t3YXJnczogS2V5d29yZCBhcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgYEF1dG9NTFJ1bi5sb2FkX21vZGVsYCBtZXRob2QuCiAgICA6cGFyYW0gb25ueF9tb2RlbF9uYW1lOiAgIFRoZSBuYW1lIHRvIHVzZSB0byBsb2cgdGhlIGNvbnZlcnRlZCBPTk5YIG1vZGVsLiBJZiBub3QgZ2l2ZW4sIHRoZSBnaXZlbiBgbW9kZWxfbmFtZWAgd2lsbAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZSB1c2VkIHdpdGggYW4gYWRkaXRpb25hbCBzdWZmaXggYF9vbm54YC4gRGVmYXVsdGVkIHRvIE5vbmUuCiAgICA6cGFyYW0gb3B0aW1pemVfbW9kZWw6ICAgIFdoZXRoZXIgdG8gb3B0aW1pemUgdGhlIE9OTlggbW9kZWwgdXNpbmcgJ29ubnhvcHRpbWl6ZXInIGJlZm9yZSBzYXZpbmcgdGhlIG1vZGVsLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEZWZhdWx0ZWQgdG8gVHJ1ZS4KICAgIDpwYXJhbSBmcmFtZXdvcmtfa3dhcmdzOiAgQWRkaXRpb25hbCBhcmd1bWVudHMgZWFjaCBmcmFtZXdvcmsgbWF5IHJlcXVpcmUgdG8gY29udmVydCB0byBPTk5YLiBUbyBnZXQgdGhlIGRvYyBzdHJpbmcKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2YgdGhlIGRlc2lyZWQgZnJhbWV3b3JrIG9ubnggY29udmVyc2lvbiBmdW5jdGlvbiwgcGFzcyAiaGVscCIuCiAgICAiIiIKICAgIGZyb20gbWxydW4uZnJhbWV3b3Jrcy5hdXRvX21scnVuLmF1dG9fbWxydW4gaW1wb3J0IEF1dG9NTFJ1bgoKICAgICMgR2V0IGEgbW9kZWwgaGFuZGxlciBvZiB0aGUgcmVxdWlyZWQgZnJhbWV3b3JrOgogICAgbG9hZF9tb2RlbF9rd2FyZ3MgPSBsb2FkX21vZGVsX2t3YXJncyBvciB7fQogICAgbW9kZWxfaGFuZGxlciA9IEF1dG9NTFJ1bi5sb2FkX21vZGVsKAogICAgICAgIG1vZGVsX3BhdGg9bW9kZWxfcGF0aCwgY29udGV4dD1jb250ZXh0LCAqKmxvYWRfbW9kZWxfa3dhcmdzCiAgICApCgogICAgIyBHZXQgdGhlIG1vZGVsJ3MgZnJhbWV3b3JrOgogICAgZnJhbWV3b3JrID0gbW9kZWxfaGFuZGxlci5GUkFNRVdPUktfTkFNRQoKICAgICMgVXNlIHRoZSBjb252ZXJzaW9uIG1hcCB0byBnZXQgdGhlIHNwZWNpZmljIGZyYW1ld29yayB0byBvbm54IGNvbnZlcnNpb246CiAgICBpZiBmcmFtZXdvcmsgbm90IGluIF9DT05WRVJTSU9OX01BUDoKICAgICAgICByYWlzZSBtbHJ1bi5lcnJvcnMuTUxSdW5JbnZhbGlkQXJndW1lbnRFcnJvcigKICAgICAgICAgICAgZiJUaGUgZm9sbG93aW5nIGZyYW1ld29yazogJ3tmcmFtZXdvcmt9JywgaGFzIG5vIE9OTlggY29udmVyc2lvbi4iCiAgICAgICAgKQogICAgY29udmVyc2lvbl9mdW5jdGlvbiA9IF9DT05WRVJTSU9OX01BUFtmcmFtZXdvcmtdCgogICAgIyBDaGVjayBpZiBuZWVkZWQgdG8gcHJpbnQgdGhlIGZ1bmN0aW9uJ3MgZG9jIHN0cmluZyAoImhlbHAiIGlzIHBhc3NlZCk6CiAgICBpZiBmcmFtZXdvcmtfa3dhcmdzID09ICJoZWxwIjoKICAgICAgICBwcmludChjb252ZXJzaW9uX2Z1bmN0aW9uLl9fZG9jX18pCiAgICAgICAgcmV0dXJuCgogICAgIyBTZXQgdGhlIGRlZmF1bHQgZW1wdHkgZnJhbWV3b3JrIGt3YXJncyBpZiBuZWVkZWQ6CiAgICBpZiBmcmFtZXdvcmtfa3dhcmdzIGlzIE5vbmU6CiAgICAgICAgZnJhbWV3b3JrX2t3YXJncyA9IHt9CgogICAgIyBSdW4gdGhlIGNvbnZlcnNpb246CiAgICB0cnk6CiAgICAgICAgY29udmVyc2lvbl9mdW5jdGlvbigKICAgICAgICAgICAgbW9kZWxfaGFuZGxlcj1tb2RlbF9oYW5kbGVyLAogICAgICAgICAgICBvbm54X21vZGVsX25hbWU9b25ueF9tb2RlbF9uYW1lLAogICAgICAgICAgICBvcHRpbWl6ZV9tb2RlbD1vcHRpbWl6ZV9tb2RlbCwKICAgICAgICAgICAgKipmcmFtZXdvcmtfa3dhcmdzLAogICAgICAgICkKICAgIGV4Y2VwdCBUeXBlRXJyb3IgYXMgZXhjZXB0aW9uOgogICAgICAgIHJhaXNlIG1scnVuLmVycm9ycy5NTFJ1bkludmFsaWRBcmd1bWVudEVycm9yKAogICAgICAgICAgICBmIkVSUk9SOiBBIFR5cGVFcnJvciBleGNlcHRpb24gd2FzIHJhaXNlZCBkdXJpbmcgdGhlIGNvbnZlcnNpb246XG57ZXhjZXB0aW9ufS4gIgogICAgICAgICAgICBmIlBsZWFzZSByZWFkIHRoZSB7ZnJhbWV3b3JrfSBmcmFtZXdvcmsgY29udmVyc2lvbiBmdW5jdGlvbiBkb2Mgc3RyaW5nIGJ5IHBhc3NpbmcgJ2hlbHAnIGluIHRoZSAiCiAgICAgICAgICAgIGYiJ2ZyYW1ld29ya19rd2FyZ3MnIGRpY3Rpb25hcnkgcGFyYW1ldGVyLiIKICAgICAgICApCgoKZGVmIG9wdGltaXplKAogICAgY29udGV4dDogbWxydW4uTUxDbGllbnRDdHgsCiAgICBtb2RlbF9wYXRoOiBzdHIsCiAgICBoYW5kbGVyX2luaXRfa3dhcmdzOiBkaWN0ID0gTm9uZSwKICAgIG9wdGltaXphdGlvbnM6IExpc3Rbc3RyXSA9IE5vbmUsCiAgICBmaXhlZF9wb2ludDogYm9vbCA9IEZhbHNlLAogICAgb3B0aW1pemVkX21vZGVsX25hbWU6IHN0ciA9IE5vbmUsCik6CiAgICAiIiIKICAgIE9wdGltaXplIHRoZSBnaXZlbiBPTk5YIG1vZGVsLgoKICAgIDpwYXJhbSBjb250ZXh0OiAgICAgICAgICAgICAgVGhlIE1MUnVuIGZ1bmN0aW9uIGV4ZWN1dGlvbiBjb250ZXh0LgogICAgOnBhcmFtIG1vZGVsX3BhdGg6ICAgICAgICAgICBQYXRoIHRvIHRoZSBPTk5YIG1vZGVsIG9iamVjdC4KICAgIDpwYXJhbSBoYW5kbGVyX2luaXRfa3dhcmdzOiAgS2V5d29yZCBhcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgYE9OTlhNb2RlbEhhbmRsZXJgIGluaXQgbWV0aG9kIHByZWxvYWRpbmcuCiAgICA6cGFyYW0gb3B0aW1pemF0aW9uczogICAgICAgIExpc3Qgb2YgcG9zc2libGUgb3B0aW1pemF0aW9ucy4gVG8gc2VlIHdoYXQgb3B0aW1pemF0aW9ucyBhcmUgYXZhaWxhYmxlLCBwYXNzICJoZWxwIi4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSWYgTm9uZSwgYWxsIHRoZSBvcHRpbWl6YXRpb25zIHdpbGwgYmUgdXNlZC4gRGVmYXVsdGVkIHRvIE5vbmUuCiAgICA6cGFyYW0gZml4ZWRfcG9pbnQ6ICAgICAgICAgIE9wdGltaXplIHRoZSB3ZWlnaHRzIHVzaW5nIGZpeGVkIHBvaW50LiBEZWZhdWx0ZWQgdG8gRmFsc2UuCiAgICA6cGFyYW0gb3B0aW1pemVkX21vZGVsX25hbWU6IFRoZSBuYW1lIG9mIHRoZSBvcHRpbWl6ZWQgbW9kZWwuIElmIE5vbmUsIHRoZSBvcmlnaW5hbCBtb2RlbCB3aWxsIGJlIG92ZXJyaWRkZW4uCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlZmF1bHRlZCB0byBOb25lLgogICAgIiIiCiAgICAjIEltcG9ydCB0aGUgbW9kZWwgaGFuZGxlcjoKICAgIGltcG9ydCBvbm54b3B0aW1pemVyCiAgICBmcm9tIG1scnVuLmZyYW1ld29ya3Mub25ueCBpbXBvcnQgT05OWE1vZGVsSGFuZGxlcgoKICAgICMgQ2hlY2sgaWYgbmVlZGVkIHRvIHByaW50IHRoZSBhdmFpbGFibGUgb3B0aW1pemF0aW9ucyAoImhlbHAiIGlzIHBhc3NlZCk6CiAgICBpZiBvcHRpbWl6YXRpb25zID09ICJoZWxwIjoKICAgICAgICBhdmFpbGFibGVfcGFzc2VzID0gIlxuKiAiLmpvaW4ob25ueG9wdGltaXplci5nZXRfYXZhaWxhYmxlX3Bhc3NlcygpKQogICAgICAgIHByaW50KGYiVGhlIGF2YWlsYWJsZSBvcHRpbWl6YXRpb25zIGFyZTpcbioge2F2YWlsYWJsZV9wYXNzZXN9IikKICAgICAgICByZXR1cm4KCiAgICAjIENyZWF0ZSB0aGUgbW9kZWwgaGFuZGxlcjoKICAgIGhhbmRsZXJfaW5pdF9rd2FyZ3MgPSBoYW5kbGVyX2luaXRfa3dhcmdzIG9yIHt9CiAgICBtb2RlbF9oYW5kbGVyID0gT05OWE1vZGVsSGFuZGxlcigKICAgICAgICBtb2RlbF9wYXRoPW1vZGVsX3BhdGgsIGNvbnRleHQ9Y29udGV4dCwgKipoYW5kbGVyX2luaXRfa3dhcmdzCiAgICApCgogICAgIyBMb2FkIHRoZSBPTk5YIG1vZGVsOgogICAgbW9kZWxfaGFuZGxlci5sb2FkKCkKCiAgICAjIE9wdGltaXplIHRoZSBtb2RlbCB1c2luZyB0aGUgZ2l2ZW4gY29uZmlndXJhdGlvbnM6CiAgICBtb2RlbF9oYW5kbGVyLm9wdGltaXplKG9wdGltaXphdGlvbnM9b3B0aW1pemF0aW9ucywgZml4ZWRfcG9pbnQ9Zml4ZWRfcG9pbnQpCgogICAgIyBSZW5hbWUgaWYgbmVlZGVkOgogICAgaWYgb3B0aW1pemVkX21vZGVsX25hbWUgaXMgbm90IE5vbmU6CiAgICAgICAgbW9kZWxfaGFuZGxlci5zZXRfbW9kZWxfbmFtZShtb2RlbF9uYW1lPW9wdGltaXplZF9tb2RlbF9uYW1lKQoKICAgICMgTG9nIHRoZSBvcHRpbWl6ZWQgbW9kZWw6CiAgICBtb2RlbF9oYW5kbGVyLmxvZygpCg==
+ base_image: mlrun/mlrun
+ with_mlrun: false
+ auto_build: true
+ requirements:
+ - tqdm~=4.67.1
+ - tensorflow~=2.19.0
+ - tf_keras~=2.19.0
+ - torch~=2.8.0
+ - torchvision~=0.23.0
+ - onnx~=1.17.0
+ - onnxruntime~=1.19.2
+ - onnxoptimizer~=0.3.13
+ - onnxmltools~=1.13.0
+ - tf2onnx~=1.16.1
+ - plotly~=5.23
+ origin_filename: ''
+ code_origin: ''
+verbose: false
diff --git a/functions/development/onnx_utils/latest/static/item.html b/functions/development/onnx_utils/latest/static/item.html
index fdd7dc51..b4662c63 100644
--- a/functions/development/onnx_utils/latest/static/item.html
+++ b/functions/development/onnx_utils/latest/static/item.html
@@ -43,7 +43,7 @@
author: Iguazio
maintainers: []
marketplaceType: ''
-mlrunVersion: 1.7.2
+mlrunVersion: 1.10.0
name: onnx_utils
platformVersion: 3.5.0
spec:
@@ -60,8 +60,8 @@
- tqdm~=4.67.1
- tensorflow~=2.19.0
- tf_keras~=2.19.0
- - torch~=2.6.0
- - torchvision~=0.21.0
+ - torch~=2.8.0
+ - torchvision~=0.23.0
- onnx~=1.17.0
- onnxruntime~=1.19.2
- onnxoptimizer~=0.3.13
@@ -69,7 +69,7 @@
- tf2onnx~=1.16.1
- plotly~=5.23
url: ''
-version: 1.3.0
+version: 1.4.0
diff --git a/functions/development/tags.json b/functions/development/tags.json
index ee43d671..62c21180 100644
--- a/functions/development/tags.json
+++ b/functions/development/tags.json
@@ -1 +1 @@
-{"kind": ["serving", "job", "nuclio:serving"], "categories": ["model-testing", "model-serving", "genai", "monitoring", "data-analysis", "deep-learning", "machine-learning", "utilities", "model-training", "data-preparation", "NLP", "data-generation", "audio"]}
\ No newline at end of file
+{"categories": ["data-generation", "machine-learning", "NLP", "model-testing", "audio", "monitoring", "data-preparation", "model-serving", "utilities", "model-training", "data-analysis", "deep-learning", "genai"], "kind": ["nuclio:serving", "job", "serving"]}
\ No newline at end of file
diff --git a/modules/development/tags.json b/modules/development/tags.json
index 8d771240..d38353be 100644
--- a/modules/development/tags.json
+++ b/modules/development/tags.json
@@ -1 +1 @@
-{"kind": ["generic", "monitoring_application"], "categories": ["model-serving", "genai", "structured-ML"]}
\ No newline at end of file
+{"kind": ["monitoring_application", "generic"], "categories": ["model-serving", "structured-ML", "genai"]}
\ No newline at end of file
diff --git a/steps/development/tags.json b/steps/development/tags.json
index 1ecf4a3b..ec9e8ba7 100644
--- a/steps/development/tags.json
+++ b/steps/development/tags.json
@@ -1 +1 @@
-{"kind": ["generic"], "categories": ["utilities", "model-serving", "data-preparation"]}
\ No newline at end of file
+{"kind": ["generic"], "categories": ["utilities", "data-preparation", "model-serving"]}
\ No newline at end of file