TFLite conversion (w/ int8 quantization) from ConcreteFunction is broken
@DLumi  Please ensure you provide a representative dataset during conversion for accurate calibration and double-check quantization parameters, especially those related to calibration. Also try different quantization options to find optimal settings. In order to expedite the trouble-shooting process, please provide a code snippet to reproduce the issue reported here.
Thank you! @sushreebarsa Can you please explain to me how providing a dataset of actual data instead of randomized dummy would actually help with a conversion error? 

Edit: Apparently, github does not like links that end with an underscore, so I formatted it as a code block, please, try to access the file once again. Please disregard whatever was there regarding you accessing the colab file Hi @DLumi ,

Sorry for the delay. The error with code is due to incorrect representative dataset usage. Please find the corrected [code](https://colab.research.google.com/gist/LakshmiKalaKadali/76b2ccec371ed520c3e946d485ed4070/tflite-from-cf.ipynb#scrollTo=gcu374Ewb-y8). Please let us know if problem persists.

Thank You. @LakshmiKalaKadali Could you please point me out what part was / needs to be changed? 
I compared my colab notebook with yours cell by cell and couldn't really spot the corrected part.  Hi @DLumi, 

In my previous post, code link is not redirecting to corrected code. Please find the corrected code below. Here is the detailed[ gist](https://colab.research.google.com/gist/LakshmiKalaKadali/2ee2f75cf69921c58eff1df85df87f1f/tflite-issue-62664.ipynb).
```import tensorflow as tf
import numpy as np

print('TF version:', tf.__version__)

# create keras model
keras_model = tf.keras.applications.MobileNetV2(weights=None)

input_names = [x.name for x in keras_model.inputs]

print(input_names)

# retrieve concrete function from it
full_model = tf.function(lambda x: keras_model(x))
input_tensors = [tf.TensorSpec(shape=inp.shape, dtype=tf.float32, name=inp.name) for inp in keras_model.inputs]
cf = full_model.get_concrete_function(x=input_tensors)

# loader with random data for now
def tflite_loader(input_names):
    for _ in range(4):
        yield {k: (np.random.random([64, 224, 224, 3])).astype('float32') for k in input_names}
'''
for d in tflite_loader():
  for k, v in d.items():
    print(k, v.shape)
  break
'''
# Here, I have changed your code with representative_dataset_gen function
# This function converts the data generated by tflite_loader into a suitable format to use as a representative dataset for conversion.
def representative_dataset_gen():
    for data in tflite_loader(input_names):
        yield [tf.constant(data[name]) for name in input_names]
    
converter = tf.lite.TFLiteConverter.from_concrete_functions([cf], trackable_obj=keras_model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter._experimental_disable_per_channel = True
converter.target_spec.supported_types = [tf.int8]
converter.representative_dataset = representative_dataset_gen  #added this line of code: notifying the representative_dataset_gen function to converter
tflite_model = converter.convert()

# To save the tflite model code
with open('model.tflite', 'wb') as f:
    f.write(tflite_model)
```
Thank You @LakshmiKalaKadali so, basically, the main change is to yield a list of tensors instead of a dict? But that's more of a workaround than a fix, don't you think? 
Because as far as I'm concerned, TFLite is meant to be fed with dictionaries as well. You can run inference on dictionaries with TFLite, and the converter initialized from keras model can digest representative datasets that yield dictionaries as well. 
So I guess, thanks for the workaround, but can we probably have an actual fix for this so that the behavior of the converter is consistent? 

P.S. I've updated the initial code at `https://colab.research.google.com/drive/1am-t2AeayTFDpZRcUzdROH1Jf7K03gF_` to add cells representing conversion from keras model (just in case you need this context, although, it's just one line of the difference) Hi @DLumi ,

Yes, you are right, the TFlite models initialized from Keras model works with representative datasets that yield dictionaries also.  In the code, as the concrete function with signature  is used, it is suggestible to pass concrete function to converter rather than a base keras model.

Thank You
 @LakshmiKalaKadali I dunno about what's suggestible and what is not, but if there is a public API that helps me do stuff I want - I use it. And if there are multiple APIs for the same thing I assume they are consistent, which is not the case here.
To achieve consistency I'd propose to either fix the bug preventing calibration process (CF converter) to feed on dictionaries, or to prohibit dictionaries altogether, i.e. disallowing the use of them in `from_keras_model` API and providing a clear understandable error message instead of confusing error that is present now. 
In either case, I'd also correct documentation to explicitly say what data structures are expected to be yielded from representative datasets, as now it's not as clear as it potentially could be.  Hi @pkgoogle,

Please look into the issue.

Thank You Hi, @DLumi, is there a resource/documentation which shows that the dictionary workflow is supported? I'm trying to figure out if this a regression or an API change, 

https://www.tensorflow.org/lite/models/convert/convert_models#convert_concrete_functions_ is the current way that is supported/recommended.

Thanks for your help. @pkgoogle 
Actually, now that I remember, it was per documentation, yes.
https://www.tensorflow.org/lite/performance/post_training_quantization#full_integer_quantization

> Since TensorFlow 2.7 version, we recommend using the signature-based approach over the input tensor list-based approach because the input tensor ordering can be easily flipped.

So, since documentation on that is a little vague, I assumed that "signature-based approach" basically means that my representative dataset is supposed to yield dicts. I kind of forgot that the list option also existed as I spent quite a while setting this whole thing up (given the errors and stuff).  Hi @DLumi, this might be related to https://github.com/tensorflow/tensorflow/issues/62620, the signature seems to get removed in certain situations

Hi @miaout17, can you please take a look? Thanks.
### 1. System information

- OS Platform and Distribution (e.g., Linux Ubuntu 16.04): Win 10 22H2 (but reproducible elsewhere)
- TensorFlow installation (pip package or built from source): pip package
- TensorFlow library (version, if pip package or github SHA, if built from source): 2.14.0

### 2. Code

Provide code to help us reproduce your issues using one of the following options:

`https://colab.research.google.com/drive/1am-t2AeayTFDpZRcUzdROH1Jf7K03gF_`

### 3. Failure after conversion

N/A

### 4. (optional) RNN conversion support

N/A

### 5. (optional) Any other info / logs

TFLite converter fails on calibration step when trying to convert ConcreteFunctions with int8 quantization. 
It seems that somewhere during the process it generates a saved model without any signatures, which leads to fail on calibration. 
I tried toggling `converter.experimental_lower_to_saved_model`, it does nothing in this case. 
As a workaround, `tf.lite.TFLiteConverter.from_keras_model()` does work as intended, but I'd like the dedicated CF conversion pipeline to be fixed. 

```
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
[<ipython-input-4-24b64f09cd68>](https://localhost:8080/#) in <cell line: 6>()
      4 converter.target_spec.supported_types = [tf.int8]
      5 converter.representative_dataset = tflite_loader
----> 6 tflite_model = converter.convert()

14 frames
[/usr/local/lib/python3.10/dist-packages/tensorflow/lite/python/lite.py](https://localhost:8080/#) in convert(self)
   2183         Invalid quantization parameters.
   2184     """
-> 2185     return super(TFLiteConverterV2, self).convert()
   2186 
   2187 

[/usr/local/lib/python3.10/dist-packages/tensorflow/lite/python/lite.py](https://localhost:8080/#) in wrapper(self, *args, **kwargs)
   1137   def wrapper(self, *args, **kwargs):
   1138     # pylint: disable=protected-access
-> 1139     return self._convert_and_export_metrics(convert_func, *args, **kwargs)
   1140     # pylint: enable=protected-access
   1141 

[/usr/local/lib/python3.10/dist-packages/tensorflow/lite/python/lite.py](https://localhost:8080/#) in _convert_and_export_metrics(self, convert_func, *args, **kwargs)
   1091     self._save_conversion_params_metric()
   1092     start_time = time.process_time()
-> 1093     result = convert_func(self, *args, **kwargs)
   1094     elapsed_time_ms = (time.process_time() - start_time) * 1000
   1095     if result:

[/usr/local/lib/python3.10/dist-packages/tensorflow/lite/python/lite.py](https://localhost:8080/#) in convert(self)
   1790     )
   1791 
-> 1792     return super(TFLiteFrozenGraphConverterV2, self).convert(
   1793         graph_def, input_tensors, output_tensors
   1794     )

[/usr/local/lib/python3.10/dist-packages/tensorflow/lite/python/lite.py](https://localhost:8080/#) in convert(self, graph_def, input_tensors, output_tensors)
   1376     )
   1377 
-> 1378     return self._optimize_tflite_model(
   1379         result, self._quant_mode, quant_io=self.experimental_new_quantizer
   1380     )

[/usr/local/lib/python3.10/dist-packages/tensorflow/lite/python/convert_phase.py](https://localhost:8080/#) in wrapper(*args, **kwargs)
    213       except Exception as error:
    214         report_error_message(str(error))
--> 215         raise error from None  # Re-throws the exception.
    216 
    217     return wrapper

[/usr/local/lib/python3.10/dist-packages/tensorflow/lite/python/convert_phase.py](https://localhost:8080/#) in wrapper(*args, **kwargs)
    203     def wrapper(*args, **kwargs):
    204       try:
--> 205         return func(*args, **kwargs)
    206       except ConverterError as converter_error:
    207         if converter_error.errors:

[/usr/local/lib/python3.10/dist-packages/tensorflow/lite/python/lite.py](https://localhost:8080/#) in _optimize_tflite_model(self, model, quant_mode, quant_io)
   1035         q_allow_float = quant_mode.is_allow_float()
   1036         q_variable_quantization = quant_mode.enable_mlir_variable_quantization
-> 1037         model = self._quantize(
   1038             model,
   1039             q_in_type,

[/usr/local/lib/python3.10/dist-packages/tensorflow/lite/python/lite.py](https://localhost:8080/#) in _quantize(self, result, input_type, output_type, activations_type, bias_type, allow_float, enable_variable_quantization)
    733     )
    734     if self._experimental_calibrate_only or self.experimental_new_quantizer:
--> 735       calibrated = calibrate_quantize.calibrate(
    736           self.representative_dataset.input_gen
    737       )

[/usr/local/lib/python3.10/dist-packages/tensorflow/lite/python/convert_phase.py](https://localhost:8080/#) in wrapper(*args, **kwargs)
    213       except Exception as error:
    214         report_error_message(str(error))
--> 215         raise error from None  # Re-throws the exception.
    216 
    217     return wrapper

[/usr/local/lib/python3.10/dist-packages/tensorflow/lite/python/convert_phase.py](https://localhost:8080/#) in wrapper(*args, **kwargs)
    203     def wrapper(*args, **kwargs):
    204       try:
--> 205         return func(*args, **kwargs)
    206       except ConverterError as converter_error:
    207         if converter_error.errors:

[/usr/local/lib/python3.10/dist-packages/tensorflow/lite/python/optimize/calibrator.py](https://localhost:8080/#) in calibrate(self, dataset_gen)
    252       dataset_gen: A generator that generates calibration samples.
    253     """
--> 254     self._feed_tensors(dataset_gen, resize_input=True)
    255     return self._calibrator.Calibrate()

[/usr/local/lib/python3.10/dist-packages/tensorflow/lite/python/optimize/calibrator.py](https://localhost:8080/#) in _feed_tensors(self, dataset_gen, resize_input)
    119           self._interpreter = Interpreter(model_content=self._model_content)
    120         signature_key = None
--> 121         input_array = self._create_input_array_from_dict(None, sample)
    122       elif isinstance(sample, list):
    123         signature_key = None

[/usr/local/lib/python3.10/dist-packages/tensorflow/lite/python/optimize/calibrator.py](https://localhost:8080/#) in _create_input_array_from_dict(self, signature_key, inputs)
     86   def _create_input_array_from_dict(self, signature_key, inputs):
     87     input_array = []
---> 88     signature_runner = self._interpreter.get_signature_runner(signature_key)
     89     input_details = sorted(
     90         signature_runner.get_input_details().items(),

[/usr/local/lib/python3.10/dist-packages/tensorflow/lite/python/interpreter.py](https://localhost:8080/#) in get_signature_runner(self, signature_key)
    851     if signature_key is None:
    852       if len(self._signature_defs) != 1:
--> 853         raise ValueError(
    854             'SignatureDef signature_key is None and model has {0} Signatures. '
    855             'None is only allowed when the model has 1 SignatureDef'.format(

ValueError: SignatureDef signature_key is None and model has 0 Signatures. None is only allowed when the model has 1 SignatureDef
```
