TFLIte Cannot set tensor: Dimension mismatch on model conversion - python

I've a keras model constructed as follows
module_url = "https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/4"
backbone = hub.KerasLayer(module_url)
backbone.build([None, 224, 224, 3])
model = tf.keras.Sequential([backbone, tf.keras.layers.Dense(len(classes), activation='softmax')])
model.build([None, 224, 224, 3])
model.compile('adam', loss='sparse_categorical_crossentropy')
Then I load Caltech101 dataset from TF hub as follows
samples, info = tfds.load("caltech101", with_info=True)
train_samples, test_samples = samples['train'], samples['test']
def normalize(row):
image, label = row['image'], row['label']
image = tf.dtypes.cast(image, tf.float32)
image = tf.image.resize(image, (224, 224))
image = image / 255.0
return image, label
train_data = train_samples.repeat().shuffle(1024).map(normalize).batch(32).prefetch(1)
test_data = test_samples.map(normalize).batch(1)
Now i'm ready to train and save my model as follows:
model.fit_generator(train_data, epochs=1, steps_per_epoch=100)
saved_model_dir = './output'
tf.saved_model.save(model, saved_model_dir)
At this point the model is usuable, I can evaluate an input of shape (224, 224, 3). I try to convert this model as follows:
def generator2():
data = train_samples
for _ in range(num_calibration_steps):
images = []
for image, _ in data.map(normalize).take(1):
images.append(image)
yield images
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = tf.lite.RepresentativeDataset(generator2)
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
tflite_default_quant_model = converter.convert()
The conversion triggers the following error
/usr/local/lib/python3.6/dist-packages/tensorflow_core/lite/python/optimize/tensorflow_lite_wrap_calibration_wrapper.py in FeedTensor(self, input_value)
110
111 def FeedTensor(self, input_value):
--> 112 return _tensorflow_lite_wrap_calibration_wrapper.CalibrationWrapper_FeedTensor(self, input_value)
113
114 def QuantizeModel(self, input_py_type, output_py_type, allow_float):
ValueError: Cannot set tensor: Dimension mismatch
Now there is a similar question but in there case they are loading an already converted model unlike my case where the issue happens when I try to convert a model.
The converter object is an auto generated class from C++ code using SWIG which makes it difficult to inspect. How can I found the exact Dimension expected by the converter object?

Had the same problem when using
def representative_dataset_gen():
for _ in range(num_calibration_steps):
# Get sample input data as a numpy array in a method of your choosing.
yield [input]
from https://www.tensorflow.org/lite/performance/post_training_quantization.
It seems that converter.representative_dataset expects a list containing one example with shape (1, input_shape). That is, using something along the lines
def representative_dataset_gen():
for i in range(num_calibration_steps):
# Get sample input data as a numpy array in a method of your choosing.
yield [input[i:i+1]]
if input has shape (num_samples, input_shape), solved the problem. In your case, when using tf Datasets, a working example would be
import tensorflow as tf
import tensorflow_hub as hub
import tensorflow_datasets as tfds
samples, info = tfds.load("caltech101", with_info=True)
train_samples, test_samples = samples['train'], samples['test']
def normalize(row):
image, label = row['image'], row['label']
image = tf.dtypes.cast(image, tf.float32)
image = tf.image.resize(image, (224, 224))
image = image / 255.0
return image, label
train_data = train_samples.repeat().shuffle(1024).map(normalize).batch(32).prefetch(1)
test_data = test_samples.map(normalize).batch(1)
module_url = "https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/4"
backbone = hub.KerasLayer(module_url)
backbone.build([None, 224, 224, 3])
model = tf.keras.Sequential([backbone, tf.keras.layers.Dense(102, activation='softmax')])
model.build([None, 224, 224, 3])
model.compile('adam', loss='sparse_categorical_crossentropy')
model.fit_generator(train_data, epochs=1, steps_per_epoch=100)
saved_model_dir = 'output/'
tf.saved_model.save(model, saved_model_dir)
num_calibration_steps = 50
def generator():
single_batches = train_samples.repeat(count=1).map(normalize).batch(1)
i=0
while(i<num_calibration_steps):
for batch in single_batches:
i+=1
yield [batch[0]]
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = tf.lite.RepresentativeDataset(generator)
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
tflite_default_quant_model = converter.convert()

I had the same problem, I used this solution, setting inputs_test as your input test it should work also for you:
def representative_dataset():
arrs=np.expand_dims(inputs_test, axis=1).astype(np.float32)
for data in arrs:
yield [ data ]
import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.int8 # or tf.uint8
converter.inference_output_type = tf.int8 # or tf.uint8
tflite_quant_model = converter.convert()

Applied this on a raspberry pi and did worked, just be sure to install tflite outside of your venev
import tflite_runtime.interpreter as tflite

Related

Error Shape are not incompatible when using TFDebertaForSequenceClassification for binary classification

i was trying to use recall metrics for the TFDebertaForSequenceClassification model for binary classification with label 0 and 1, but i got this error:
ValueError: Shapes (32, 2) and (32, 1) are incompatible
anyone know how to solve it ?
this is how i processed the data:
with tf.device('/cpu:0'):
train_data = tf.data.Dataset.from_tensor_slices((train_df["body"].values, train_df["label"].values))
valid_data = tf.data.Dataset.from_tensor_slices((valid_df.body.values, valid_df.label.values))
def map_example_to_dict(input_ids, attention_masks, token_type_ids, label):
X = {
"input_ids": input_ids,
"token_type_ids": token_type_ids,
"attention_mask": attention_masks,
}
Y = label
return X, Y
def encode_examples(df, limit=-1):
# prepare list, so that we can build up final TensorFlow dataset from slices.
input_ids_list = []
token_type_ids_list = []
attention_mask_list = []
labels = []
for data in df.to_numpy():
bert_input = tokenizer(data[2],add_special_tokens=True,
max_length=MAX_SEQ_LEN,
padding='max_length',
return_token_type_ids=True,
truncation=True)
input_ids_list.append(bert_input['input_ids'])
token_type_ids_list.append(bert_input['token_type_ids'])
attention_mask_list.append(bert_input['attention_mask'])
labels.append([data[3]])
return tf.data.Dataset.from_tensor_slices((input_ids_list, attention_mask_list, token_type_ids_list, labels)).map(map_example_to_dict)
encoded_train_input = encode_examples(train_df).shuffle(1000).batch(32, drop_remainder=True)
encoded_valid_input = encode_examples(valid_df).shuffle(1000).batch(32, drop_remainder=True)
and this is how i setup the mode:
model = TFDebertaForSequenceClassification.from_pretrained('kamalkraj/deberta-base')
lr = 2e-6 #1e-6 #2e-5 #3e-5
epochs = 1
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=lr),
loss=tf.keras.losses.BinaryCrossentropy(),
metrics=[tf.keras.metrics.BinaryAccuracy(), tf.keras.metrics.Recall()])
history = model.fit(encoded_train_input, validation_data=encoded_valid_input, epochs=epochs, verbose=1)
this is the screenshot error:
shape not incompatible error
Try passing the number of classes to the model.
configure = DebertaConfig(model_name, gradient_checkpointing=True, num_labels=3)
model=TFDebertaForSequenceClassification.from_pretrained('kamalkraj/deberta-base', config=configure)

TFLite: `ValueError: Model input is not quantized.`

Problem
I try to convert the crop_and_resize operation to TFLite. I am using the script below. But the conversion fails and the error ValueError: Model input is not quantized. is raised.
Does someone have any idea? I did not find any relevant information on the related previous questions.
Code snippet
import tensorflow as tf
IMG_SIZE = 128
NUM_BOXES = 100
CROP_SIZE = 28
NB_DATA_SAMPLES = 32
BATCH_SIZE = 1
def create_model():
images_ = tf.keras.Input(shape=(IMG_SIZE, IMG_SIZE, 3), batch_size=BATCH_SIZE, dtype=tf.float32)
boxes_ = tf.keras.Input(shape=(NUM_BOXES, 4), batch_size=BATCH_SIZE, dtype=tf.float32)
box_indices = tf.reshape(
tf.repeat(
tf.expand_dims(tf.range(BATCH_SIZE, dtype=tf.int32), axis=-1),
NUM_BOXES,
axis=-1
),
shape=(-1,)
)
cropped_images = tf.image.crop_and_resize(
image=images_,
boxes=tf.reshape(boxes_, (-1, 4)),
box_indices=box_indices,
crop_size=(CROP_SIZE, CROP_SIZE))
model = tf.keras.models.Model(inputs=[images_, boxes_], outputs=cropped_images)
model.summary(line_length=200)
return model
model = create_model()
def representative_dataset_generator():
for _ in range(NB_DATA_SAMPLES):
image_ = tf.random.normal(shape=(1, IMG_SIZE, IMG_SIZE, 3))
bboxes_ = tf.random.uniform((1, NUM_BOXES, 4), maxval=1)
yield [image_, bboxes_]
# Converter
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [
tf.lite.OpsSet.TFLITE_BUILTINS_INT8,
tf.lite.OpsSet.SELECT_TF_OPS
]
converter.target_spec.supported_types = [tf.int8]
converter.inference_input_type = tf.uint8
converter.inference_output_type = tf.uint8
converter.representative_dataset = representative_dataset_generator
quant_model = converter.convert()
Thanks
I could execute your code successfully. However, it only quantize the Reshape layer but not crop layer. So I guess maybe tflite can't quantize the op they do not support.

Loading TF Records into Keras

I am trying to load a custom TFRecord file into my keras model. I attempted to follow this tutorial: https://medium.com/#moritzkrger/speeding-up-keras-with-tfrecord-datasets-5464f9836c36, but adapting for my use.
My goal is to have the functions work similar to ImageDataGenerator from Keras. I cannot use that function because I specific metadata from the images that the generator does not grab. I'm not including that metadata here because I just need the basic network to function first.
I also want to be able to apply this to a transfer learning application.
I keep getting this error: TypeError: Could not build a TypeSpec for None with type NoneType
I am using Tensorflow 2.2
def _parse_function(serialized):
features = \
{
'image': tf.io.FixedLenFeature([], tf.string),
'label': tf.io.FixedLenFeature([], tf.int64),
'shapex': tf.io.FixedLenFeature([], tf.int64),
'shapey': tf.io.FixedLenFeature([], tf.int64),
}
parsed_example = tf.io.parse_single_example(serialized=serialized,
features=features)
shapex = tf.cast(parsed_example['shapex'], tf.int32)
shapey = tf.cast(parsed_example['shapey'], tf.int32)
image_shape = tf.stack([shapex, shapey, 3])
image_raw = parsed_example['image']
# Decode the raw bytes so it becomes a tensor with type.
image = tf.io.decode_raw(image_raw, tf.uint8)
image = tf.reshape(image, image_shape)
# Get labels
label = tf.cast(parsed_example['label'], tf.float32)
return image, label
def imgs_inputs(type, perform_shuffle=False):
records_dir = '/path/to/tfrecord/'
record_paths = [os.path.join(records_dir,record_name) for record_name in os.listdir(records_dir)]
full_dataset = tf.data.TFRecordDataset(filenames=record_paths)
full_dataset = full_dataset.map(_parse_function, num_parallel_calls=16)
dataset_length = (len(list(full_dataset))) #Gets length of datase
iterator = tf.compat.v1.data.make_one_shot_iterator(databatch)
image, label = iterator.get_next()
#labels saved as values ex: [1,2,3], and are now converted to one hot encoded
label = to_categorical(label)
return image, label
image, label = imgs_inputs(type ='Train',perform_shuffle=True)
#Combine it with keras
# base_model = MobileNet(weights='imagenet', include_top=False, input_shape=(200,200,3), dropout=.3)
model_input = Input(shape=[200,200,3])
#Build your network
model_output = Flatten(input_shape=(200, 200, 3))(model_input)
model_output = Dense(19, activation='relu')(model_output)
#Create your model
train_model = Model(inputs=model_input, outputs=model_output)
#Compile your model
optimizer = Adam(learning_rate=.001)
train_model.compile(optimizer=optimizer,loss='mean_squared_error',metrics=['accuracy'],target_tensors=[label])
#Train the model
train_model.fit(epochs=10,steps_per_epoch=2)
image returns array of shape (100,200,200,3) which is a batch of 100 images
label returns array of shape(100,19) which is a batch of 100 labels (there are 19 labels)
The issue related to shapex and shapey but I don't know exactly why.
I set shapex = 200 and shapey=200. Then I rewrote the model to include the transfer learning.
base_model = MobileNet(weights='imagenet', include_top=False, input_shape=(200,200,3), dropout=.3)
x = base_model.output
types = Dense(19,activation='softmax')(x)
model = Model(inputs=base_model.input,outputs=types)
model.compile(
optimizer='adam',
loss = 'sparse_categorical_crossentropy',
metrics=['accuracy']
history = model.fit(get_batches(), steps_per_epoch=1000, epochs=10)
I found everything I needed on this Google Colab:
[https://colab.research.google.com/github/GoogleCloudPlatform/training-data-analyst/blob/master/courses/fast-and-lean-data-science/04_Keras_Flowers_transfer_learning_solution.ipynb#scrollTo=XLJNVGwHUDy1][1]
[1]: https://colab.research.google.com/github/GoogleCloudPlatform/training-data-analyst/blob/master/courses/fast-and-lean-data-science/04_Keras_Flowers_transfer_learning_solution.ipynb#scrollTo=XLJNVGwHUDy1

Read and preprocess image for tensorflow pretrained model

I don't have much experience in Tensorflow. I am trying to use a pretrained ResNet152 model to get the activations of the last layer as output. The images I use for input are stored on my harddrive. So I need to load the images, preprocess them and then get the output from the pretrained model. I found examples for that using URLs of images but when I try it with image paths I can't get it to work. This is what I have so far (only one image for now):
with tf.Graph().as_default():
filename_queue = tf.train.string_input_producer(['./testimg/A_008.jpg'])
reader = tf.WholeFileReader()
key, value = reader.read(filename_queue)
image = tf.image.decode_jpeg(value, channels=3)
preprocessing = preprocessing_factory.get_preprocessing('resnet_v2_152', is_training=False)
processed_image = preprocessing(image, 299,299)
processed_images = tf.expand_dims(processed_image, 0)
with slim.arg_scope(resnet_v2.resnet_arg_scope()):
logits, end_points = resnet_v2.resnet_v2_152(processed_images, is_training=False)
checkpoints_dir='./models/resnet_v2_152'
init_fn = slim.assign_from_checkpoint_fn(
os.path.join(checkpoints_dir, 'resnet_v2_152.ckpt'),
slim.get_variables_to_restore())
with tf.Session() as sess:
init_fn(sess)
np_image, fv = sess.run([image, logits])
I am doing this in a Jupyter Notebook. When I execute the code I don't get an error message, it just keeps running and running until I restart the kernel.
Any ideas what I did wrong? And how would I do it for multiple images?
I found the solution by replacing the tf.WholeFileReader() with tf.read_file():
graph = tf.Graph()
with graph.as_default():
image_path = image = tf.placeholder(tf.string)
image = tf.image.decode_jpeg(tf.read_file(image_path), channels=3)
preprocessing = preprocessing_factory.get_preprocessing('resnet_v2_152', is_training=False)
processed_image = preprocessing(image, image_size, image_size)
processed_images = tf.expand_dims(processed_image, 0)
with slim.arg_scope(resnet_v2.resnet_arg_scope()):
logits, end_points = resnet_v2.resnet_v2_152(processed_images, is_training=False)
checkpoints_dir='./models/resnet_v2_152'
init_fn = slim.assign_from_checkpoint_fn(
os.path.join(checkpoints_dir, 'resnet_v2_152.ckpt'),
slim.get_variables_to_restore())
images = ['./testimg/A_008.jpg', './testimg/logo.jpg']
with tf.Session(graph=graph) as sess:
init_fn(sess)
for img in images:
fv = sess.run(logits, feed_dict={image_path: img})
print(fv)

Tensorflow: Image Preprocessing Inception v4 not accepting my jpg

I'm new to tensorflow and I tried using the script mentioned in Tensorflow: use pretrained inception model to avoid using a TF Record but all my predictions end up in the same wrong class. The evaluation classifier however produces correct results, so it's not the model, I believe the pre processing is what I'm doing wrong.
So I decided to try the inception preprocessing function but now it won't accept my jpgs. I get this error:
inception_preprocessing.py", line 265, in preprocess_for_eval
image = tf.image.central_crop(image, central_fraction=central_fraction)
File "/usr/local/lib/python2.7/dist-packages/tensorflow/python/ops/image_ops_impl.py", line 335, in central_crop
_Check3DImage(image, require_static=False)
File "/usr/local/lib/python2.7/dist-packages/tensorflow/python/ops/image_ops_impl.py", line 129, in _Check3DImage
raise ValueError("'image' must be three-dimensional.")
ValueError: 'image' must be three-dimensional.
Here's my code:
arg_scope = inception_utils.inception_arg_scope()
im_size = 299
inputs = tf.placeholder(tf.float32, (None, im_size, im_size, 3))
inputs = inception_preprocessing.preprocess_image(inputs, im_size, im_size)
with slim.arg_scope(arg_scope):
logits, end_points = inception_v4.inception_v4(inputs)
saver = tf.train.Saver()
saver.restore(sess,ckpt_file)
for image in sample_img:
im = Image.open(image)
im = im.resize((im_size,im_size))
im = np.array(im)
logit_values = sess.run(logits, feed_dict={inputs:im})
print(np.argmax(logit_values))
inputs_processed = inception_preprocessing.preprocess_image(tf.squeeze(inputs), im_size, im_size)
inputs_processed = tf.expand_dims(inputs_processed, 0)
with slim.arg_scope(arg_scope):
logits, end_points = inception_v4.inception_v4(inputs_processed)
# placeholder feed value should be 4D
im = np.exapnd_dims(np.array(im), 0)

Categories