How to batch tensors with different shapes in Tensorflow Data API?

Viewed 415

I am trying to implement a Fully Convolutional Neural Network from scratch after studying the Research paper. Since FCN works on input of any size I am having a hard time implementing the DataLoader for it.I am trying to batch the inputs using batch() function but it gives an error because of variable length tensors. Is there any feasible way to batch the tensors of arbitrary shape ?

My Code :

import tensorflow as tf
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
import os
from albumentations import ElasticTransform,VerticalFlip,RandomSizedCrop,Compose,RandomRotate90

# Train and Val contains the respective paths for [TrainImage,Labels] and [ValImage,Labels] respectively.

num_classes = 21
Train = tf.data.Dataset.from_tensor_slices(Train)
Val = tf.data.Dataset.from_tensor_slices(Val)


def Create_Mask(Img):
  Seg_Labels = np.zeros((Img.shape[0],Img.shape[1],num_classes),dtype=np.float32)
  for class_ in range(num_classes):
    Seg_Labels[:,:,class_] = (Img == class_)
  return tf.cast(Seg_Labels,dtype=tf.float32)


def Create_PreProcess_Mask_Img(Instance):
  Img = np.asarray(Image.open(Instance[0].numpy()))
  Mask = np.asarray(Image.open(Instance[1].numpy()))    
  # Since Mask is in 'P' mode it will automatically convert to labels using Color Palette 

  Normalization = tf.keras.layers.experimental.preprocessing.Rescaling(1./255)

  if tf.random.uniform(()) > 0.5:  # Applying data Augmentation
    Num = tf.random.uniform((),minval=0,maxval=3,dtype=tf.int32)
    if Num == 0:
      aug = ElasticTransform(p=1)
      Augmented = aug(image = Img,mask = Mask)

    elif Num == 1:
      Height,Width = Img.shape[0],Img.shape[1]
      aug = RandomSizedCrop(min_max_height=(50,101),height=Height,width=Width,p = 1)
      Augmented = aug(image = Img,mask = Mask)

    elif Num == 2:
      aug = Compose([VerticalFlip(p=0.5),RandomRotate90(p=0.5)])
      Augmented = aug(image = Img,mask = Mask)

    Img = Augmented["image"]
    Mask = Augmented["mask"]
  
  return Normalization(Img),Create_Mask(Mask)


def Preprocess(Instance):
  Img,Mask = tf.py_function(Create_PreProcess_Mask_Img,[Instance],[tf.float32,tf.float32])
  return tf.ensure_shape(Img,[None,None,3]),tf.ensure_shape(Mask,[None,None,num_classes])  
  #tf.ensure_shape returns the matrix if shape matches else error

def DataLoader(dataset,BATCH_SIZE = 32,BUFFER_SIZE = 256):
  data = dataset.map(Preprocess,num_parallel_calls = tf.data.AUTOTUNE)
  data = data.cache().shuffle(BUFFER_SIZE).batch(BATCH_SIZE).repeat(1)
  data = data.prefetch(buffer_size = tf.data.AUTOTUNE)
  return data

Train = DataLoader(Train)
Val = DataLoader(Val)

for X,Y in Train.take(1):
  print(X.shape)
  print(Y.shape)

Stack Trace:

---------------------------------------------------------------------------
InvalidArgumentError                      Traceback (most recent call last)
/usr/local/lib/python3.7/dist-packages/tensorflow/python/eager/context.py in execution_mode(mode)
   2112       ctx.executor = executor_new
-> 2113       yield
   2114     finally:

9 frames
InvalidArgumentError: Cannot batch tensors with different shapes in component 0. First element had shape [500,375,3] and element 1 had shape [500,383,3]. [Op:IteratorGetNext]

During handling of the above exception, another exception occurred:

InvalidArgumentError                      Traceback (most recent call last)
/usr/local/lib/python3.7/dist-packages/tensorflow/python/eager/executor.py in wait(self)
     67   def wait(self):
     68     """Waits for ops dispatched in this executor to finish."""
---> 69     pywrap_tfe.TFE_ExecutorWaitForAllPendingNodes(self._handle)
     70 
     71   def clear_error(self):

InvalidArgumentError: Cannot batch tensors with different shapes in component 0. First element had shape [500,375,3] and element 1 had shape [500,383,3].
1 Answers

you can't have a batch with different image sizes but if you want to work around the problem you can either:

  • Resize all the images for a common shape (if the images have close ratios, the impact is minimal) look at this link.
  • Decrease the size of your batch to one image (this method makes the training very unstable).

You can take a look to this post

Related