Error when applying tfmot.quantization.keras.quantize_model - tensorflow

The following error occur when I am trying to use the tfmot.quantization.keras.quantize_model to quantize a BERT model.
"NotImplementedError: Can only generate a valid config for hub.KerasLayer(handle, ...)that uses a string handle."
What I did is just trying to apply QAT for the BERT model provided in TF Hub. The following are my codes:
def get_classifier_BERT_QAT(number_of_class=2):
encoder = hub.KerasLayer(hub.load("https://tfhub.dev/tensorflow/bert_en_uncased_L-12_H-768_A-12/3"), trainable=True, name='encoder')
preprocess= hub.KerasLayer(hub.load("https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/1"), name='preprocess')
dropout = tf.keras.layers.Dropout(0.1)
dense = tf.keras.layers.Dense(number_of_class)
model_inputs = dict()
model_inputs['input_type_ids'] = tf.keras.Input(shape=256, dtype='int32', name='input_type_ids')
model_inputs['input_mask'] = tf.keras.Input(shape=256, dtype='int32', name='input_mask')
model_inputs['input_word_ids'] = tf.keras.Input(shape=256, dtype='int32', name='input_word_ids')
outputs = encoder(model_inputs)["pooled_output"]
outputs = dropout(outputs)
outputs = dense(outputs)
model = keras.Model(inputs=model_inputs, outputs=outputs, name="BERT_QAT_Model")
return model
if __name__ == "__main__":
model = get_classifier_BERT_QAT(number_of_class)
import tensorflow_model_optimization as tfmot
quantize_model = tfmot.quantization.keras.quantize_model
qat_model = quantize_model(model)
A bit confused with message. Wondering how can I avoid the problem and quantize the model?
Thanks for any idea or help :)!

Related

Keras generator function in model.fit()

I wrote a simple code to train a neural network with Keras model.fit() with generator. It is important for me to know
how many times the model.fit() calls the generator??
It seems that the generator is called one time before the first epoch and I don't know why?? This one extra call is visible in the attached figure --> 1
Here is my simple code.
import numpy
from keras.models import Model
from keras import layers, losses
from tensorflow.keras import optimizers
input_layer = layers.Input(shape=(256,))
x_layer = layers.BatchNormalization()(input_layer)
x_layer = layers.Dense(500, activation='relu')(input_layer)
x_layer = layers.BatchNormalization()(x_layer)
x_layer = layers.Dense(250, activation='relu')(x_layer)
x_layer = layers.BatchNormalization()(x_layer)
x_layer = layers.Dense(120, activation='relu')(x_layer)
x_layer = layers.BatchNormalization()(x_layer)
output_layer = layers.Dense(16, activation='sigmoid')(x_layer)
NN_model = Model(inputs=input_layer, outputs=output_layer)
NN_model.compile(optimizer=optimizers.RMSprop(), loss=losses.mean_squared_error)
NN_model.summary()
def training_generator(number_of_samples):
while True:
print('\n ---------- One Refer to This File')
NN_inputs = []
NN_labels = []
for _ in range(number_of_samples):
NN_inputs.append(numpy.arange(256))
NN_labels.append(numpy.arange(16))
yield numpy.asarray(NN_inputs), numpy.asarray(NN_labels)
NN_history = NN_model.fit(training_generator(1000),
steps_per_epoch=4,
epochs=10,
verbose=2)

Agumenting data in keras using albumentations

I am trying to train a keras ResNet50 model for image classification model using a tutorial. Instead of the inbuilt data generator, I want to use albumentations library for augmentation.
from albumentations import Compose
transforms = Compose([HorizontalFlip()])
I have read a few articles, but I could not figure out how to implement albumentations.
Which line of code should I modify to implement albumentations.
I am reproducing the code below after removing non necessary lines.
NUM_CLASSES = 2
CHANNELS = 3
IMAGE_RESIZE = 224
RESNET50_POOLING_AVERAGE = 'avg'
DENSE_LAYER_ACTIVATION = 'softmax'
OBJECTIVE_FUNCTION = 'categorical_crossentropy'
LOSS_METRICS = ['accuracy']
NUM_EPOCHS = 300
EARLY_STOP_PATIENCE = 20
STEPS_PER_EPOCH_TRAINING = 20
STEPS_PER_EPOCH_VALIDATION = 20
BATCH_SIZE_TRAINING = 10
BATCH_SIZE_VALIDATION = 10
# %% ---------------------------------------------------------------------
TrainingData_directory = 'C:/datafolder/Train'
ValidationData_directory = 'C:/datafolder/Validation'
ModelCheckpointPath = 'C:/datafolder/ResNet50_Weights.hdf5'
# %% ---------------------------------------------------------------------
from albumentations import Compose
import tensorflow as tf
from tensorflow.keras.applications import ResNet50
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
# %% ---------------------------------------------------------------------
model = Sequential()
model.add(ResNet50(include_top = False, pooling = RESNET50_POOLING_AVERAGE, weights = 'imagenet'))
model.add(Dense(NUM_CLASSES, activation = DENSE_LAYER_ACTIVATION))
model.layers[0].trainable = False
from tensorflow.keras import optimizers
sgd = optimizers.SGD(lr = 0.001, decay = 1e-6, momentum = 0.9, nesterov = True)
model.compile(optimizer = sgd, loss = OBJECTIVE_FUNCTION, metrics = LOSS_METRICS)
from keras.applications.resnet50 import preprocess_input
from keras.preprocessing.image import ImageDataGenerator
image_size = IMAGE_RESIZE
data_generator = ImageDataGenerator(preprocessing_function = preprocess_input)
train_generator = data_generator.flow_from_directory(TrainingData_directory,
target_size = (image_size, image_size),
batch_size = BATCH_SIZE_TRAINING,
class_mode = 'categorical')
validation_generator = data_generator.flow_from_directory(ValidationData_directory,
target_size = (image_size, image_size),
batch_size = BATCH_SIZE_VALIDATION,
class_mode = 'categorical')
from tensorflow.python.keras.callbacks import EarlyStopping, ModelCheckpoint
cb_early_stopper = EarlyStopping(monitor = 'val_loss', patience = EARLY_STOP_PATIENCE)
cb_checkpointer = ModelCheckpoint(filepath = ModelCheckpointPath,
monitor = 'val_loss', save_best_only = True, mode = 'auto')
fit_history = model.fit_generator(
train_generator,
steps_per_epoch=STEPS_PER_EPOCH_TRAINING,
epochs = NUM_EPOCHS,
validation_data=validation_generator,
validation_steps=STEPS_PER_EPOCH_VALIDATION,
callbacks=[cb_checkpointer, cb_early_stopper]
)
I think you can do it using the ImageDataGenerator preprocessing_function. The function should taken in a single image as input and return an image. So in your case.
def augmentor (img)
# place you code here do to the albumentations transforms
# your code should result in a single transformed image I called aug_img
return aug_img/127.5-1 #scales the pixels between -1 and +1 which it what preprocees_input does
data_generator = ImageDataGenerator(preprocessing_function = augmentor)
You can include it into the preprocessing function passed to ImageDataGenerator:
def preprocessing_function(x):
preprocessed_x = preprocess_input(x)
transformed_image = transforms(image=preprocessed_x)['image']
return transformed_image
ImageDataGenerator(preprocessing_function = preprocessing_function)
That's (IMO) the limitation or losing the flexibility that one might come across using a built-in data generator (ImageDataGenerator). You should implement your own custom data generator.
Check this kernel: [TF.Keras]: SOTA Augmentation in Sequence Generator, where we've shown how one can use albumentation, cutmix, mixup, and fmix type advance augmentation into the custom generator. Here is a basic approach of how to use albumentaiton in a custom data generator.
import albumentations as A
# For Training
def albu_transforms_train(data_resize):
return A.Compose([
A.ToFloat(),
A.Resize(data_resize, data_resize),
A. [.....what ever......]
], p=1.)
class Generator(tf.keras.utils.Sequence):
def __getitem__(self, index):
...........
Data = np.empty((self.batch_size, *self.dim))
Target = np.empty((self.batch_size, 5), dtype = np.float32)
for i, k in enumerate(idx):
# load the image file using cv2
image = cv2.imread(self.img_path + self.data['image_id'][k])
image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
# call augmentor / albumentation
res = self.augment(image=image)
image = res['image']
# assign
Data[i,:, :, :] = image
Target[i,:] = self.label.loc[k, :].values
return Data, Target
# call the generator
check_gens = Generator(...., transform = albu_transforms_train(128))

I am getting "Requested tensor connection from unknown node: "keras_layer_input:0"". error while loading keras model

I had Saved model using
tf.keras.experimental.export_saved_model(model, export_path)
This model have custom layers and loss function.
Loading model using
import tensorflow as tf
import tensorflow_hub as hub
import keras
class training_model:
def __init__(self):
path_bce="D:\\nsfw\\training_model\\models\\bce_20210120_153631"
path2="D:\\nsfw\\training_model\\models\\soft-f1_20210120_153631"
self.graph = tf.Graph()
with self.graph.as_default():
self.session = tf.Session()
with self.session.as_default() :
self.reloaded =tf.keras.experimental.load_from_saved_model(path2, custom_objects={'KerasLayer':hub.KerasLayer})
training_model=training_model()
img = keras.preprocessing.image.load_img(
"0drqz7883ox51.jpg", target_size=(224, 224)
)
img_array = keras.preprocessing.image.img_to_array(img)
img_array = tf.expand_dims(img_array, 0) # Create a batch
with training_model.graph.as_default():
with training_model.session.as_default():
print(training_model.reloaded.predict(img_array,steps=1))
It is working fine if i remove Graph and Session but I want to serve this model with API.
You can try something like this.
with self.graph1.as_default():
self.face_graph = tf.compat.v1.GraphDef()
fid = tf.io.gfile.GFile(self.facenet_model, "rb")
serialized_graph = fid.read()
self.face_graph.ParseFromString(serialized_graph)
tf.import_graph_def(self.face_graph, name="")
self.facenet_sess = tf.compat.v1.Session(graph=self.graph1)
self.images_placeholder = self.graph1.get_tensor_by_name("input:0")
self.embeddings = self.graph1.get_tensor_by_name("embeddings:0")
hub.KerasLayer is a TF2 API. One thing to try might be to switch the prediction part from TF1 style (graph + session) to TF2. Alternatively, you could try TensorFlow Serving as an alternative to custom inference logic.

Object Detection API v2 Tflite model post quantization

I try to convert and quantize a model trained with the Object Detection API v2 to run it on a Coral Devboard.
It seems like there is still a big problem with exporting Object Detection Models to lite, though I hope that maybe someone has some advice for me.
my converter looks like the following and I try to convert "SSD MobileNet v2 320x320" from Model Zoo v2
def convertModel(input_dir, output_dir, pipeline_config="", checkpoint:int=-1, quantization=False ):
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
files = os.listdir(input_dir)
if pipeline_config == "":
pipeline_config = [pipe for pipe in files if pipe.endswith(".config")][0]
pipeline_config_path = os.path.join(input_dir, pipeline_config)
# Find latest or given checkpoint
checkpoint_file = ""
checkpointDir = os.path.join(input_dir, 'checkpoint')
for chck in sorted(os.listdir(checkpointDir)):
if chck.endswith(".index"):
checkpoint_file = chck[:-6]
# Stop search when the requested was found
if chck.endswith(str(checkpoint)):
break
print("#####################################")
print(checkpoint_file)
print("#####################################")
#ckeckpint_file = [chck for chck in files if chck.endswith(f"{checkpoint}.meta")][0]
trained_checkpoint_prefix = os.path.join(checkpointDir, checkpoint_file)
configs = config_util.get_configs_from_pipeline_file(pipeline_config_path)
detection_model = model_builder.build(configs['model'], is_training=False)
ckpt = tf.compat.v2.train.Checkpoint(
model=detection_model)
ckpt.restore(trained_checkpoint_prefix).expect_partial()
class MyModel(tf.keras.Model):
def __init__(self, model):
super(MyModel, self).__init__()
self.model = model
self.seq = tf.keras.Sequential([
tf.keras.Input([300,300,3], 1),
])
def call(self, x):
x = self.seq(x)
images, shapes = self.model.preprocess(x)
prediction_dict = self.model.predict(images, shapes)
detections = self.model.postprocess(prediction_dict, shapes)
return detections
km = MyModel(detection_model)
y = km.predict(np.random.random((1,300,300,3)).astype(np.float32))
converter = tf.lite.TFLiteConverter.from_keras_model(km)
if quantization:
converter.optimizations = [tf.lite.Optimize.OPTIMIZE_FOR_SIZE]
converter.target_spec.supported_ops = [ tf.lite.OpsSet.SELECT_TF_OPS, tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.representative_dataset = _genDataset
else:
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS]
converter.experimental_new_converter = True
converter.allow_custom_ops = True
tflite_model = converter.convert()
open(os.path.join(output_dir, 'model.tflite'), 'wb').write(tflite_model)
My Datagenerator loads about 100 images downloaded from the coco dataset to generate sample inputs
def _genDataset():
sampleDir = os.path.join("Dataset", "Coco")
for i in os.listdir(sampleDir):
image = cv2.imread(os.path.join(sampleDir, i))
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image = cv2.resize(image, (300,300))
image = image.astype("float")
image = np.expand_dims(image, axis=1)
image = image.reshape(1, 300, 300, 3)
yield [image.astype("float32")]
I tried to tun the code with TF2.2.0 which returned me
RuntimeError: Max and min for dynamic tensors should be recorded during calibration
according to an update to TF2.3.0 should help when then returns me
<unknown>:0: error: failed while converting: 'main': Ops that can be supported by the flex runtime (enabled via setting the -emit-select-tf-ops flag):
tf.Size {device = ""}
I also tested tf-nightly (2.4.0) which returns again
RuntimeError: Max and min for dynamic tensors should be recorded during calibration
Right now this tf.Size operator seems to be the reason why I can convert the model because when I allow custom operations I can convert it to tflite.
Sadly that is not a solution for me because the coral converter or my interpreter can't use the model with a missing custom op.
Does someone know if there is a possibility to remove this op in postprocessing or just ignore it during conversion?
Just converting it to TFlite without quantization and tf.lite.OpsSet.TFLITE_BUILTINS works without problems

tf.device() appeared exception

When I use tf.device() to assign GPU number, it appeared an exception. It's my first time to ask question in Stack Overflow, if it has some error, please forgive me, and tell me.
When I put allow_soft_placement=True in code, it works.
def init_graph(self):
"""
init bert graph
"""
with self.tf_instance.device('device:GPU:{}'.format(str(self.gpu_no))):
# add tokenizer
from bert import tokenization
self.tokenizer = tokenization.FullTokenizer(self.args.vocab_file)
from bert import modeling
bert_config = modeling.BertConfig.from_json_file(self.args.config_file)
self.model = modeling.BertModel(config=bert_config,
is_training=False,
input_ids=self.input_ids,
input_mask=self.input_mask,
token_type_ids=self.input_type_ids,
use_one_hot_embeddings=False)
# get output weights and output bias
reader = self.tf_instance.train.NewCheckpointReader(self.args.ckpt_file)
output_weights = reader.get_tensor('output_weights')
output_bias = reader.get_tensor('output_bias')
# get result op
output_layer = self.model.get_pooled_output()
logits = self.tf_instance.matmul(output_layer, output_weights, transpose_b=True)
logits = self.tf_instance.nn.bias_add(logits, output_bias)
self.probabilities = self.tf_instance.nn.softmax(logits, axis=-1)
sess_config = self.tf_instance.ConfigProto()
sess_config.gpu_options.allow_growth = True
graph = self.probabilities.graph
saver = self.tf_instance.train.Saver()
self.sess = self.tf_instance.Session(config=sess_config, graph=graph)
self.sess.run(self.tf_instance.global_variables_initializer())
self.tf_instance.reset_default_graph()
saver.restore(self.sess, self.args.ckpt_file)