Tensorflow - mapping images with labels - tensorflow

I need the solution, that works with TPU, neither ImageDataGenerator or tf.py_function doesn't work.
My code for CPU:
def get_label(file_path):
file_name = tf.strings.split(file_path, os.path.sep)[-1]
label = image_name_to_label[file_name.numpy().decode('utf-8')]
label = tf.constant([label])
return label
def decode_img(img):
img = tf.io.decode_jpeg(img, channels=3)
return tf.image.resize(img, [img_height, img_width])
def process_path(file_path):
label = tf.py_function(func=get_label, inp=[file_path], Tout=tf.int32)
label.set_shape((1,))
img = tf.io.read_file(file_path)
img = decode_img(img)
return img, label
image_name_to_label is a python dict
I don't want to convert data to tfrecords

Ok, I found the solution using .from_tensor_slice I can load images and labels simultaneously, but question about work in map function is still and what about third party augmentations?
def decode_img(img):
img = tf.io.decode_jpeg(img, channels=3)
return tf.image.resize(img, [img_height, img_width])
def process_path(file_path, label):
img = tf.io.read_file(train_path_f+file_path)
img = decode_img(img)
label = tf.reshape(label,[1])
return img, label
images = imgs_files
labels = train_csv.species_cat.values
dataset = tf.data.Dataset.from_tensor_slices((images, labels))
dataset = dataset.map(process_path)

Related

Can't preprocess data before training for image segmentation

I'm trying to do some image segmentation for ocr, my mask image is a 3 classes image, like this
and my original image is a gray image like this
but when I try to fit the model I get this error
could not broadcast input array from shape (128,128,3) into shape (128,128)
here is the code I'm using to create the datasets
img_size = (128, 128)
batch_size = 32
input_img_paths = sorted(
[ os.path.join(input_dir, fname)
for fname in os.listdir(input_dir)
if fname.endswith(".jpg") ] )
target_img_paths = sorted(
[ os.path.join(target_dir, fname)
for fname in os.listdir(target_dir)
if fname.endswith(".jpg") and not fname.startswith(".") ])
class OxfordPets(keras.utils.Sequence):
"""Helper to iterate over the data (as Numpy arrays)."""
def __init__(self, batch_size, img_size, input_img_paths, target_img_paths):
self.batch_size = batch_size
self.img_size = img_size
self.input_img_paths = input_img_paths
self.target_img_paths = target_img_paths
def __len__(self):
return len(self.target_img_paths) // self.batch_size
def __getitem__(self, idx):
"""Returns tuple (input, target) correspond to batch #idx."""
i = idx * self.batch_size
batch_input_img_paths = self.input_img_paths[i : i + self.batch_size]
batch_target_img_paths = self.target_img_paths[i : i + self.batch_size]
x = np.zeros((batch_size,) + self.img_size, dtype="float32")
for j, path in enumerate(batch_input_img_paths):
img = load_img(path, target_size=self.img_size)
x[j] = img
y = np.zeros((batch_size,) + self.img_size, dtype="float32")
for j, path in enumerate(batch_target_img_paths):
img = load_img(path, target_size=self.img_size, color_mode="rgb")
y[j] = img
return x, y
val_samples = 150
random.Random(1337).shuffle(input_img_paths)
random.Random(1337).shuffle(target_img_paths)
train_input_img_paths = input_img_paths[:-val_samples]
train_target_img_paths = target_img_paths[:-val_samples]
val_input_img_paths = input_img_paths[-val_samples:]
val_target_img_paths = target_img_paths[-val_samples:]
# Instantiate data Sequences for each split
train_gen = OxfordPets(
batch_size, img_size, train_input_img_paths, train_target_img_paths
)
val_gen = OxfordPets(batch_size, img_size, val_input_img_paths, val_target_img_paths)
but when i try to fit whit this
model_history = model.fit(train_gen, epochs=30,
steps_per_epoch=50,
validation_steps=25,
validation_data=val_gen)
I get the error, I am trying to adapt this solution
https://keras.io/examples/vision/oxford_pets_image_segmentation/?fbclid=IwAR2wFYju-N0X7FUaWkhvOVaAAaVqLdOryBwg7xDC0Rji9LQ5F2jYOkeNnns
from keras
into the example of the tensorflow page
https://www.tensorflow.org/tutorials/images/segmentation
and I have the impression that the problem has something to do whit the fact that the original image is on gray scale, how can I solve this error? any advice would be great!
You should convert your image to RGB first. Your image is gray-scaled and has only 1 channel. Its shape is (128,128,1). Them apply sth like opencv: backtorgb = cv2.cvtColor(gray,cv2.COLOR_GRAY2RGB) to every image in your data and everything will be ok
Your mask is RGB and has 3 channels. but your image is grayscale and has one channel. See This question for converting RGB image to grayscale image

tf.data or tf.keras.utils.Sequence. Improving efficiency of tf.data?

I am trying to develop an image colorizer using autoencoders. There are 13000 training images. Each epoch takes about 45 minutes if I use tf.data and about 25 minutes if I use tf.utils.keras.Sequence. However with the use of Sequence there is a risk of deadlocks. How do I improve tf.data? I tried a couple of things but they don't seem to improve anything.
tf.data 1
image_path_list = glob.glob('datasets/imagenette/*')
data = tf.data.Dataset.list_files(image_path_list)
def tf_rgb2lab(image):
im_shape = image.shape
[image,] = tf.py_function(color.rgb2lab, [image], [tf.float32])
image.set_shape(im_shape)
return image
def preprocess(path):
image = tf.io.read_file(path)
image = tf.image.decode_jpeg(image, channels=3)
image = tf.image.convert_image_dtype(image, tf.float32)
image = tf.image.resize(image, [224, 224])
image = tf_rgb2lab(image)
L = image[:,:,0]/100.
ab = image[:,:,1:]/128.
input = tf.stack([L,L,L], axis=2)
return input, ab
train_ds = data.repeat().map(preprocess, AUTOTUNE).batch(32).prefetch(AUTOTUNE)
tf.data 2
AUTOTUNE = tf.data.experimental.AUTOTUNE
def tf_rgb2lab(image):
im_shape = image.shape
[image,] = tf.py_function(color.rgb2lab, [image], [tf.float32])
image.set_shape(im_shape)
return image
def split_for_feed(image):
L = image[:,:,:,0]/100.
ab = image[:,:,:,1:]/128.
input = tf.stack([L,L,L], axis=-1)
return input, ab
def read_images(path):
image = tf.io.read_file(path)
image = tf.image.decode_jpeg(image, channels=3)
image = tf.image.convert_image_dtype(image, tf.float32)
image = tf.image.resize(image, [224, 224])
image = tf_rgb2lab(image)
return image
data2 = data.repeat().map(read_images, AUTOTUNE).batch(32)
train_ds = data2.map(split_for_feed, AUTOTUNE).prefetch(AUTOTUNE)
Sequence
class ImageGenerator(tf.keras.utils.Sequence):
def __init__(self, image_filenames, batch_size):
self.image_filenames = image_filenames
self.batch_size = batch_size
def __len__(self):
return math.ceil(len(self.image_filenames) / self.batch_size)
def __getitem__(self, idx):
batch = self.image_filenames[idx * self.batch_size : (idx + 1) * self.batch_size]
X_batch = []
y_batch = []
for file_name in batch:
file_name = 'datasets/imagenette/' + file_name
try:
color_image = transform.resize(io.imread(file_name),(224,224))
lab_image = color.rgb2lab(color_image)
L = lab_image[:,:,0]/100.
ab = lab_image[:,:,1:]/128.
X_batch.append(np.stack((L,L,L), axis=2))
y_batch.append(ab)
except:
pass
return np.array(X_batch), np.array(y_batch)
If your data fits in memory, try caching the preprocessing. Instead of
train_ds = data.repeat().map(preprocess, AUTOTUNE).batch(32).prefetch(AUTOTUNE)
Do
train_ds = data.map(preprocess, AUTOTUNE).batch(32).cache().repeat().prefetch(AUTOTUNE)
That way you parse each file just once, instead of repeatedly.
If you're looking to optimize the pipeline further, consider using the TF Profiler, which can tell you exactly how much time is being spent in each part of the dataset, so that you can find the bottleneck and solve it.

What is the correct way to create representative dataset for TFliteconverter?

I am trying to infer tinyYOLO-V2 with INT8 weights and activation. I can convert the weights to INT8 with TFliteConverter. For INT8 activation, I have to give representative dataset to estimate the scaling factor. My method of creating such dataset seems wrong.
What is the correct procedure ?
def rep_data_gen():
a = []
for i in range(160):
inst = anns[i]
file_name = inst['filename']
img = cv2.imread(img_dir + file_name)
img = cv2.resize(img, (NORM_H, NORM_W))
img = img / 255.0
img = img.astype('float32')
a.append(img)
a = np.array(a)
print(a.shape) # a is np array of 160 3D images
img = tf.data.Dataset.from_tensor_slices(a).batch(1)
for i in img.take(BATCH_SIZE):
print(i)
yield [i]
# https://www.tensorflow.org/lite/performance/post_training_quantization
converter = tf.lite.TFLiteConverter.from_keras_model_file("./yolo.h5")
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = [tf.int8]
converter.inference_output_type = [tf.int8]
converter.representative_dataset=rep_data_gen
tflite_quant_model = converter.convert()
ValueError: Cannot set tensor: Got tensor of type STRING but expected type FLOAT32 for input 27, name: input_1
I used your code for reading in a dataset and found the error:
img = img.astype('float32') should be
img = img.astype(np.float32)
Hope this helps

TFRecord - converting png to bytes

Code to create a tfrecord:
def convert(self):
with tf.python_io.TFRecordWriter(self.tfrecord_out) as writer:
example = self._convert_image()
writer.write(example.SerializeToString())
def _convert_image(self):
for (path, label) in zip(self.image_paths, self.labels):
label = int(label)
# Read image data in terms of bytes
with open(path, 'rb') as fid:
png_bytes = fid.read()
example = tf.train.Example(features=tf.train.Features(feature={
'image': tf.train.Feature(bytes_list=tf.train.BytesList(value=[png_bytes]))
}))
return example
My problem is when I read from the file the image doesn't decode correctly:
def parse(self, serialized):
features = \
{
'image': tf.FixedLenFeature([], tf.string)
}
parsed_example = tf.parse_single_example(serialized=serialized,
features=features)
image_raw = parsed_example['image']
image = tf.image.decode_png(contents=image_raw, channels=3, dtype=tf.uint8)
image = tf.cast(image, tf.float32)
return image`
Does anyone know why is that?
Found the solution, hopefully my stupid mistake will help others.
When reshaping the tensor into 4 dimensions for tensorboard[batch_size, height, width, channels] I switched width and height.
The correct reshape code is:
x_reshaped = session.run(tf.reshape(tensor=decoded_png_uint8, shape=[batch_size, height, width, channels], name="x_reshaped"))
but I had shape=[batch_size, width, height, channels]. Ah well. Every day is a school day.

Passing two queues to Tensorflow training

I'm trying to create a train operation based on CIFAR10 example from Tensorflow that uses tf.RandomShuffleQueue and my labels comes from the name of the files as mentioned in (Accessing filename from file queue in Tensor Flow). How can I use this code with that?
When I try to run the following code, where path is a directory with many files:
filenames = [path, f) for f in os.listdir(path)][1:]
file_fifo = tf.train.string_input_producer(filenames,
shuffle=False,
capacity=len(filenames))
reader = tf.WholeFileReader()
key, value = reader.read(file_fifo)
image = tf.image.decode_png(value, channels=3, dtype=tf.uint8)
image.set_shape([config.image_height, config.image_width, config.image_depth])
image = tf.cast(image, tf.float32)
image = tf.divide(image, 255.0)
labels = [int(os.path.basename(f).split('_')[-1].split('.')[0]) for f in filenames]
label_fifo = tf.FIFOQueue(len(filenames), tf.int32, shapes=[[]])
label_enqueue = label_fifo.enqueue_many([tf.constant(labels)])
label = label_fifo.dequeue()
bq = tf.RandomShuffleQueue(capacity=16 * batch_size,
min_after_dequeue=8 * batch,
dtypes=[tf.float32, tf.int32])
batch_enqueue_op = bq.enqueue([image, label_enqueue])
runner = tf.train.queue_runner.QueueRunner(bq, [batch_enqueue_op] * num_threads)
tf.train.add_queue_runner(runner)
# Read 'batch' labels + images from the example queue.
images, labels = batch_queue.dequeue_many(FLAGS.batch_size)
labels = tf.reshape(labels, [FLAGS.batch_size, 1])
I get obvious erros, because I know my code doesn't make much sense. I have two FIFO queues file_fifo and label_fifo, but I don't know how to make my label_fifo input of my tf.RandomShuffleQueue.
Can someone help? Thank you :-)
I changed my code to:
filenames = [os.path.join(FLAGS.data_path, f) for f in os.listdir(FLAGS.data_path)][1:]
np.random.shuffle(filenames)
file_fifo = tf.train.string_input_producer(filenames, shuffle=False, capacity=len(filenames))
reader = tf.WholeFileReader()
key, value = reader.read(file_fifo)
image = tf.image.decode_png(value, channels=3, dtype=tf.uint8)
image.set_shape([config.image_height, config.image_width, config.image_depth])
image = tf.cast(image, tf.float32)
image = tf.divide(image, 255.0)
labels = [int(os.path.basename(f).split('_')[-1].split('.')[0]) for f in filenames]
label_fifo = tf.FIFOQueue(len(filenames), tf.int32, shapes=[[]])
label_enqueue = label_fifo.enqueue_many([tf.constant(labels)])
label = label_fifo.dequeue()
if is_train:
images, label_batch = tf.train.shuffle_batch([image, label],
batch_size=FLAGS.batch_size,
num_threads=FLAGS.num_threads,
capacity=16 * FLAGS.batch_size,
min_after_dequeue=8 * FLAGS.batch_size)
labels = tf.reshape(label_batch, [FLAGS.batch_size, 1])
For training I have:
class _LoggerHook(tf.train.SessionRunHook):
"""Logs loss and runtime."""
def begin(self):
self._step = -1
def before_run(self, run_context):
self._step += 1
self._start_time = time.time()
if self._step % int(config.train_examples / FLAGS.batch_size) == 0 or self._step == 0:
run_context.session.run(label_enqueue_op)
return tf.train.SessionRunArgs({'loss': loss, 'net': net})
and I run training as:
with tf.train.MonitoredTrainingSession(
checkpoint_dir=FLAGS.train_path,
hooks=[tf.train.StopAtStepHook(last_step=FLAGS.max_steps), tf.train.NanTensorHook(loss), _LoggerHook()],
config=tf.ConfigProto(log_device_placement=FLAGS.log_device_placement)) as mon_sess:
while not mon_sess.should_stop():
mon_sess.run(train_op)
The training starts, but it runs only for the very first step and hangs - maybe because it's waiting for some queue command