code: def save_model(
      name: Tag | str,
      model: onnx.ModelProto,
      *,
      signatures: dict[str, ModelSignatureDict]
      | dict[str, ModelSignature]
      | None = None,
      labels: dict[str, str] | None = None,
      custom_objects: dict[str, t.Any] | None = None,
      external_modules: t.List[ModuleType] | None = None,
      metadata: dict[str, t.Any] | None = None,
  ) -> bentoml.Model:
      """Save a onnx model instance to the BentoML model store.
  
      Args:
          name (``str``):
              The name to give to the model in the BentoML store. This must be a valid
              :obj:`~bentoml.Tag` name.
          model (:obj:`~onnx.ModelProto`):
              The ONNX model to be saved.
          signatures (``dict[str, ModelSignatureDict]``, optional):
              Signatures of predict methods to be used. If not provided, the signatures default to
              ``{"run": {"batchable": False}}``. See :obj:`~bentoml.types.ModelSignature` for more details.
              ``bentoml.onnx`` internally use ``onnxruntime.InferenceSession`` to run inference.
              When the original model is converted to ONNX format and loaded by
              ``onnxruntime.InferenceSession``, the inference method of the original model is
              converted to the ``run`` method of the ``onnxruntime.InferenceSession``.
              ``signatures`` here refers to the predict method of
              ``onnxruntime.InferenceSession``, hence the only allowed method name in ``signatures``
              is ``run``.
          labels (``dict[str, str]``, optional):
              A default set of management labels to be associated with the model. An example is
              ``{"training-set": "data-1"}``.
          custom_objects (``dict[str, Any]``, optional):
              Custom objects to be saved with the model. An example is
              ``{"my-normalizer": normalizer}``.
  
              Custom objects are currently serialized with cloudpickle, but this implementation is
              subject to change.
          external_modules (:code:`List[ModuleType]`, `optional`, default to :code:`None`):
              user-defined additional python modules to be saved alongside the model or custom objects,
              e.g. a tokenizer module, preprocessor module, model configuration module
          metadata (``dict[str, Any]``, optional):
              Metadata to be associated with the model. An example is ``{"bias": 4}``.
  
              Metadata is intended for display in a model management UI and therefore must be a
              default Python type, such as ``str`` or ``int``.
  
      Returns:
  
          :obj:`~bentoml.Model`: A BentoML model containing the saved
          ONNX model instance.  store.
  
      Example:
  
      .. code-block:: python
  
          import bentoml
  
          import torch
          import torch.nn as nn
  
          class ExtendedModel(nn.Module):
              def __init__(self, D_in, H, D_out):
                  # In the constructor we instantiate two nn.Linear modules and assign them as
                  #  member variables.
                  super(ExtendedModel, self).__init__()
                  self.linear1 = nn.Linear(D_in, H)
                  self.linear2 = nn.Linear(H, D_out)
  
              def forward(self, x, bias):
                  # In the forward function we accept a Tensor of input data and an optional bias
                  h_relu = self.linear1(x).clamp(min=0)
                  y_pred = self.linear2(h_relu)
                  return y_pred + bias
  
  
          N, D_in, H, D_out = 64, 1000, 100, 1
          x = torch.randn(N, D_in)
          model = ExtendedModel(D_in, H, D_out)
  
          input_names = ["x", "bias"]
          output_names = ["output1"]
  
          tmpdir = "/tmp/model"
          model_path = os.path.join(tmpdir, "test_torch.onnx")
          torch.onnx.export(
              model,
              (x, torch.Tensor([1.0])),
              model_path,
              input_names=input_names,
              output_names=output_names,
          )
  
          bento_model = bentoml.onnx.save_model("onnx_model", model_path, signatures={"run": {"batchable": True}})
  
      """
  
      # prefer "onnxruntime-gpu" over "onnxruntime" for framework versioning
      _onnxruntime_version = None
      _onnxruntime_pkg = None
      _PACKAGE = [
          "onnxruntime-gpu",
          "onnxruntime",
          "onnxruntime-silicon",
      ]
      for p in _PACKAGE:
          try:
              _onnxruntime_version = get_pkg_version(p)
              _onnxruntime_pkg = p
              break
          except PackageNotFoundError:
              pass
      assert (
          _onnxruntime_pkg is not None
          and _onnxruntime_version is not None
      ), "Failed to find onnxruntime package version."
  
      assert (
          _onnxruntime_version is not None
      ), "onnxruntime is not installed"
      if not isinstance(model, onnx.ModelProto):
          raise TypeError(
              f"Given model ({model}) is not a onnx.ModelProto."
          )
  
      context = ModelContext(
          framework_name="onnx",
          framework_versions={
              "onnx": get_pkg_version("onnx"),
              _onnxruntime_pkg: _onnxruntime_version,
          },
      )
  
      if signatures is None:
          signatures = {
              "run": {"batchable": False},
          }
          logger.info(
              'Using the default model signature for ONNX (%s) for model "%s".',
              signatures,
              name,
          )
      else:
          provided_methods = list(signatures.keys())
          if provided_methods != ["run"]:
              raise BentoMLException(
                  f"Provided method names {[m for m  in provided_methods if m != 'run']} are invalid. 'bentoml.onnx' will load ONNX model into an 'onnxruntime.InferenceSession' for inference, so the only supported method name is 'run'."
              )
  
      run_input_specs = [
          MessageToDict(inp) for inp in model.graph.input
      ]
      run_output_specs = [
          MessageToDict(out) for out in model.graph.output
      ]
      input_specs = {"run": run_input_specs}
      output_specs = {"run": run_output_specs}
  
      options = ONNXOptions(
          input_specs=input_specs, output_specs=output_specs
      )
  
      with bentoml.models.create(
          name,
          module=MODULE_NAME,
          api_version=API_VERSION,
          signatures=signatures,
          labels=labels,
          options=options,
          custom_objects=custom_objects,
          external_modules=external_modules,
          metadata=metadata,
          context=context,
      ) as bento_model:
          onnx.save(model, bento_model.path_of(MODEL_FILENAME))
  
          return bento_model
  
imports: from __future__ import annotations
  import logging
  import os
  import typing
  from types import ModuleType
  from typing import TYPE_CHECKING
  import attr
  import bentoml
  from bentoml import Tag
  from bentoml.exceptions import BentoMLException
  from bentoml.exceptions import MissingDependencyException
  from bentoml.exceptions import NotFound
  from bentoml.models import ModelContext
  from bentoml.models import ModelOptions
  from ..utils.pkg import PackageNotFoundError
  from ..utils.pkg import get_pkg_version
label_desc: Use image node_id 5 for calling a global function with example usage: save_model(name, model) and returns: bento_model