code: def prepare_converter_for_quantization(
      model: "TFPreTrainedModel",
      config: "TFLiteConfig",
      preprocessor: Optional[Preprocessor],
      signatures: Dict[str, Callable],
      quantization_config: "TFLiteQuantizationConfig",
      converter: "tf.lite.TFLiteConverter",
      task: Optional[str] = None,
  ):
      import tensorflow as tf
  
      if (
          not config.supports_quantization_approach(
              quantization_config.approach
          )
          and not quantization_config.fallback_to_float
      ):
          raise QuantizationApproachNotSupported(
              f"{model.config.model_type} do not support full {quantization_config.approach} quantization, use "
              "fallback_to_float=True to fallback to the float implementation for the unsupported ops."
          )
  
      str_to_dtype = {"int8": tf.int8, "uint8": tf.uint8}
      if quantization_config.approach in [
          QuantizationApproach.INT8,
          QuantizationApproach.INT8x16,
      ]:
          if preprocessor is None:
              raise ValueError(
                  "A preprocessor must be passed for INT8 and INT8x16 quantization since it is needed to preprocess "
                  "the calibration dataset."
              )
  
          converter.optimizations = [tf.lite.Optimize.DEFAULT]
  
          # Handling the calibration dataset:
          # - Either loading the default dataset if no calibration dataset was provided or the required dataset,
          # - Splitting the dataset with the provided dataset split or with the first split if none is provided.
          # - Shuffling the split.
          # - Selecting num_calibration_samples in the dataset split.
          # - Batching the dataset.
          # - Converting it to the TensorFlow format.
  
          if task is None:
              from ...exporters import TasksManager
  
              task = TasksManager.infer_task_from_model(model)
  
          preprocessor_kwargs = {}
          if isinstance(preprocessor, PreTrainedTokenizerBase):
              preprocessor_kwargs["max_length"] = config.sequence_length
          task_processor = (
              TaskProcessorsManager.get_task_processor_class_for_task(
                  task
              )(model.config, preprocessor, preprocessor_kwargs)
          )
  
          if (
              task == "token-classification"
              and model.config.model_type
              in {
                  "bloom",
                  "camembert",
                  "deberta",
                  "gpt2",
                  "roberta",
              }
          ):
              preprocessor.add_prefix_space = True
  
          load_smallest_split = (
              quantization_config.calibration_split is None
          )
          if load_smallest_split:
              logger.warning(
                  "Since no calibration split was provided for the calibration dataset, the smallest split will be "
                  "used if the dataset contains multiple splits."
              )
  
          batch_size = config.batch_size
          num_calibration_samples = (
              quantization_config.num_calibration_samples
          )
          if num_calibration_samples % batch_size != 0:
              new_num_calibration_samples = (
                  num_calibration_samples // batch_size + 1
              ) * batch_size
              logger.info(
                  f"The number of calibration examples ({num_calibration_samples}) does not divide the batch size "
                  f"({batch_size}), using {new_num_calibration_samples} examples instead."
              )
              num_calibration_samples = new_num_calibration_samples
  
          if (
              quantization_config.calibration_dataset_name_or_path
              is None
          ):
              calibration_dataset = task_processor.load_default_dataset(
                  only_keep_necessary_columns=True,
                  load_smallest_split=load_smallest_split,
                  num_samples=num_calibration_samples,
                  shuffle=True,
                  split=quantization_config.calibration_split,
              )
          else:
              data_keys = {}
              if quantization_config.primary_key is not None:
                  data_keys["primary"] = quantization_config.primary_key
              if quantization_config.secondary_key is not None:
                  data_keys[
                      "secondary"
                  ] = quantization_config.secondary_key
              if quantization_config.question_key is not None:
                  data_keys[
                      "question"
                  ] = quantization_config.question_key
              if quantization_config.context_key is not None:
                  data_keys["context"] = quantization_config.context_key
              if quantization_config.image_key is not None:
                  data_keys["image"] = quantization_config.image_key
  
              calibration_dataset = task_processor.load_dataset(
                  quantization_config.calibration_dataset_name_or_path,
                  data_keys=data_keys,
                  only_keep_necessary_columns=True,
                  load_smallest_split=load_smallest_split,
                  num_samples=num_calibration_samples,
                  shuffle=True,
                  name=quantization_config.calibration_dataset_config_name,
                  split=quantization_config.calibration_split,
              )
  
          if batch_size > 1:
              # Batching can be buggy if a column for on example is empty, and another is not.
              # Since we only care about the columns used by the model (no evaluation), we can filter by only keeping
              # columns that are used at least by one signature. If batching still fails, then it is wanted because it
              # means that there is missing data for calibrating the model.
              columns_needed_by_all_signatures = set()
              for tf_function in signatures.values():
                  args, kwargs = tf_function.structured_input_signature
                  columns_needed_by_all_signatures |= {
                      input_.name for input_ in args
                  }
                  columns_needed_by_all_signatures |= {
                      input_.name for input_ in kwargs.values()
                  }
  
              # TODO: maybe use calibration.select_columns(columns_needed_by_all_signatures) instead, did not work?
              columns_to_remove = (
                  set(calibration_dataset.column_names)
                  - columns_needed_by_all_signatures
              )
              calibration_dataset = calibration_dataset.remove_columns(
                  columns_to_remove
              )
  
              def batching_function(examples):
                  return {
                      column_name: [examples[column_name]]
                      for column_name in examples.keys()
                  }
  
              calibration_dataset = calibration_dataset.map(
                  batching_function, batched=True, batch_size=batch_size
              )
  
          calibration_dataset = calibration_dataset.with_format("tf")
          converter.representative_dataset = (
              create_representative_dataset(
                  signatures, calibration_dataset
              )
          )
  
          # Handling the OpsSet.
          if quantization_config.approach is QuantizationApproach.INT8:
              opsset = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
          else:
              logger.warning(
                  "The latency with 8x16 quantization can be much slower than int8 only because it is currently an "
                  "experimental feature, use this only if necessary."
              )
              opsset = [
                  tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8
              ]
          if quantization_config.fallback_to_float:
              opsset.append(tf.lite.OpsSet.TFLITE_BUILTINS)
          converter.target_spec.supported_ops = opsset
  
          # Handling the inputs and outputs dtype, this allows to have a TFLite model taking integers inputs and
          # outputting integers outputs, needed for integer-only hardware.
          if quantization_config.inputs_dtype is not None:
              converter.inference_input_type = str_to_dtype[
                  quantization_config.inputs_dtype
              ]
          if quantization_config.outputs_dtype is not None:
              converter.inference_output_type = str_to_dtype[
                  quantization_config.outputs_dtype
              ]
      elif (
          quantization_config.approach
          is QuantizationApproach.INT8_DYNAMIC
      ):
          converter.optimizations = [tf.lite.Optimize.DEFAULT]
      elif quantization_config.approach is QuantizationApproach.FP16:
          converter.optimizations = [tf.lite.Optimize.DEFAULT]
          converter.target_spec.supported_types = [tf.float16]
  
file_path: optimum/optimum/exporters/tflite/convert.py
imports: from pathlib import Path
  from tempfile import TemporaryDirectory
  from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Tuple
  import numpy
  from transformers import PreTrainedTokenizerBase
  from transformers.utils import is_tf_available
  from ...utils import logging
  from ...utils.preprocessing import Preprocessor, TaskProcessorsManager
  from ..error_utils import AtolError, OutputMatchError, ShapeError
  from .base import QuantizationApproach, QuantizationApproachNotSupported
label_desc: Use image node_id 3 for calling a global function with example usage: prepare_converter_for_quantization(model, config, preprocessor, signatures, quantization_config, converter, task) and returns: unknown