code: def _quantize(
      model,
      metric,
      dataloader,
      eval_func,
      framework,
      conf=None,
      approach="static",
      tuning_strategy="bayesian",
      accuracy_criterion={"relative": 0.01, "higher_is_better": True},
      timeout=0,
      max_trials=1,
      inputs=[],
      outputs=[],
      **kwargs,
  ):
      from neural_compressor import quantization
  
      if compare_version("neural_compressor", operator.ge, "2.1"):
          from neural_compressor import PostTrainingQuantConfig
      else:
          from neural_compressor.quantization import (
              PostTrainingQuantConfig,
          )
      from neural_compressor.config import (
          AccuracyCriterion,
          TuningCriterion,
      )
      from neural_compressor.conf.pythonic_config import Config
      from neural_compressor.conf.config import QuantConf
      from neural_compressor.data import DataLoader
  
      if approach == "dynamic":
          dataloader = None
      elif "onnx" in framework:
          if hasattr(dataloader, "batch_size"):
              # `dataloader` is pytorch DataLoader
              # we should convert pytorch tensor to numpy ndarray
              import torch
  
              def wrap_collate_fn(func):
                  def new_collate_fn(batch):
                      return [
                          x.detach().numpy()
                          if isinstance(x, torch.Tensor)
                          else x
                          for x in func(batch)
                      ]
  
                  return new_collate_fn
  
              dataloader = DataLoader(
                  framework,
                  dataloader.dataset,
                  collate_fn=wrap_collate_fn(dataloader.collate_fn),
              )
          else:
              # `dataloader` is tensorflow (x,y)
              # we should construct a INC DataLoader from tf.Dataset or numpy ndarray
              import tensorflow as tf
  
              if isinstance(dataloader[0], tf.data.Dataset):
                  dataloader = DataLoader("tensorflow", dataloader[0])
              else:
                  from .onnx.tensorflow.quantization import (
                      KerasNumpyDataset,
                  )
  
                  dataloader = KerasNumpyDataset(
                      dataloader[0], dataloader[1]
                  )
  
      elif not hasattr(dataloader, "batch_size") and not hasattr(
          dataloader, "_batch_size"
      ):
          # INC requires a batched dataloader,
          # A torch.Dataset doesn't have `batch_size` attribute,
          # A tf.Dataset without `_batch_size` attribute is unbatched,
          # So we construct a INC DataLoader from them
          dataloader = DataLoader(framework, dataloader)
  
      if "pytorch" in framework:
          # INC 1.14 and 2.0 doesn't support quantizing pytorch-lightning module for now
          from bigdl.nano.pytorch.lightning import LightningModule
  
          if isinstance(model, LightningModule):
              model = model.model
          if metric is not None:
              from .pytorch.metric import PytorchINCMetric
  
              inc_metric = PytorchINCMetric()
              inc_metric.metric = metric
      elif "onnx" in framework:
          onnx_option = kwargs.pop("onnx_option", None)
          model = model.onnx_model
          if metric is not None:
              if onnx_option == "tensorflow":
                  from .onnx.tensorflow.metric import (
                      KerasONNXRuntimeINCMetic,
                  )
  
                  inc_metric = KerasONNXRuntimeINCMetic()
              else:
                  from .onnx.pytorch.metric import (
                      PytorchONNXRuntimeINCMetic,
                  )
  
                  inc_metric = PytorchONNXRuntimeINCMetic()
              inc_metric.metric = metric
      elif "tensorflow" in framework:
          if metric is not None:
              from .tensorflow.metric import TensorflowINCMetric
  
              inc_metric = TensorflowINCMetric()
              inc_metric.metric = metric
  
      custom_inc_metric = None
      # use metric_id and new custom_inc_metric to solve the same registered metric name
      if metric is not None:
          metric_id = str(inc_metric.get_next_metric_id())
          if "tensorflow" in framework:
              # works for Tensorflow
              custom_inc_metric = type(
                  type(inc_metric).__name__ + metric_id,
                  (object,),
                  {
                      "stack": inc_metric.stack,
                      "to_scalar": inc_metric.to_scalar,
                      "result": inc_metric.result,
                      "update": inc_metric.update,
                      "stack": inc_metric.stack,
                      "reset": inc_metric.reset,
                  },
              )
          else:
              # works for PyTorch
              custom_inc_metric = type(
                  type(inc_metric).__name__ + metric_id,
                  (BaseINCMetric,),
                  {
                      "stack": inc_metric.stack,
                      "to_scalar": inc_metric.to_scalar,
                  },
              )
          custom_inc_metric = custom_inc_metric()
          custom_inc_metric.metric = metric
  
      if "relative" in accuracy_criterion:
          criterion = "relative"
      elif "absolute" in accuracy_criterion:
          criterion = "absolute"
      else:
          criterion = None
  
      if criterion is None:
          accuracy_criterion = AccuracyCriterion(
              higher_is_better=accuracy_criterion.get(
                  "higher_is_better", True
              ),
          )
      else:
          accuracy_criterion = AccuracyCriterion(
              higher_is_better=accuracy_criterion.get(
                  "higher_is_better", True
              ),
              criterion=criterion,
              tolerable_loss=float(accuracy_criterion[criterion]),
          )
  
      tuning_criterion = TuningCriterion(
          strategy=tuning_strategy,
          timeout=timeout,
          max_trials=max_trials,
      )
      # For ipex quantization, we should set backend = "ipex"
      backend = "default" if framework != "pytorch_ipex" else "ipex"
      config = PostTrainingQuantConfig(
          accuracy_criterion=accuracy_criterion,
          tuning_criterion=tuning_criterion,
          approach=approach,
          inputs=inputs,
          outputs=outputs,
          backend=backend,
      )
      if metric is None and eval_func is None:
          config.performance_only = True
  
      if compare_version("neural_compressor", operator.ge, "2.1"):
          q_conf = config
          # TODO: how to pass framework?
      else:
          config = Config(
              quantization=config,
              benchmark=None,
              pruning=None,
              distillation=None,
              nas=None,
          )
  
          q_conf = QuantConf()
          q_conf.map_pyconfig_to_cfg(config)
          q_conf.usr_cfg.model.framework = framework
  
      q_model = quantization.fit(
          model=model,
          conf=q_conf,
          calib_dataloader=dataloader,
          eval_func=eval_func,
          eval_metric=custom_inc_metric,
          # use same dataloader as 1.0 API
          eval_dataloader=dataloader if metric is not None else None,
      )
      return q_model
  
imports: from bigdl.nano.utils.common import invalidInputError
  from .core.base_metric import BaseINCMetric
  from bigdl.nano.utils.common import compare_version
  import operator
label_desc: Use image node_id 2 for calling a global function with example usage: _quantize(model, metric, dataloader, eval_func, framework, conf, approach, tuning_strategy, accuracy_criterion, timeout, max_trials, inputs, outputs) and returns: q_model, new_collate_fn, unknown