Reputation: 2157
I am quantizing a model. The model takes 224x224 input.
I preprocess the data with a build-in function preprocess_input()
which subtracts some center pixels.
Now when using a simple image with this preprocessing function in the representative_dataset_gen()
everything works fine
def representative_dataset_gen():
pfad='./000001.jpg'
img = cv2.imread(pfad)
img = np.expand_dims(img,0).astype(np.float32)
img = preprocess_input(img)
yield [img]
But when I use a generator function to use more than one image
def prepare(img):
img = np.expand_dims(img,0).astype(np.float32)
img = preprocess_input(img)
return arg
repDatagen=tf.keras.preprocessing.image.ImageDataGenerator(preprocessing_function=prepare)
datagen=repDatagen.flow_from_directory(folderpath,target_size=size,batch_size=1)
def representative_dataset_gen():
for _ in range(10):
img = datagen.next()
yield [img]
I get following error:
ValueError: Failed to convert value into readable tensor.
My guess: This is due to ImageDataGenerator(preprocessing_function=prepare)
. In the tensorflow description it says:
function that will be applied on each input. The function will run after the image is resized and augmented. The function should take one argument: one image (Numpy tensor with rank 3), and should output a Numpy tensor with the same shape.
I tried to adjust the shape of the img output of the "prepare" function without and with np.squeez().
This results in either (1,244,244,3) or (224,224,3). But I still get the error. I also tried tf.convert_to_tensor()
with the same error.
def prepare(img):
img = np.expand_dims(img,0).astype(np.float32)
img = preprocess_input(img, version=2)
img = np.squeeze(img)
arg = tf.convert_to_tensor(img, dtype=tf.float32)
return arg
Does anyone know how I have to prepare the output to get the correct tensor?
Thanks
Upvotes: 0
Views: 2181
Reputation: 11
Thank you, you are amazing and your post save my day, I apply quantization on YOLO model, the code:
#https://github.com/ultralytics/ultralytics/issues/6676
#https://github.com/onnx/onnx-tensorflow
#https://github.com/onnx/onnx-tensorflow/blob/main/example/onnx_to_tf.py
#https://docs.ultralytics.com/modes/export/#usage-examples
#https://coral.ai/docs/edgetpu/models-intro/#compatibility-overview
import tensorflow as tf
import numpy as np
import os
import cv2
def representative_data_gen():
image_paths = "/..../images/"
op_ = 0
for image_path in os.listdir(image_paths):
op_ = op_ + 1
image = cv2.imread("/.../images/"+image_path)
print("------111-------", image.shape)
image = cv2.resize(image, (640, 640))
print("------222-------", image.shape)
image = np.array(image).astype(np.float32) / 255.0
print("------333-------", image.shape)
image = np.transpose(image, (2, 0, 1)) # (H, W, C) -> (C, H, W)
print("------444-------", image.shape)
image = np.expand_dims(image, axis=0) # Add batch dimension
print("------555-------", image.shape)
if op_ == 100:
break
print(len(image), len(image[0]), len(image[0][0]), len(image[0][0][0]))
yield [image] #[np.array(image[0][0], dtype=np.float32)]# [image]
print(" what next ")
# ... (Load your TensorFlow model)
converter = tf.lite.TFLiteConverter.from_saved_model('/..../teston')
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.int8
converter.inference_output_type = tf.int8
converter.representative_dataset = representative_data_gen # Provide a data generator function
tflite_quant_model = converter.convert()
# Save the quantized model
with open('/..../teston/quantized_model2.tflite', 'wb') as f:
f.write(tflite_quant_model)
Upvotes: 0
Reputation: 2157
The problem was actually the generator output.
The output is not a np.array()
. Converting with np.asarray() was not possible as it throws an error.
So the answer is quite simple:
the data_generator output is a tuple
so simply yield only the first element img[0]
.
The code in total:
size=(224,224)
def prepare(img):
img = np.expand_dims(img,0).astype(np.float32)
img = preprocess_input(img, version=2)
return img
repDatagen=tf.keras.preprocessing.image.ImageDataGenerator(preprocessing_function=prepare)
datagen=repDatagen.flow_from_directory(folderpath,target_size=size,batch_size=1)
def representative_dataset_gen():
for _ in range(10):
img = datagen.next()
yield [img[0]]
#yield [np.array(img[0], dtype=np.float32)] # also possible
Upvotes: 1