docstr: Post-training quantization on a keras model.
  
  :param model: The Keras model to quantize.
  :param x: Input data which is used for training. It could be:
  
            | 1. a Numpy array (or array-like), or a list of arrays (in case the model
            | has multiple inputs).
            |
            | 2. a TensorFlow tensor, or a list of tensors (in case the model has
            | multiple inputs).
            |
            | 3. an unbatched tf.data.Dataset. Should return a tuple of (inputs, targets).
  
            X will be used as calibration dataset for Post-Training Static Quantization (PTQ).
            To avoid data leak during calibration, please use training dataset.
            only valid when precision='int8', otherwise will be ignored.
  :param y: Target data. Like the input data x, it could be either Numpy array(s) or
            TensorFlow tensor(s). Its length should be consistent with x.
            If x is a dataset, y will be ignored (since targets will be obtained from x).
  :param precision:       Global precision of quantized model,
                          supported type: 'int8', 'bf16', 'fp16', defaults to 'int8'.
                          Note that, mixed bf16 precision only works for ``keras.Model`` with
                          explict input and output definition(e.g.,
                          model = keras.Model(inputs=inputs, outputs=outputs)).
  :param accelerator:     Use accelerator 'None', 'onnxruntime', 'openvino', defaults to None.
                          None means staying in tensorflow.
  :param input_spec:      (optional) A (tuple or list of) ``tf.TensorSpec``
                          defining the shape/dtype of the input. This is only required when
                          you have a custom Keras model (no input/output layer is explicitly
                          defined).
  :param eval_func:       A evaluation function which only accepts model as input and return
                          evaluation value. This parameter provides a higher degree of
                          freedom than using eval_loader and metric. Default to None meaning
                          no performance tuning, but it would be better give an evaluation
                          function to get better quantization performance.
  :param metric:          A tensorflow.keras.metrics.Metric object for evaluation.
  :param accuracy_criterion:  Tolerable accuracy drop, defaults to None meaning no
                              accuracy control.
                              accuracy_criterion = {'absolute':0.99, 'higher_is_better':False}
                              means accuracy loss must be smaller than 0.99. For example, if
                              higher_is_better is True, then this requires original metric
                              value subtract current metric value be smaller than 0.99.
                              For inc 1.x, this value must be set to [0, 1), for inc 2.x,
                              there is no limit.
                              accuracy_criterion = {'relative':0.1, 'higher_is_better':True}
                              allows relative accuracy loss: 10%.
  :param approach:        'static' or 'dynamic'.
                          'static': post_training_static_quant,
                          'dynamic': post_training_dynamic_quant.
                          Default: 'static'. Only 'static' approach is supported now.
  :param method:      Method to do quantization. When accelerator=None, supported methods:
          None. When accelerator='onnxruntime', supported methods: 'qlinear', 'integer',
          defaults to 'qlinear'. Suggest 'qlinear' for lower accuracy drop if using
          static quantization.
          More details in https://onnxruntime.ai/docs/performance/quantization.html.
          This argument doesn't take effect for OpenVINO, don't change it for OpenVINO.
  :param conf:        A path to conf yaml file for quantization.
                          Default: None, using default config.
  :param tuning_strategy:    'bayesian', 'basic', 'mse', 'sigopt'. Default: 'bayesian'.
  :param timeout:     Tuning timeout (seconds). Default: None,  which means early stop.
                      Combine with max_trials field to decide when to exit.
  :param max_trials:  Max tune times. Default: None, which means no tuning.
                      Combine with timeout field to decide when to exit.
                      "timeout=0, max_trials=1" means it will try quantization only once and
                      return satisfying best model.
  :param batch:       Batch size of dataloader for calib_dataset. Defaults to None, if the
                      dataset is not a BatchDataset, batchsize equals to 1. Otherwise,
                      batchsize complies with the dataset._batch_size.
  :param thread_num:  (optional) a int represents how many threads(cores) is needed for
                      inference, only valid for accelerator='onnxruntime'
                      or accelerator='openvino'.
  :param device: (optional) A string represents the device of the inference. Default to 'CPU',
                  only valid when accelerator='openvino', otherwise will be ignored.
                  'CPU', 'GPU' and 'VPUX' are supported for now.
  :param custom_objects: Optional dictionary mapping names (strings) to custom classes
                         or functions to be considered during deserialization.
                         Only may be required when quantizing bf16 model and `accelerator`
                         is None.
  :param inputs:      A list of input names.
                      Default: None, automatically get names from graph.
  :param outputs:     A list of output names.
                      Default: None, automatically get names from graph.
  :param sample_size: (optional) a int represents how many samples will be used for
                      Post-training Optimization Tools (POT) from OpenVINO toolkit,
                      only valid for accelerator='openvino'. Default to 100.
                      The larger the value, the more accurate the conversion,
                      the lower the performance degradation, but the longer the time.
  :param onnxruntime_session_options: The session option for onnxruntime, only valid when
                                      accelerator='onnxruntime', otherwise will be ignored.
  :param openvino_config: The config to be inputted in core.compile_model. Only valid when
                          accelerator='openvino', otherwise will be ignored.
  :param logging: whether to log detailed information of model conversion, only valid when
                  accelerator='openvino', otherwise will be ignored. Default: ``True``.
  :param **kwargs: Other extra advanced settings include:
                   1. those be passed to ``torch.onnx.export`` function,
                   only valid when accelerator='onnxruntime'/'openvino',
                   otherwise will be ignored.
                   Possible arguments are: input_names, output_names, opset_version,
                   et al. For more details, please refer
                   https://pytorch.org/docs/stable/onnx.html#torch.onnx.export.
                   2. those be passed to ``model optimizer`` function of openvino,
                   only valid when accelerator='openvino',
                   otherwise will be ignored.
                   Possible arguments are: mean_values, layout, input, output, et al.
                   For more details about model optimizer, you can see mo --help .
                   If you want to quantize with openvino on VPUX device,
                   you must specify  ``mean_value`` for model optimizer function.
                   Here ``mean_value`` represents mean values to be used for the input image
                   per channel. Values to be provided in the (R,G,B) or [R,G,B] format.
                   Can be defined for desired input of the model, for example:
                   "--mean_values data[255,255,255],info[255,255,255]". The exact meaning
                   and order of channels depend on how the original model was trained.
  :return:            A TensorflowBaseModel. If there is no model found, return None.
docstr_tok: ["Post-training","quantization","on","a","keras","model",".",":","param","model",":","The","Keras","model","to","quantize",".",":","param","x",":","Input","data","which","is","used","for","training",".","It","could","be",":","|","1.","a","Numpy","array","(","or","array-like",")",",","or","a","list","of","arrays","(","in","case","the","model","|","has","multiple","inputs",")",".","|","|","2.","a","TensorFlow","tensor",",","or","a","list","of","tensors","(","in","case","the","model","has","|","multiple","inputs",")",".","|","|","3.","an","unbatched","tf.data.Dataset",".","Should","return","a","tuple","of","(","inputs",",","targets",")",".","X","will","be","used","as","calibration","dataset","for","Post-Training","Static","Quantization","(","PTQ",")",".","To","avoid","data","leak","during","calibration",",","please","use","training","dataset",".","only","valid","when","precision='int8","'",",","otherwise","will","be","ignored",".",":","param","y",":","Target","data",".","Like","the","input","data","x",",","it","could","be","either","Numpy","array","(","s",")","or","TensorFlow","tensor","(","s",")",".","Its","length","should","be","consistent","with","x",".","If","x","is","a","dataset",",","y","will","be","ignored","(","since","targets","will","be","obtained","from","x",")",".",":","param","precision",":","Global","precision","of","quantized","model",",","supported","type",":","'int8","'",",","'bf16","'",",","'fp16","'",",","defaults","to","'int8","'",".","Note","that",",","mixed","bf16","precision","only","works","for","``","keras.Model","``","with","explict","input","and","output","definition","(","e.g.",",","model","=","keras.Model","(","inputs=inputs",",","outputs=outputs",")",")",".",":","param","accelerator",":","Use","accelerator","'None","'",",","'onnxruntime","'",",","'openvino","'",",","defaults","to","None",".","None","means","staying","in","tensorflow",".",":","param","input_spec",":","(","optional",")","A","(","tuple","or","list","of",")","``","tf.TensorSpec","``","defining","the","shape\/dtype","of","the","input",".","This","is","only","required","when","you","have","a","custom","Keras","model","(","no","input\/output","layer","is","explicitly","defined",")",".",":","param","eval_func",":","A","evaluation","function","which","only","accepts","model","as","input","and","return","evaluation","value",".","This","parameter","provides","a","higher","degree","of","freedom","than","using","eval_loader","and","metric",".","Default","to","None","meaning","no","performance","tuning",",","but","it","would","be","better","give","an","evaluation","function","to","get","better","quantization","performance",".",":","param","metric",":","A","tensorflow.keras.metrics.Metric","object","for","evaluation",".",":","param","accuracy_criterion",":","Tolerable","accuracy","drop",",","defaults","to","None","meaning","no","accuracy","control",".","accuracy_criterion","=","{","'absolute':0.99",",","'higher_is_better","'",":","False","}","means","accuracy","loss","must","be","smaller","than","0.99",".","For","example",",","if","higher_is_better","is","True",",","then","this","requires","original","metric","value","subtract","current","metric","value","be","smaller","than","0.99",".","For","inc","1.x",",","this","value","must","be","set","to","[","0",",","1",")",",","for","inc","2.x",",","there","is","no","limit",".","accuracy_criterion","=","{","'relative':0.1",",","'higher_is_better","'",":","True","}","allows","relative","accuracy","loss",":","10","%",".",":","param","approach",":","'static","'","or","'dynamic","'",".","'static","'",":","post_training_static_quant",",","'dynamic","'",":","post_training_dynamic_quant",".","Default",":","'static","'",".","Only","'static","'","approach","is","supported","now",".",":","param","method",":","Method","to","do","quantization",".","When","accelerator=None",",","supported","methods",":","None",".","When","accelerator='onnxruntime","'",",","supported","methods",":","'qlinear","'",",","'integer","'",",","defaults","to","'qlinear","'",".","Suggest","'qlinear","'","for","lower","accuracy","drop","if","using","static","quantization",".","More","details","in","https",":","\/\/onnxruntime.ai\/docs\/performance\/quantization.html",".","This","argument","does","n't","take","effect","for","OpenVINO",",","do","n't","change","it","for","OpenVINO",".",":","param","conf",":","A","path","to","conf","yaml","file","for","quantization",".","Default",":","None",",","using","default","config",".",":","param","tuning_strategy",":","'bayesian","'",",","'basic","'",",","'mse","'",",","'sigopt","'",".","Default",":","'bayesian","'",".",":","param","timeout",":","Tuning","timeout","(","seconds",")",".","Default",":","None",",","which","means","early","stop",".","Combine","with","max_trials","field","to","decide","when","to","exit",".",":","param","max_trials",":","Max","tune","times",".","Default",":","None",",","which","means","no","tuning",".","Combine","with","timeout","field","to","decide","when","to","exit",".","``","timeout=0",",","max_trials=1","''","means","it","will","try","quantization","only","once","and","return","satisfying","best","model",".",":","param","batch",":","Batch","size","of","dataloader","for","calib_dataset",".","Defaults","to","None",",","if","the","dataset","is","not","a","BatchDataset",",","batchsize","equals","to","1",".","Otherwise",",","batchsize","complies","with","the","dataset._batch_size",".",":","param","thread_num",":","(","optional",")","a","int","represents","how","many","threads","(","cores",")","is","needed","for","inference",",","only","valid","for","accelerator='onnxruntime'","or","accelerator='openvino","'",".",":","param","device",":","(","optional",")","A","string","represents","the","device","of","the","inference",".","Default","to","'CPU","'",",","only","valid","when","accelerator='openvino","'",",","otherwise","will","be","ignored",".","'CPU","'",",","'GPU","'","and","'VPUX","'","are","supported","for","now",".",":","param","custom_objects",":","Optional","dictionary","mapping","names","(","strings",")","to","custom","classes","or","functions","to","be","considered","during","deserialization",".","Only","may","be","required","when","quantizing","bf16","model","and","`","accelerator","`","is","None",".",":","param","inputs",":","A","list","of","input","names",".","Default",":","None",",","automatically","get","names","from","graph",".",":","param","outputs",":","A","list","of","output","names",".","Default",":","None",",","automatically","get","names","from","graph",".",":","param","sample_size",":","(","optional",")","a","int","represents","how","many","samples","will","be","used","for","Post-training","Optimization","Tools","(","POT",")","from","OpenVINO","toolkit",",","only","valid","for","accelerator='openvino","'",".","Default","to","100",".","The","larger","the","value",",","the","more","accurate","the","conversion",",","the","lower","the","performance","degradation",",","but","the","longer","the","time",".",":","param","onnxruntime_session_options",":","The","session","option","for","onnxruntime",",","only","valid","when","accelerator='onnxruntime","'",",","otherwise","will","be","ignored",".",":","param","openvino_config",":","The","config","to","be","inputted","in","core.compile_model",".","Only","valid","when","accelerator='openvino","'",",","otherwise","will","be","ignored",".",":","param","logging",":","whether","to","log","detailed","information","of","model","conversion",",","only","valid","when","accelerator='openvino","'",",","otherwise","will","be","ignored",".","Default",":","``","True","``",".",":","param","*","*","kwargs",":","Other","extra","advanced","settings","include",":","1.","those","be","passed","to","``","torch.onnx.export","``","function",",","only","valid","when","accelerator='onnxruntime'\/'openvino","'",",","otherwise","will","be","ignored",".","Possible","arguments","are",":","input_names",",","output_names",",","opset_version",",","et","al",".","For","more","details",",","please","refer","https",":","\/\/pytorch.org\/docs\/stable\/onnx.html","#","torch.onnx.export",".","2.","those","be","passed","to","``","model","optimizer","``","function","of","openvino",",","only","valid","when","accelerator='openvino","'",",","otherwise","will","be","ignored",".","Possible","arguments","are",":","mean_values",",","layout",",","input",",","output",",","et","al",".","For","more","details","about","model","optimizer",",","you","can","see","mo","--","help",".","If","you","want","to","quantize","with","openvino","on","VPUX","device",",","you","must","specify","``","mean_value","``","for","model","optimizer","function",".","Here","``","mean_value","``","represents","mean","values","to","be","used","for","the","input","image","per","channel",".","Values","to","be","provided","in","the","(","R",",","G",",","B",")","or","[","R",",","G",",","B","]","format",".","Can","be","defined","for","desired","input","of","the","model",",","for","example",":","``","--","mean_values","data","[","255,255,255","]",",","info","[","255,255,255","]","''",".","The","exact","meaning","and","order","of","channels","depend","on","how","the","original","model","was","trained",".",":","return",":","A","TensorflowBaseModel",".","If","there","is","no","model","found",",","return","None","."]
code: def quantize(
      model: Model,
      x: Union[tf.Tensor, np.ndarray, tf.data.Dataset] = None,
      y: Union[tf.Tensor, np.ndarray] = None,
      precision: str = "int8",
      accelerator: Optional[str] = None,
      input_spec=None,
      eval_func: Optional[Callable] = None,
      metric: Optional[Metric] = None,
      accuracy_criterion: Optional[dict] = None,
      approach: str = "static",
      method: Optional[str] = None,
      conf: Optional[str] = None,
      tuning_strategy: Optional[str] = None,
      timeout: Optional[int] = None,
      max_trials: Optional[int] = None,
      batch: Optional[int] = None,
      thread_num: Optional[int] = None,
      device: Optional[str] = "CPU",
      custom_objects=None,
      inputs: List[str] = None,
      outputs: List[str] = None,
      sample_size: int = 100,
      onnxruntime_session_options=None,
      openvino_config=None,
      logging: bool = True,
      **kwargs,
  ):
      """
      Post-training quantization on a keras model.
  
      :param model: The Keras model to quantize.
      :param x: Input data which is used for training. It could be:
  
                | 1. a Numpy array (or array-like), or a list of arrays (in case the model
                | has multiple inputs).
                |
                | 2. a TensorFlow tensor, or a list of tensors (in case the model has
                | multiple inputs).
                |
                | 3. an unbatched tf.data.Dataset. Should return a tuple of (inputs, targets).
  
                X will be used as calibration dataset for Post-Training Static Quantization (PTQ).
                To avoid data leak during calibration, please use training dataset.
                only valid when precision='int8', otherwise will be ignored.
      :param y: Target data. Like the input data x, it could be either Numpy array(s) or
                TensorFlow tensor(s). Its length should be consistent with x.
                If x is a dataset, y will be ignored (since targets will be obtained from x).
      :param precision:       Global precision of quantized model,
                              supported type: 'int8', 'bf16', 'fp16', defaults to 'int8'.
                              Note that, mixed bf16 precision only works for ``keras.Model`` with
                              explict input and output definition(e.g.,
                              model = keras.Model(inputs=inputs, outputs=outputs)).
      :param accelerator:     Use accelerator 'None', 'onnxruntime', 'openvino', defaults to None.
                              None means staying in tensorflow.
      :param input_spec:      (optional) A (tuple or list of) ``tf.TensorSpec``
                              defining the shape/dtype of the input. This is only required when
                              you have a custom Keras model (no input/output layer is explicitly
                              defined).
      :param eval_func:       A evaluation function which only accepts model as input and return
                              evaluation value. This parameter provides a higher degree of
                              freedom than using eval_loader and metric. Default to None meaning
                              no performance tuning, but it would be better give an evaluation
                              function to get better quantization performance.
      :param metric:          A tensorflow.keras.metrics.Metric object for evaluation.
      :param accuracy_criterion:  Tolerable accuracy drop, defaults to None meaning no
                                  accuracy control.
                                  accuracy_criterion = {'absolute':0.99, 'higher_is_better':False}
                                  means accuracy loss must be smaller than 0.99. For example, if
                                  higher_is_better is True, then this requires original metric
                                  value subtract current metric value be smaller than 0.99.
                                  For inc 1.x, this value must be set to [0, 1), for inc 2.x,
                                  there is no limit.
                                  accuracy_criterion = {'relative':0.1, 'higher_is_better':True}
                                  allows relative accuracy loss: 10%.
      :param approach:        'static' or 'dynamic'.
                              'static': post_training_static_quant,
                              'dynamic': post_training_dynamic_quant.
                              Default: 'static'. Only 'static' approach is supported now.
      :param method:      Method to do quantization. When accelerator=None, supported methods:
              None. When accelerator='onnxruntime', supported methods: 'qlinear', 'integer',
              defaults to 'qlinear'. Suggest 'qlinear' for lower accuracy drop if using
              static quantization.
              More details in https://onnxruntime.ai/docs/performance/quantization.html.
              This argument doesn't take effect for OpenVINO, don't change it for OpenVINO.
      :param conf:        A path to conf yaml file for quantization.
                              Default: None, using default config.
      :param tuning_strategy:    'bayesian', 'basic', 'mse', 'sigopt'. Default: 'bayesian'.
      :param timeout:     Tuning timeout (seconds). Default: None,  which means early stop.
                          Combine with max_trials field to decide when to exit.
      :param max_trials:  Max tune times. Default: None, which means no tuning.
                          Combine with timeout field to decide when to exit.
                          "timeout=0, max_trials=1" means it will try quantization only once and
                          return satisfying best model.
      :param batch:       Batch size of dataloader for calib_dataset. Defaults to None, if the
                          dataset is not a BatchDataset, batchsize equals to 1. Otherwise,
                          batchsize complies with the dataset._batch_size.
      :param thread_num:  (optional) a int represents how many threads(cores) is needed for
                          inference, only valid for accelerator='onnxruntime'
                          or accelerator='openvino'.
      :param device: (optional) A string represents the device of the inference. Default to 'CPU',
                      only valid when accelerator='openvino', otherwise will be ignored.
                      'CPU', 'GPU' and 'VPUX' are supported for now.
      :param custom_objects: Optional dictionary mapping names (strings) to custom classes
                             or functions to be considered during deserialization.
                             Only may be required when quantizing bf16 model and `accelerator`
                             is None.
      :param inputs:      A list of input names.
                          Default: None, automatically get names from graph.
      :param outputs:     A list of output names.
                          Default: None, automatically get names from graph.
      :param sample_size: (optional) a int represents how many samples will be used for
                          Post-training Optimization Tools (POT) from OpenVINO toolkit,
                          only valid for accelerator='openvino'. Default to 100.
                          The larger the value, the more accurate the conversion,
                          the lower the performance degradation, but the longer the time.
      :param onnxruntime_session_options: The session option for onnxruntime, only valid when
                                          accelerator='onnxruntime', otherwise will be ignored.
      :param openvino_config: The config to be inputted in core.compile_model. Only valid when
                              accelerator='openvino', otherwise will be ignored.
      :param logging: whether to log detailed information of model conversion, only valid when
                      accelerator='openvino', otherwise will be ignored. Default: ``True``.
      :param **kwargs: Other extra advanced settings include:
                       1. those be passed to ``torch.onnx.export`` function,
                       only valid when accelerator='onnxruntime'/'openvino',
                       otherwise will be ignored.
                       Possible arguments are: input_names, output_names, opset_version,
                       et al. For more details, please refer
                       https://pytorch.org/docs/stable/onnx.html#torch.onnx.export.
                       2. those be passed to ``model optimizer`` function of openvino,
                       only valid when accelerator='openvino',
                       otherwise will be ignored.
                       Possible arguments are: mean_values, layout, input, output, et al.
                       For more details about model optimizer, you can see mo --help .
                       If you want to quantize with openvino on VPUX device,
                       you must specify  ``mean_value`` for model optimizer function.
                       Here ``mean_value`` represents mean values to be used for the input image
                       per channel. Values to be provided in the (R,G,B) or [R,G,B] format.
                       Can be defined for desired input of the model, for example:
                       "--mean_values data[255,255,255],info[255,255,255]". The exact meaning
                       and order of channels depend on how the original model was trained.
      :return:            A TensorflowBaseModel. If there is no model found, return None.
      """
      invalidInputError(
          precision in ["int8", "fp16", "bf16"],
          "Only support 'int8', 'bf16', 'fp16' now, "
          "no support for {}.".format(precision),
      )
      # device name might be: CPU, GPU, GPU.0, VPUX ...
      invalidInputError(
          device == "CPU" or "GPU" in device or device == "VPUX",
          "Now we only support CPU, GPU and VPUX, not {}".format(
              device
          ),
      )
      if device != "CPU" and accelerator != "openvino":
          invalidInputError(
              False,
              "Now we only support {} device when accelerator "
              "is openvino.".format(device),
          )
  
      if isinstance(model, _ModuleWrapper):
          original_model = model.source_obj
          model = model.target_obj
      else:
          original_model = model
  
      if precision == "fp16":
          invalidInputError(
              accelerator == "openvino",
              "fp16 is not supported on {} accelerator.".format(
                  accelerator
              ),
          )
          if device == "VPUX":
              # for fp16 on VPUX, must specify mean_value.
              invalidInputError(
                  "mean_value" in kwargs,
                  "If you want to quantize with openvino float16 precision on "
                  "VPUX device, you must specify mean_value for model optimizer "
                  "function. For more details about model optimizer, you can "
                  "see mo --help .",
              )
          from bigdl.nano.deps.openvino.tf.model import KerasOpenVINOModel  # type: ignore
  
          result = KerasOpenVINOModel(
              model,
              input_spec=input_spec,
              precision=precision,
              thread_num=thread_num,
              device=device,
              config=openvino_config,
              logging=logging,
              **kwargs,
          )
          return patch_compiled_and_attrs(result, original_model)
  
      elif precision == "bf16":
          invalidInputError(
              accelerator == "openvino" or accelerator is None,
              "Accelerator {} is invalid for BF16.".format(accelerator),
          )
          invalidInputError(
              device == "CPU",
              "Device {} don't support bfloat16.".format(device),
          )
          if accelerator == "openvino":
              final_openvino_option = {
                  "INFERENCE_PRECISION_HINT": "bf16"
              }
              if openvino_config is not None:
                  final_openvino_option.update(openvino_config)
              from bigdl.nano.deps.openvino.tf.model import KerasOpenVINOModel  # type: ignore
  
              result = KerasOpenVINOModel(
                  model,
                  input_spec=input_spec,
                  precision=precision,
                  thread_num=thread_num,
                  device=device,
                  config=final_openvino_option,
                  logging=logging,
                  **kwargs,
              )
          elif accelerator is None:
              return BF16Model(model, custom_objects=custom_objects)
          return patch_compiled_and_attrs(result, original_model)
  
      invalidInputError(
          approach == "static",
          "Only 'static' approach is supported now.",
      )
  
      if not isinstance(x, tf.data.Dataset) and y is None:
          # fake label to make quantization work
          y = range(len(x))  # type: ignore
      if isinstance(x, tf.data.Dataset):
          batch_data = next(iter(x))
          # todo: for now, if len(batch_data) == 2 we assume it is (x, y),
          # otherwise, we assume it is x or (x1, x2, x3, ...)
          if (
              isinstance(batch_data, tf.Tensor)
              or isinstance(batch_data, tuple)
              and len(batch_data) != 2
          ):
              # fake label to make quantization work
              y = range(len(x))  # type: ignore
              y = tf.data.Dataset.from_tensor_slices(y)
              x = tf.data.Dataset.zip((x, y))
  
      if accelerator is None:
          if isinstance(x, tf.data.Dataset):
              calib_dataset = x
          else:
              calib_dataset = tf.data.Dataset.from_tensor_slices((x, y))
          if batch:
              calib_dataset = calib_dataset.batch(batch)
  
          try_fake_inference(model, input_spec)
          if model.inputs is None or model.outputs is None:
              INC_LESS_14 = compare_version(
                  "neural_compressor", operator.lt, "1.14"
              )
              # oly works for inc version >= 1.14
              if not INC_LESS_14:
                  # try to fake input and output for model
                  signature = inspect.signature(model.call)
                  input_names = []
                  for param in signature.parameters.values():
                      input_names.append(param.name)
                  if inputs is None:
                      inputs = input_names
                  if outputs is None:
                      outputs = "outputs"  # type: ignore
  
          result = inc_quantzie(
              model,
              dataloader=calib_dataset,
              eval_func=eval_func,
              metric=metric,
              framework="tensorflow",
              conf=conf,
              approach=approach,
              tuning_strategy=tuning_strategy,
              accuracy_criterion=accuracy_criterion,
              timeout=timeout,
              max_trials=max_trials,
              inputs=inputs,
              outputs=outputs,
          )
      elif accelerator == "openvino":
          from bigdl.nano.deps.openvino.tf.model import KerasOpenVINOModel  # type: ignore
  
          if isinstance(model, KerasOpenVINOModel):  # type: ignore
              openvino_model = model
          else:
              # For CPU: fp32 -> int8, for GPU: fp16 -> int8
              _precision = "fp16" if device != "CPU" else "fp32"
              if device == "VPUX":
                  # for fp16 on VPUX, must specify mean_value.
                  invalidInputError(
                      "mean_value" in kwargs,
                      "If you want to quantize with openvino on VPUX device, "
                      "you must specify mean_value for model optimizer "
                      "function. For more details about model optimizer, you "
                      "can see mo --help .",
                  )
              openvino_model = KerasOpenVINOModel(
                  model,
                  input_spec=input_spec,
                  precision=_precision,
                  thread_num=thread_num,
                  device=device,
                  config=openvino_config,
                  logging=logging,
                  **kwargs,
              )
          if metric:
              if not isinstance(accuracy_criterion, dict):
                  accuracy_criterion = {
                      "relative": 0.99,
                      "higher_is_better": True,
                  }
              drop_type = (
                  "relative"
                  if "relative" in accuracy_criterion
                  else "absolute"
              )
              higher_is_better = accuracy_criterion.get(
                  "higher_is_better", None
              )
              maximal_drop = accuracy_criterion.get(drop_type, None)
          else:
              drop_type, higher_is_better, maximal_drop = (
                  None,
                  None,
                  None,
              )
          result = openvino_model.pot(
              x=x,  # type: ignore
              y=y,
              metric=metric,
              higher_better=higher_is_better,
              drop_type=drop_type,
              maximal_drop=maximal_drop,
              max_iter_num=max_trials,
              sample_size=sample_size,
              config=openvino_config,
              thread_num=thread_num,
          )
      elif accelerator == "onnxruntime":
          # convert tensorflow model to onnx model
          from bigdl.nano.deps.onnxruntime.tensorflow.model import (
              KerasONNXRuntimeModel,
          )
  
          if isinstance(model, KerasONNXRuntimeModel):  # type: ignore
              onnx_model = model
          else:
              onnx_model = InferenceOptimizer.trace(
                  model=model,
                  accelerator="onnxruntime",
                  input_spec=input_spec,
                  thread_num=thread_num,
              )
  
          # trace onnx model
          method_map = {
              "qlinear": "onnxrt_qlinearops",
              "integer": "onnxrt_integerops",
              None: "onnxrt_qlinearops",  # default
          }
          framework = method_map.get(method, None)
          result = inc_quantzie(
              onnx_model,
              dataloader=(x, y),
              eval_func=eval_func,
              metric=metric,
              framework=framework,
              thread_num=thread_num,
              conf=conf,
              approach=approach,
              tuning_strategy=tuning_strategy,
              accuracy_criterion=accuracy_criterion,
              timeout=timeout,
              max_trials=max_trials,
              inputs=inputs,
              outputs=outputs,
              onnx_option="tensorflow",
              onnxruntime_session_options=onnxruntime_session_options,
          )
          result._inputs_dtypes = onnx_model._inputs_dtypes
          result._mode = "arg"  # todo
      else:
          invalidInputError(
              False, "Accelerator {} is invalid.".format(accelerator)
          )
      return patch_compiled_and_attrs(result, original_model)
  
imports: import os
  import subprocess
  import tempfile
  import cloudpickle
  import copy
  import time
  import operator
  from pathlib import Path
  import numpy
  import traceback
  import inspect
  import sigfig
  import tensorflow
  import keras
  from typing import Dict, Optional, List, Union, Callable
  from bigdl.nano.utils.common import BaseInferenceOptimizer, available_acceleration_combination, AccelerationOption, latency_calculate_helper, format_optimize_result
  from bigdl.nano.utils.common import invalidInputError
  from bigdl.nano.utils.tf import _ModuleWrapper
  from bigdl.nano.utils.tf import patch_compiled_and_attrs, patch_attrs
  from tensorflow.keras import Model
  from tensorflow.data import Dataset
  from tensorflow.keras.metrics import Metric
  from bigdl.nano.deps.neural_compressor.inc_api import quantize
  from bigdl.nano.deps.openvino.openvino_api import KerasOpenVINOModel
  from bigdl.nano.deps.onnxruntime.onnxruntime_api import KerasONNXRuntimeModel
  from bigdl.nano.deps.openvino.openvino_api import load_openvino_model
  from bigdl.nano.deps.onnxruntime.onnxruntime_api import load_onnxruntime_model
  from bigdl.nano.deps.neural_compressor.inc_api import load_inc_model
  from bigdl.nano.tf.keras.amp import BF16Model, load_bf16_model
  from bigdl.nano.utils.common import compare_version
  from bigdl.nano.utils.tf import try_fake_inference
label_desc: Use image node_id 3 for calling the InferenceOptimizer obj's underlying member method code with example usage: obj.quantize(model, x, y, precision, accelerator, input_spec, eval_func, metric, accuracy_criterion, approach, method, conf, tuning_strategy, timeout, max_trials, batch, thread_num, device, custom_objects, inputs, outputs, sample_size, onnxruntime_session_options, openvino_config, logging) and returns: patch_compiled_and_attrs, patch_compiled_and_attrs, patch_compiled_and_attrs, BF16Model